Annotation of embedaddon/ntp/libparse/clk_meinberg.c, revision 1.1.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>