Annotation of embedaddon/ntp/libparse/clk_meinberg.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
        !             3:  *  
        !             4:  * clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
        !             5:  *
        !             6:  * Meinberg clock support
        !             7:  *
        !             8:  * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
        !             9:  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  * 3. Neither the name of the author nor the names of its contributors
        !            20:  *    may be used to endorse or promote products derived from this software
        !            21:  *    without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            33:  * SUCH DAMAGE.
        !            34:  *
        !            35:  */
        !            36: 
        !            37: #ifdef HAVE_CONFIG_H
        !            38: # include <config.h>
        !            39: #endif
        !            40: 
        !            41: #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_MEINBERG)
        !            42: 
        !            43: #include "ntp_fp.h"
        !            44: #include "ntp_unixtime.h"
        !            45: #include "ntp_calendar.h"
        !            46: 
        !            47: #include "ntp_machine.h"
        !            48: 
        !            49: #include "parse.h"
        !            50: 
        !            51: #ifndef PARSESTREAM
        !            52: #include <stdio.h>
        !            53: #else
        !            54: #include "sys/parsestreams.h"
        !            55: #endif
        !            56: 
        !            57: #include "ntp_stdlib.h"
        !            58: 
        !            59: #include "ntp_stdlib.h"
        !            60: 
        !            61: #include "mbg_gps166.h"
        !            62: #include "binio.h"
        !            63: #include "ascii.h"
        !            64: 
        !            65: /*
        !            66:  * The Meinberg receiver every second sends a datagram of the following form
        !            67:  * (Standard Format)
        !            68:  * 
        !            69:  *     <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
        !            70:  * pos:  0  00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2  2  3  3   3
        !            71:  *       1  23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8  9  0  1   2
        !            72:  * <STX>           = '\002' ASCII start of text
        !            73:  * <ETX>           = '\003' ASCII end of text
        !            74:  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
        !            75:  * <w>             = day of week (sunday= 0)
        !            76:  * <hh>,<mm>,<ss>  = hour, minute, second
        !            77:  * <S>             = '#' if never synced since powerup for DCF C51
        !            78:  *                 = '#' if not PZF sychronisation available for PZF 535/509
        !            79:  *                 = ' ' if ok
        !            80:  * <F>             = '*' if time comes from internal quartz
        !            81:  *                 = ' ' if completely synched
        !            82:  * <D>             = 'S' if daylight saving time is active
        !            83:  *                 = 'U' if time is represented in UTC
        !            84:  *                 = ' ' if no special condition exists
        !            85:  * <A>             = '!' during the hour preceeding an daylight saving time
        !            86:  *                       start/end change
        !            87:  *                 = 'A' leap second insert warning
        !            88:  *                 = ' ' if no special condition exists
        !            89:  *
        !            90:  * Extended data format (PZFUERL for PZF type clocks)
        !            91:  *
        !            92:  *     <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
        !            93:  * pos:  0   00 0 00 0 00 11 1 11 11 1 11 2 22 22 2  2  2  2  2  3  3   3
        !            94:  *       1   23 4 56 7 89 01 2 34 56 7 89 0 12 34 5  6  7  8  9  0  1   2
        !            95:  * <STX>           = '\002' ASCII start of text
        !            96:  * <ETX>           = '\003' ASCII end of text
        !            97:  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
        !            98:  * <w>             = day of week (sunday= 0)
        !            99:  * <hh>,<mm>,<ss>  = hour, minute, second
        !           100:  * <U>             = 'U' UTC time display
        !           101:  * <S>             = '#' if never synced since powerup else ' ' for DCF C51
        !           102:  *                   '#' if not PZF sychronisation available else ' ' for PZF 535/509
        !           103:  * <F>             = '*' if time comes from internal quartz else ' '
        !           104:  * <D>             = 'S' if daylight saving time is active else ' '
        !           105:  * <A>             = '!' during the hour preceeding an daylight saving time
        !           106:  *                       start/end change
        !           107:  * <L>             = 'A' LEAP second announcement
        !           108:  * <R>             = 'R' alternate antenna
        !           109:  *
        !           110:  * Meinberg GPS166 receiver
        !           111:  *
        !           112:  * You must get the Uni-Erlangen firmware for the GPS receiver support
        !           113:  * to work to full satisfaction !
        !           114:  *
        !           115:  *     <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
        !           116:  *
        !           117:  *        000000000111111111122222222223333333333444444444455555555556666666
        !           118:  *        123456789012345678901234567890123456789012345678901234567890123456
        !           119:  *     \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N  11.0280E  373m\x03
        !           120:  *
        !           121:  * 
        !           122:  * <STX>           = '\002' ASCII start of text
        !           123:  * <ETX>           = '\003' ASCII end of text
        !           124:  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
        !           125:  * <w>             = day of week (sunday= 0)
        !           126:  * <hh>,<mm>,<ss>  = hour, minute, second
        !           127:  * <+/->,<00:00>   = offset to UTC
        !           128:  * <S>             = '#' if never synced since powerup else ' '
        !           129:  * <F>             = '*' if position is not confirmed else ' '
        !           130:  * <D>             = 'S' if daylight saving time is active else ' '
        !           131:  * <A>             = '!' during the hour preceeding an daylight saving time
        !           132:  *                       start/end change
        !           133:  * <L>             = 'A' LEAP second announcement
        !           134:  * <R>             = 'R' alternate antenna (reminiscent of PZF535) usually ' '
        !           135:  * <L>            = 'L' on 23:59:60
        !           136:  *
        !           137:  * Binary messages have a lead in for a fixed header of SOH
        !           138:  */
        !           139: 
        !           140: /*--------------------------------------------------------------*/
        !           141: /* Name:         csum()                                         */
        !           142: /*                                                              */
        !           143: /* Purpose:      Compute a checksum about a number of bytes     */
        !           144: /*                                                              */
        !           145: /* Input:        uchar *p    address of the first byte          */
        !           146: /*               short n     the number of bytes                */
        !           147: /*                                                              */
        !           148: /* Output:       --                                             */
        !           149: /*                                                              */
        !           150: /* Ret val:      the checksum                                   */
        !           151: /*+-------------------------------------------------------------*/
        !           152: 
        !           153: unsigned long
        !           154: mbg_csum(
        !           155:         unsigned char *p,
        !           156:         unsigned int n
        !           157:         )
        !           158: {
        !           159:   unsigned long sum = 0;
        !           160:   short i;
        !           161:   
        !           162:   for ( i = 0; i < n; i++ )
        !           163:     sum += *p++;
        !           164:   
        !           165:   return( sum );
        !           166: }  /* csum */
        !           167: 
        !           168: void
        !           169: get_mbg_header(
        !           170:               unsigned char **bufpp,
        !           171:               GPS_MSG_HDR *headerp
        !           172:               )
        !           173: {
        !           174:   headerp->gps_cmd = get_lsb_short(bufpp);
        !           175:   headerp->gps_len = get_lsb_short(bufpp);
        !           176:   headerp->gps_data_csum = get_lsb_short(bufpp);
        !           177:   headerp->gps_hdr_csum  = get_lsb_short(bufpp);
        !           178: }
        !           179: 
        !           180: static struct format meinberg_fmt[] =
        !           181: {
        !           182:        {
        !           183:                {
        !           184:                        { 3, 2},  {  6, 2}, {  9, 2},
        !           185:                        { 18, 2}, { 21, 2}, { 24, 2},
        !           186:                        { 14, 1}, { 27, 4}, { 29, 1},
        !           187:                },
        !           188:                (const unsigned char *)"\2D:  .  .  ;T: ;U:  .  .  ;    \3",
        !           189:                0
        !           190:        },
        !           191:        {                       /* special extended FAU Erlangen extended format */
        !           192:                {
        !           193:                        { 1, 2},  { 4,  2}, {  7, 2},
        !           194:                        { 14, 2}, { 17, 2}, { 20, 2},
        !           195:                        { 11, 1}, { 25, 4}, { 27, 1},
        !           196:                },
        !           197:                (const unsigned char *)"\2  .  .  ;  ;   :  :  ;        \3",
        !           198:                MBG_EXTENDED
        !           199:        },
        !           200:        {                       /* special extended FAU Erlangen GPS format */
        !           201:                {
        !           202:                        { 1,  2}, {  4, 2}, {  7, 2},
        !           203:                        { 14, 2}, { 17, 2}, { 20, 2},
        !           204:                        { 11, 1}, { 32, 7}, { 35, 1},
        !           205:                        { 25, 2}, { 28, 2}, { 24, 1}
        !           206:                },
        !           207:                (const unsigned char *)"\2  .  .  ;  ;   :  :  ;    :  ;        ;   .         .       ",
        !           208:                0
        !           209:        }
        !           210: };
        !           211: 
        !           212: static u_long cvt_meinberg (unsigned char *, int, struct format *, clocktime_t *, void *);
        !           213: static u_long cvt_mgps     (unsigned char *, int, struct format *, clocktime_t *, void *);
        !           214: static u_long mbg_input    (parse_t *, unsigned int, timestamp_t *);
        !           215: static u_long gps_input    (parse_t *, unsigned int, timestamp_t *);
        !           216: 
        !           217: struct msg_buf
        !           218: {
        !           219:   unsigned short len;          /* len to fill */
        !           220:   unsigned short phase;                /* current input phase */
        !           221: };
        !           222: 
        !           223: #define MBG_NONE       0       /* no data input */
        !           224: #define MBG_HEADER     1       /* receiving header */
        !           225: #define MBG_DATA       2       /* receiving data */
        !           226: #define MBG_STRING      3      /* receiving standard data message */
        !           227:   
        !           228: clockformat_t clock_meinberg[] =
        !           229: {
        !           230:        {
        !           231:                mbg_input,      /* normal input handling */
        !           232:                cvt_meinberg,   /* Meinberg conversion */
        !           233:                pps_one,        /* easy PPS monitoring */
        !           234:                0,              /* conversion configuration */
        !           235:                "Meinberg Standard", /* Meinberg simple format - beware */
        !           236:                32,                             /* string buffer */
        !           237:                0               /* no private data (complete pakets) */
        !           238:        },
        !           239:        {
        !           240:                mbg_input,      /* normal input handling */
        !           241:                cvt_meinberg,   /* Meinberg conversion */
        !           242:                pps_one,        /* easy PPS monitoring */
        !           243:                0,              /* conversion configuration */
        !           244:                "Meinberg Extended", /* Meinberg enhanced format */
        !           245:                32,             /* string buffer */
        !           246:                0               /* no private data (complete pakets) */
        !           247:        },
        !           248:        {
        !           249:                gps_input,      /* no input handling */
        !           250:                cvt_mgps,       /* Meinberg GPS166 conversion */
        !           251:                pps_one,        /* easy PPS monitoring */
        !           252:                (void *)&meinberg_fmt[2], /* conversion configuration */
        !           253:                "Meinberg GPS Extended", /* Meinberg FAU GPS format */
        !           254:                512,            /* string buffer */
        !           255:                sizeof(struct msg_buf)  /* no private data (complete pakets) */
        !           256:        }
        !           257: };
        !           258: 
        !           259: /*
        !           260:  * cvt_meinberg
        !           261:  *
        !           262:  * convert simple type format
        !           263:  */
        !           264: static u_long
        !           265: cvt_meinberg(
        !           266:             unsigned char *buffer,
        !           267:             int            size,
        !           268:             struct format *unused,
        !           269:             clocktime_t   *clock_time,
        !           270:             void          *local
        !           271:             )
        !           272: {
        !           273:        struct format *format;
        !           274:        
        !           275:        /*
        !           276:         * select automagically correct data format
        !           277:         */
        !           278:        if (Strok(buffer, meinberg_fmt[0].fixed_string))
        !           279:        {
        !           280:                format = &meinberg_fmt[0];
        !           281:        }
        !           282:        else
        !           283:        {
        !           284:                if (Strok(buffer, meinberg_fmt[1].fixed_string))
        !           285:                {
        !           286:                        format = &meinberg_fmt[1];
        !           287:                }
        !           288:                else
        !           289:                {
        !           290:                        return CVT_FAIL|CVT_BADFMT;
        !           291:                }
        !           292:        }
        !           293: 
        !           294:        /*
        !           295:         * collect data
        !           296:         */
        !           297:        if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
        !           298:                 format->field_offsets[O_DAY].length) ||
        !           299:            Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
        !           300:                 format->field_offsets[O_MONTH].length) ||
        !           301:            Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
        !           302:                 format->field_offsets[O_YEAR].length) ||
        !           303:            Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
        !           304:                 format->field_offsets[O_HOUR].length) ||
        !           305:            Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
        !           306:                 format->field_offsets[O_MIN].length) ||
        !           307:            Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
        !           308:                 format->field_offsets[O_SEC].length))
        !           309:        {
        !           310:                return CVT_FAIL|CVT_BADFMT;
        !           311:        }
        !           312:        else
        !           313:        {
        !           314:                unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
        !           315:                
        !           316:                clock_time->usecond = 0;
        !           317:                clock_time->flags   = PARSEB_S_LEAP;
        !           318: 
        !           319:                if (clock_time->second == 60)
        !           320:                        clock_time->flags |= PARSEB_LEAPSECOND;
        !           321: 
        !           322:                /*
        !           323:                 * in the extended timecode format we have also the
        !           324:                 * indication that the timecode is in UTC
        !           325:                 * for compatibilty reasons we start at the USUAL
        !           326:                 * offset (POWERUP flag) and know that the UTC indication
        !           327:                 * is the character before the powerup flag
        !           328:                 */
        !           329:                if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U'))
        !           330:                {
        !           331:                        /*
        !           332:                         * timecode is in UTC
        !           333:                         */
        !           334:                        clock_time->utcoffset = 0; /* UTC */
        !           335:                        clock_time->flags    |= PARSEB_UTC;
        !           336:                }
        !           337:                else
        !           338:                {
        !           339:                        /*
        !           340:                         * only calculate UTC offset if MET/MED is in time code
        !           341:                         * or we have the old time code format, where we do not
        !           342:                         * know whether it is UTC time or MET/MED
        !           343:                         * pray that nobody switches to UTC in the *old* standard time code
        !           344:                         * ROMS !!!! The new ROMS have 'U' at the ZONE field - good.
        !           345:                         */
        !           346:                        switch (buffer[format->field_offsets[O_ZONE].offset])
        !           347:                        {
        !           348:                        case ' ':
        !           349:                                clock_time->utcoffset = -1*60*60; /* MET */
        !           350:                                break;
        !           351:                                
        !           352:                        case 'S':
        !           353:                                clock_time->utcoffset = -2*60*60; /* MED */
        !           354:                                break;
        !           355: 
        !           356:                        case 'U':
        !           357:                                /*
        !           358:                                 * timecode is in UTC
        !           359:                                 */
        !           360:                                clock_time->utcoffset = 0;        /* UTC */
        !           361:                                clock_time->flags    |= PARSEB_UTC;
        !           362:                                break;
        !           363:                                
        !           364:                        default:
        !           365:                                return CVT_FAIL|CVT_BADFMT;
        !           366:                        }
        !           367:                }
        !           368:                
        !           369:                /*
        !           370:                 * gather status flags
        !           371:                 */
        !           372:                if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
        !           373:                        clock_time->flags    |= PARSEB_DST;
        !           374:                
        !           375:                if (f[0] == '#')
        !           376:                        clock_time->flags |= PARSEB_POWERUP;
        !           377:                
        !           378:                if (f[1] == '*')
        !           379:                        clock_time->flags |= PARSEB_NOSYNC;
        !           380:                
        !           381:                if (f[3] == '!')
        !           382:                        clock_time->flags |= PARSEB_ANNOUNCE;
        !           383:                
        !           384:                /*
        !           385:                 * oncoming leap second
        !           386:                 * 'a' code not confirmed - earth is not
        !           387:                 * expected to speed up
        !           388:                 */
        !           389:                if (f[3] == 'A')
        !           390:                        clock_time->flags |= PARSEB_LEAPADD;
        !           391:                
        !           392:                if (f[3] == 'a')
        !           393:                        clock_time->flags |= PARSEB_LEAPDEL;
        !           394:                
        !           395:                
        !           396:                if (format->flags & MBG_EXTENDED)
        !           397:                {
        !           398:                        clock_time->flags |= PARSEB_S_ANTENNA;
        !           399:                        
        !           400:                        /*
        !           401:                         * DCF77 does not encode the direction -
        !           402:                         * so we take the current default -
        !           403:                         * earth slowing down
        !           404:                         */
        !           405:                        clock_time->flags &= ~PARSEB_LEAPDEL;
        !           406:                        
        !           407:                        if (f[4] == 'A')
        !           408:                                clock_time->flags |= PARSEB_LEAPADD;
        !           409:                        
        !           410:                        if (f[5] == 'R')
        !           411:                                clock_time->flags |= PARSEB_ALTERNATE;
        !           412:                }
        !           413:                return CVT_OK;
        !           414:        }
        !           415: }
        !           416: 
        !           417: 
        !           418: /*
        !           419:  * mbg_input
        !           420:  *
        !           421:  * grep data from input stream
        !           422:  */
        !           423: static u_long
        !           424: mbg_input(
        !           425:          parse_t      *parseio,
        !           426:          unsigned int  ch,
        !           427:          timestamp_t  *tstamp
        !           428:          )
        !           429: {
        !           430:        unsigned int rtc;
        !           431:        
        !           432:        parseprintf(DD_PARSE, ("mbg_input(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
        !           433:        
        !           434:        switch (ch)
        !           435:        {
        !           436:        case STX:
        !           437:                parseprintf(DD_PARSE, ("mbg_input: STX seen\n"));
        !           438:                
        !           439:                parseio->parse_index = 1;
        !           440:                parseio->parse_data[0] = ch;
        !           441:                parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
        !           442:                return PARSE_INP_SKIP;
        !           443:          
        !           444:        case ETX:
        !           445:                parseprintf(DD_PARSE, ("mbg_input: ETX seen\n"));
        !           446:                if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
        !           447:                        return parse_end(parseio);
        !           448:                else
        !           449:                        return rtc;
        !           450: 
        !           451:        default:
        !           452:                return parse_addchar(parseio, ch);
        !           453:        }
        !           454: }
        !           455: 
        !           456: 
        !           457: /*
        !           458:  * cvt_mgps
        !           459:  *
        !           460:  * convert Meinberg GPS format
        !           461:  */
        !           462: static u_long
        !           463: cvt_mgps(
        !           464:         unsigned char *buffer,
        !           465:         int            size,
        !           466:         struct format *format,
        !           467:         clocktime_t   *clock_time,
        !           468:         void          *local
        !           469:        )
        !           470: {
        !           471:        if (!Strok(buffer, format->fixed_string))
        !           472:        {
        !           473:                return cvt_meinberg(buffer, size, format, clock_time, local);
        !           474:        }
        !           475:        else
        !           476:        {
        !           477:                if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
        !           478:                         format->field_offsets[O_DAY].length) ||
        !           479:                    Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
        !           480:                         format->field_offsets[O_MONTH].length) ||
        !           481:                    Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
        !           482:                         format->field_offsets[O_YEAR].length) ||
        !           483:                    Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
        !           484:                         format->field_offsets[O_HOUR].length) ||
        !           485:                    Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
        !           486:                         format->field_offsets[O_MIN].length) ||
        !           487:                    Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
        !           488:                         format->field_offsets[O_SEC].length))
        !           489:                {
        !           490:                        return CVT_FAIL|CVT_BADFMT;
        !           491:                }
        !           492:                else
        !           493:                {
        !           494:                        long h;
        !           495:                        unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
        !           496:          
        !           497:                        clock_time->flags = PARSEB_S_LEAP|PARSEB_S_POSITION;
        !           498:              
        !           499:                        clock_time->usecond = 0;
        !           500: 
        !           501:                        /*
        !           502:                         * calculate UTC offset
        !           503:                         */
        !           504:                        if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h,
        !           505:                                 format->field_offsets[O_UTCHOFFSET].length))
        !           506:                        {
        !           507:                                return CVT_FAIL|CVT_BADFMT;
        !           508:                        }
        !           509:                        else
        !           510:                        {
        !           511:                                if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock_time->utcoffset,
        !           512:                                         format->field_offsets[O_UTCMOFFSET].length))
        !           513:                                {
        !           514:                                        return CVT_FAIL|CVT_BADFMT;
        !           515:                                }
        !           516: 
        !           517:                                clock_time->utcoffset += TIMES60(h);
        !           518:                                clock_time->utcoffset  = TIMES60(clock_time->utcoffset);
        !           519: 
        !           520:                                if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-')
        !           521:                                {
        !           522:                                        clock_time->utcoffset = -clock_time->utcoffset;
        !           523:                                }
        !           524:                        }
        !           525:          
        !           526:                        /*
        !           527:                         * gather status flags
        !           528:                         */
        !           529:                        if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
        !           530:                            clock_time->flags    |= PARSEB_DST;
        !           531:          
        !           532:                        if (clock_time->utcoffset == 0)
        !           533:                            clock_time->flags |= PARSEB_UTC;
        !           534:          
        !           535:                        /*
        !           536:                         * no sv's seen - no time & position
        !           537:                         */
        !           538:                        if (f[0] == '#')
        !           539:                            clock_time->flags |= PARSEB_POWERUP;
        !           540:          
        !           541:                        /*
        !           542:                         * at least one sv seen - time (for last position)
        !           543:                         */
        !           544:                        if (f[1] == '*')
        !           545:                            clock_time->flags |= PARSEB_NOSYNC;
        !           546:                        else
        !           547:                            if (!(clock_time->flags & PARSEB_POWERUP))
        !           548:                                clock_time->flags |= PARSEB_POSITION;
        !           549:          
        !           550:                        /*
        !           551:                         * oncoming zone switch
        !           552:                         */
        !           553:                        if (f[3] == '!')
        !           554:                            clock_time->flags |= PARSEB_ANNOUNCE;
        !           555:          
        !           556:                        /*
        !           557:                         * oncoming leap second
        !           558:                         * 'a' code not confirmed - earth is not
        !           559:                         * expected to speed up
        !           560:                         */
        !           561:                        if (f[4] == 'A')
        !           562:                            clock_time->flags |= PARSEB_LEAPADD;
        !           563:          
        !           564:                        if (f[4] == 'a')
        !           565:                            clock_time->flags |= PARSEB_LEAPDEL;
        !           566: 
        !           567:                        /*
        !           568:                         * f[5] == ' '
        !           569:                         */
        !           570:          
        !           571:                        /*
        !           572:                         * this is the leap second
        !           573:                         */
        !           574:                        if ((f[6] == 'L') || (clock_time->second == 60))
        !           575:                            clock_time->flags |= PARSEB_LEAPSECOND;
        !           576: 
        !           577:                        return CVT_OK;
        !           578:                }
        !           579:        }
        !           580: }
        !           581: 
        !           582: /*
        !           583:  * gps_input
        !           584:  *
        !           585:  * grep binary data from input stream
        !           586:  */
        !           587: static u_long
        !           588: gps_input(
        !           589:          parse_t      *parseio,
        !           590:          unsigned int  ch,
        !           591:          timestamp_t  *tstamp
        !           592:          )
        !           593: {
        !           594:   CSUM calc_csum;                    /* used to compare the incoming csums */
        !           595:   GPS_MSG_HDR header;
        !           596:   struct msg_buf *msg_buf;
        !           597:   
        !           598:   msg_buf = (struct msg_buf *)parseio->parse_pdata;
        !           599: 
        !           600:   parseprintf(DD_PARSE, ("gps_input(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
        !           601: 
        !           602:   if (!msg_buf)
        !           603:     return PARSE_INP_SKIP;
        !           604:   
        !           605:   if ( msg_buf->phase == MBG_NONE )
        !           606:     {                  /* not receiving yet */
        !           607:       switch (ch)
        !           608:        {
        !           609:        case SOH:
        !           610:          parseprintf(DD_PARSE, ("gps_input: SOH seen\n"));
        !           611:          
        !           612:          msg_buf->len = sizeof( header ); /* prepare to receive msg header */
        !           613:          msg_buf->phase = MBG_HEADER; /* receiving header */
        !           614:          break;
        !           615: 
        !           616:        case STX:
        !           617:          parseprintf(DD_PARSE, ("gps_input: STX seen\n"));
        !           618: 
        !           619:          msg_buf->len = 0;
        !           620:          msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */
        !           621:          parseio->parse_index = 1;
        !           622:          parseio->parse_data[0] = ch;
        !           623:          break;
        !           624:          
        !           625:        default:
        !           626:          return PARSE_INP_SKIP;        /* keep searching */
        !           627:        }
        !           628: 
        !           629:       parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */
        !           630:       parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */
        !           631:       parseio->parse_dtime.parse_stime  = *tstamp; /* collect timestamp */
        !           632:       return PARSE_INP_SKIP;
        !           633:     }
        !           634: 
        !           635:   /* SOH/STX has already been received */
        !           636: 
        !           637:   /* save incoming character in both buffers if needbe */
        !           638:   if ((msg_buf->phase == MBG_STRING) &&
        !           639:       (parseio->parse_index < parseio->parse_dsize))
        !           640:     parseio->parse_data[parseio->parse_index++] = ch;
        !           641:   
        !           642:   parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
        !           643: 
        !           644:   if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg))
        !           645:     {
        !           646:       msg_buf->phase = MBG_NONE; /* buffer overflow - discard */
        !           647:       parseio->parse_data[parseio->parse_index] = '\0';
        !           648:       memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
        !           649:       parseio->parse_ldsize = parseio->parse_index;
        !           650:       return PARSE_INP_DATA;
        !           651:     }
        !           652:   
        !           653:   switch (msg_buf->phase)
        !           654:     {
        !           655:     case MBG_HEADER:
        !           656:     case MBG_DATA:
        !           657:       msg_buf->len--;
        !           658: 
        !           659:       if ( msg_buf->len )               /* transfer not complete */
        !           660:        return PARSE_INP_SKIP;
        !           661: 
        !           662:       parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header"));
        !           663: 
        !           664:       break;
        !           665: 
        !           666:     case MBG_STRING:
        !           667:       if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize))
        !           668:        {
        !           669:          msg_buf->phase = MBG_NONE;
        !           670:          parseprintf(DD_PARSE, ("gps_input: string complete\n"));
        !           671:          parseio->parse_data[parseio->parse_index] = '\0';
        !           672:          memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
        !           673:          parseio->parse_ldsize = parseio->parse_index;
        !           674:          parseio->parse_index = 0;
        !           675:          return PARSE_INP_TIME;
        !           676:        }
        !           677:       else
        !           678:        {
        !           679:          return PARSE_INP_SKIP;
        !           680:        }
        !           681:     }
        !           682: 
        !           683:   /* cnt == 0, so the header or the whole message is complete */
        !           684: 
        !           685:   if ( msg_buf->phase == MBG_HEADER )
        !           686:     {         /* header complete now */
        !           687:       unsigned char *datap = parseio->parse_dtime.parse_msg + 1;
        !           688:       
        !           689:       get_mbg_header(&datap, &header);
        !           690:       
        !           691:       parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n",
        !           692:                             (int)header.gps_cmd, (int)header.gps_len, (int)header.gps_data_csum,
        !           693:                             (int)header.gps_hdr_csum));
        !           694:       
        !           695: 
        !           696:       calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 );
        !           697: 
        !           698:       if ( calc_csum != header.gps_hdr_csum )
        !           699:        {
        !           700:          parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n",
        !           701:                                 (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 )));
        !           702:          
        !           703:          msg_buf->phase = MBG_NONE;  /* back to hunting mode */
        !           704:          return PARSE_INP_DATA;      /* invalid header checksum received - pass up for detection */
        !           705:        }
        !           706: 
        !           707:       if ((header.gps_len == 0)  ||       /* no data to wait for */
        !           708:          (header.gps_len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1)))   /* blows anything we have space for */
        !           709:        {
        !           710:          msg_buf->phase = MBG_NONE;  /* back to hunting mode */
        !           711:          return (header.gps_len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */
        !           712:        }
        !           713:     
        !           714:       parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.gps_len));
        !           715:       
        !           716:       msg_buf->len   = header.gps_len;/* save number of bytes to wait for */
        !           717:       msg_buf->phase = MBG_DATA;      /* flag header already complete */
        !           718:       return PARSE_INP_SKIP;
        !           719:     }
        !           720: 
        !           721:   parseprintf(DD_PARSE, ("gps_input: message data complete\n"));
        !           722:   
        !           723:   /* Header and data have been received. The header checksum has been */
        !           724:   /* checked */
        !           725: 
        !           726:   msg_buf->phase = MBG_NONE;         /* back to hunting mode */
        !           727:   return PARSE_INP_DATA;              /* message complete, must be evaluated */
        !           728: }
        !           729: 
        !           730: #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
        !           731: int clk_meinberg_bs;
        !           732: #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
        !           733: 
        !           734: /*
        !           735:  * History:
        !           736:  *
        !           737:  * clk_meinberg.c,v
        !           738:  * Revision 4.12.2.1  2005/09/25 10:22:35  kardel
        !           739:  * cleanup buffer bounds
        !           740:  *
        !           741:  * Revision 4.12  2005/04/16 17:32:10  kardel
        !           742:  * update copyright
        !           743:  *
        !           744:  * Revision 4.11  2004/11/14 15:29:41  kardel
        !           745:  * support PPSAPI, upgrade Copyright to Berkeley style
        !           746:  *
        !           747:  * Revision 4.8  1999/11/28 09:13:50  kardel
        !           748:  * RECON_4_0_98F
        !           749:  *
        !           750:  * Revision 4.7  1999/02/21 11:09:14  kardel
        !           751:  * cleanup
        !           752:  *
        !           753:  * Revision 4.6  1998/06/14 21:09:36  kardel
        !           754:  * Sun acc cleanup
        !           755:  *
        !           756:  * Revision 4.5  1998/06/13 15:18:54  kardel
        !           757:  * fix mem*() to b*() function macro emulation
        !           758:  *
        !           759:  * Revision 4.4  1998/06/13 12:03:23  kardel
        !           760:  * fix SYSV clock name clash
        !           761:  *
        !           762:  * Revision 4.3  1998/06/12 15:22:28  kardel
        !           763:  * fix prototypes
        !           764:  *
        !           765:  * Revision 4.2  1998/05/24 16:14:42  kardel
        !           766:  * support current Meinberg standard data formats
        !           767:  *
        !           768:  * Revision 4.1  1998/05/24 09:39:52  kardel
        !           769:  * implementation of the new IO handling model
        !           770:  *
        !           771:  * Revision 4.0  1998/04/10 19:45:29  kardel
        !           772:  * Start 4.0 release version numbering
        !           773:  *
        !           774:  * from V3 3.23 - log info deleted 1998/04/11 kardel
        !           775:  *
        !           776:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>