Annotation of embedaddon/ntp/libparse/clk_trimtsip.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_trimtsip.c,v 4.19 2009/11/01 10:47:49 kardel RELEASE_20091101_A
                      3:  *
                      4:  * clk_trimtsip.c,v 4.19 2009/11/01 10:47:49 kardel RELEASE_20091101_A
                      5:  *
                      6:  * Trimble TSIP support
                      7:  * Thanks to Sven Dietrich for providing test hardware
                      8:  *
                      9:  * Copyright (c) 1995-2009 by Frank Kardel <kardel <AT> ntp.org>
                     10:  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. Neither the name of the author nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
                     36:  */
                     37: 
                     38: #ifdef HAVE_CONFIG_H
                     39: # include <config.h>
                     40: #endif
                     41: 
                     42: #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_TRIMTSIP)
                     43: 
                     44: #include "ntp_syslog.h"
                     45: #include "ntp_types.h"
                     46: #include "ntp_fp.h"
                     47: #include "ntp_unixtime.h"
                     48: #include "ntp_calendar.h"
                     49: #include "ntp_machine.h"
                     50: #include "ntp_stdlib.h"
                     51: 
                     52: #include "parse.h"
                     53: 
                     54: #ifndef PARSESTREAM
                     55: # include <stdio.h>
                     56: #else
                     57: # include "sys/parsestreams.h"
                     58: #endif
                     59: 
                     60: #include "ascii.h"
                     61: #include "binio.h"
                     62: #include "ieee754io.h"
                     63: #include "trimble.h"
                     64: 
                     65: /*
                     66:  * Trimble low level TSIP parser / time converter
                     67:  *
                     68:  * The receiver uses a serial message protocol called Trimble Standard
                     69:  * Interface Protocol (it can support others but this driver only supports
                     70:  * TSIP). Messages in this protocol have the following form:
                     71:  *
                     72:  * <DLE><id> ... <data> ... <DLE><ETX>
                     73:  *
                     74:  * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
                     75:  * on transmission and compressed back to one on reception. Otherwise
                     76:  * the values of data bytes can be anything. The serial interface is RS-422
                     77:  * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
                     78:  * in total!), and 1 stop bit. The protocol supports byte, integer, single,
                     79:  * and double datatypes. Integers are two bytes, sent most significant first.
                     80:  * Singles are IEEE754 single precision floating point numbers (4 byte) sent
                     81:  * sign & exponent first. Doubles are IEEE754 double precision floating point
                     82:  * numbers (8 byte) sent sign & exponent first.
                     83:  * The receiver supports a large set of messages, only a very small subset of
                     84:  * which is used here.
                     85:  *
                     86:  * From this module the following are recognised:
                     87:  *
                     88:  *  ID    Description
                     89:  *
                     90:  *  41    GPS Time
                     91:  *  46    Receiver health
                     92:  *  4F    UTC correction data (used to get leap second warnings)
                     93:  *
                     94:  * All others are accepted but ignored for time conversion - they are passed up to higher layers.
                     95:  *
                     96:  */
                     97: 
                     98: static offsets_t trim_offsets = { 0, 1, 2, 3, 4, 5, 6, 7 };
                     99: 
                    100: struct trimble
                    101: {
                    102:        u_char  t_in_pkt;       /* first DLE received */
                    103:        u_char  t_dle;          /* subsequent DLE received */
                    104:        u_short t_week;         /* GPS week */
                    105:        u_short t_weekleap;     /* GPS week of next/last week */
                    106:        u_short t_dayleap;      /* day in week */
                    107:        u_short t_gpsutc;       /* GPS - UTC offset */
                    108:        u_short t_gpsutcleap;   /* offset at next/last leap */
                    109:        u_char  t_operable;     /* receiver feels OK */
                    110:        u_char  t_mode;         /* actual operating mode */
                    111:        u_char  t_leap;         /* possible leap warning */
                    112:         u_char  t_utcknown;    /* utc offset known */
                    113: };
                    114: 
                    115: #define STATUS_BAD    0                /* BAD or UNINITIALIZED receiver status */
                    116: #define STATUS_UNSAFE 1                /* not enough receivers for full precision */
                    117: #define STATUS_SYNC   2                /* enough information for good operation */
                    118: 
                    119: static unsigned long inp_tsip (parse_t *, unsigned int, timestamp_t *);
                    120: static unsigned long cvt_trimtsip (unsigned char *, int, struct format *, clocktime_t *, void *);
                    121: 
                    122: struct clockformat clock_trimtsip =
                    123: {
                    124:        inp_tsip,               /* Trimble TSIP input handler */
                    125:        cvt_trimtsip,           /* Trimble TSIP conversion */
                    126:        pps_one,                /* easy PPS monitoring */
                    127:        0,                      /* no configuration data */
                    128:        "Trimble TSIP",
                    129:        400,                    /* input buffer */
                    130:        sizeof(struct trimble)  /* private data */
                    131: };
                    132: 
                    133: #define ADDSECOND      0x01
                    134: #define DELSECOND      0x02
                    135: 
                    136: static unsigned long
                    137: inp_tsip(
                    138:         parse_t      *parseio,
                    139:         unsigned int ch,
                    140:         timestamp_t  *tstamp
                    141:        )
                    142: {
                    143:        struct trimble *t = (struct trimble *)parseio->parse_pdata;
                    144: 
                    145:        if (!t)
                    146:            return PARSE_INP_SKIP;              /* local data not allocated - sigh! */
                    147: 
                    148:        if (!t->t_in_pkt && ch != DLE) {
                    149:                /* wait for start of packet */
                    150:                return PARSE_INP_SKIP;
                    151:        }
                    152: 
                    153:        if ((parseio->parse_index >= (parseio->parse_dsize - 2)) ||
                    154:            (parseio->parse_dtime.parse_msglen >= (sizeof(parseio->parse_dtime.parse_msg) - 2)))
                    155:                {               /* OVERFLOW - DROP! */
                    156:                        t->t_in_pkt = t->t_dle = 0;
                    157:                        parseio->parse_index = 0;
                    158:                        parseio->parse_dtime.parse_msglen = 0;
                    159:                return PARSE_INP_SKIP;
                    160:        }
                    161: 
                    162:        switch (ch) {
                    163:            case DLE:
                    164:                if (!t->t_in_pkt) {
                    165:                        t->t_dle = 0;
                    166:                        t->t_in_pkt = 1;
                    167:                        parseio->parse_index = 0;
                    168:                        parseio->parse_data[parseio->parse_index++] = ch;
                    169:                        parseio->parse_dtime.parse_msglen = 0;
                    170:                        parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
                    171:                        parseio->parse_dtime.parse_stime = *tstamp; /* pick up time stamp at packet start */
                    172:                } else if (t->t_dle) {
                    173:                        /* Double DLE -> insert a DLE */
                    174:                        t->t_dle = 0;
                    175:                        parseio->parse_data[parseio->parse_index++] = DLE;
                    176:                        parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = DLE;
                    177:                } else
                    178:                    t->t_dle = 1;
                    179:                break;
                    180: 
                    181:            case ETX:
                    182:                if (t->t_dle) {
                    183:                        /* DLE,ETX -> end of packet */
                    184:                        parseio->parse_data[parseio->parse_index++] = DLE;
                    185:                        parseio->parse_data[parseio->parse_index] = ch;
                    186:                        parseio->parse_ldsize = parseio->parse_index+1;
                    187:                        memcpy(parseio->parse_ldata, parseio->parse_data, parseio->parse_ldsize);
                    188:                        parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = DLE;
                    189:                        parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
                    190:                        t->t_in_pkt = t->t_dle = 0;
                    191:                        return PARSE_INP_TIME|PARSE_INP_DATA;
                    192:                }
                    193:                /*FALLTHROUGH*/
                    194: 
                    195:            default:            /* collect data */
                    196:                t->t_dle = 0;
                    197:                parseio->parse_data[parseio->parse_index++] = ch;
                    198:                parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
                    199:        }
                    200: 
                    201:   return PARSE_INP_SKIP;
                    202: }
                    203:      
                    204: static int
                    205: getshort(
                    206:         unsigned char *p
                    207:         )
                    208: {
                    209:        return get_msb_short(&p);
                    210: }
                    211: 
                    212: /*
                    213:  * cvt_trimtsip
                    214:  *
                    215:  * convert TSIP type format
                    216:  */
                    217: static unsigned long
                    218: cvt_trimtsip(
                    219:             unsigned char *buffer,
                    220:             int            size,
                    221:             struct format *format,
                    222:             clocktime_t   *clock_time,
                    223:             void          *local
                    224:             )
                    225: {
                    226:         register struct trimble *t = (struct trimble *)local; /* get local data space */
                    227: #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
                    228:        register u_char cmd;
                    229: 
                    230:        clock_time->flags = 0;
                    231: 
                    232:        if (!t) {
                    233:                return CVT_NONE;                /* local data not allocated - sigh! */
                    234:        }
                    235: 
                    236:        if ((size < 4) ||
                    237:            (buffer[0]      != DLE) ||
                    238:            (buffer[size-1] != ETX) ||
                    239:            (buffer[size-2] != DLE))
                    240:        {
                    241:                printf("TRIMBLE BAD packet, size %d:\n", size);
                    242:                return CVT_NONE;
                    243:        }
                    244:        else
                    245:        {
                    246:                unsigned char *bp;
                    247:                cmd = buffer[1];
                    248:       
                    249:                    switch(cmd)
                    250:                    {
                    251:                    case CMD_RCURTIME:
                    252:                            {                   /* GPS time */
                    253:                                    l_fp secs;
                    254:                                    int   week = getshort((unsigned char *)&mb(4));
                    255:                                    l_fp utcoffset;
                    256:                                    l_fp gpstime;
                    257: 
                    258:                                    bp = &mb(0);
                    259:                                    if (fetch_ieee754(&bp, IEEE_SINGLE, &secs, trim_offsets) != IEEE_OK)
                    260:                                            return CVT_FAIL|CVT_BADFMT;
                    261:                                    
                    262:                                    if ((secs.l_i <= 0) ||
                    263:                                        (t->t_utcknown == 0))
                    264:                                    {
                    265:                                            clock_time->flags = PARSEB_POWERUP;
                    266:                                            return CVT_OK;
                    267:                                    }
                    268:                                    if (week < 990) {
                    269:                                            week += 1024;
                    270:                                    }
                    271: 
                    272:                                    /* time OK */
                    273: 
                    274:                                    /* fetch UTC offset */
                    275:                                    bp = &mb(6);
                    276:                                    if (fetch_ieee754(&bp, IEEE_SINGLE, &utcoffset, trim_offsets) != IEEE_OK)
                    277:                                            return CVT_FAIL|CVT_BADFMT;
                    278:                                    
                    279:                                    L_SUB(&secs, &utcoffset); /* adjust GPS time to UTC time */
                    280: 
                    281:                                    gpstolfp((unsigned short)week, (unsigned short)0,
                    282:                                             secs.l_ui, &gpstime);
                    283: 
                    284:                                    gpstime.l_uf = secs.l_uf;
                    285: 
                    286:                                    clock_time->utctime = gpstime.l_ui - JAN_1970;
                    287: 
                    288:                                    TSFTOTVU(gpstime.l_uf, clock_time->usecond);
                    289: 
                    290:                                    if (t->t_leap == ADDSECOND)
                    291:                                        clock_time->flags |= PARSEB_LEAPADD;
                    292:                      
                    293:                                    if (t->t_leap == DELSECOND)
                    294:                                        clock_time->flags |= PARSEB_LEAPDEL;
                    295:        
                    296:                                    switch (t->t_operable)
                    297:                                      {
                    298:                                      case STATUS_SYNC:
                    299:                                        clock_time->flags &= ~(PARSEB_POWERUP|PARSEB_NOSYNC);
                    300:                                        break;
                    301: 
                    302:                                      case STATUS_UNSAFE:
                    303:                                        clock_time->flags |= PARSEB_NOSYNC;
                    304:                                        break;
                    305: 
                    306:                                      case STATUS_BAD:
                    307:                                        clock_time->flags |= PARSEB_NOSYNC|PARSEB_POWERUP;
                    308:                                        break;
                    309:                                      }
                    310:                                        
                    311:                                    if (t->t_mode == 0)
                    312:                                            clock_time->flags |= PARSEB_POSITION;
                    313:                                    
                    314:                                    clock_time->flags |= PARSEB_S_LEAP|PARSEB_S_POSITION;
                    315:                                    
                    316:                                    return CVT_OK;
                    317: 
                    318:                            } /* case 0x41 */
                    319: 
                    320:                    case CMD_RRECVHEALTH:
                    321:                            {
                    322:                                    /* TRIMBLE health */
                    323:                                    u_char status = mb(0);
                    324: 
                    325:                                    switch (status)
                    326:                                    {
                    327:                                      case 0x00: /* position fixes */
                    328:                                        t->t_operable = STATUS_SYNC;
                    329:                                        break;
                    330: 
                    331:                                      case 0x09: /* 1 satellite */
                    332:                                      case 0x0A: /* 2 satellites */
                    333:                                      case 0x0B: /* 3 satellites */
                    334:                                        t->t_operable = STATUS_UNSAFE;
                    335:                                        break;
                    336: 
                    337:                                      default:
                    338:                                        t->t_operable = STATUS_BAD;
                    339:                                        break;
                    340:                                    }
                    341:                                    t->t_mode = status;
                    342:                            }
                    343:                            break;
                    344: 
                    345:                    case CMD_RUTCPARAM:
                    346:                            {
                    347:                                    l_fp t0t;
                    348:                                    unsigned char *lbp;
                    349:                                    
                    350:                                    /* UTC correction data - derive a leap warning */
                    351:                                    int tls   = t->t_gpsutc     = getshort((unsigned char *)&mb(12)); /* current leap correction (GPS-UTC) */
                    352:                                    int tlsf  = t->t_gpsutcleap = getshort((unsigned char *)&mb(24)); /* new leap correction */
                    353: 
                    354:                                    t->t_weekleap   = getshort((unsigned char *)&mb(20)); /* week no of leap correction */
                    355:                                    if (t->t_weekleap < 990)
                    356:                                      t->t_weekleap += 1024;
                    357: 
                    358:                                    t->t_dayleap    = getshort((unsigned char *)&mb(22)); /* day in week of leap correction */
                    359:                                    t->t_week = getshort((unsigned char *)&mb(18)); /* current week no */
                    360:                                    if (t->t_week < 990)
                    361:                                      t->t_week += 1024;
                    362:                                    
                    363:                                    lbp = (unsigned char *)&mb(14); /* last update time */
                    364:                                    if (fetch_ieee754(&lbp, IEEE_SINGLE, &t0t, trim_offsets) != IEEE_OK)
                    365:                                            return CVT_FAIL|CVT_BADFMT;
                    366: 
                    367:                                    t->t_utcknown = t0t.l_ui != 0;
                    368:                                      
                    369:                                    if ((t->t_utcknown) && /* got UTC information */
                    370:                                        (tlsf != tls)   && /* something will change */
                    371:                                        ((t->t_weekleap - t->t_week) < 5)) /* and close in the future */
                    372:                                    {
                    373:                                            /* generate a leap warning */
                    374:                                            if (tlsf > tls)
                    375:                                                t->t_leap = ADDSECOND;
                    376:                                            else
                    377:                                                t->t_leap = DELSECOND;
                    378:                                    }
                    379:                                    else
                    380:                                    {
                    381:                                            t->t_leap = 0;
                    382:                                    }
                    383:                            }
                    384:                            break;
                    385: 
                    386:                    default:
                    387:                            /* it's validly formed, but we don't care about it! */
                    388:                            break;
                    389:                }
                    390:        }
                    391:        return CVT_SKIP;
                    392: }
                    393: 
                    394: #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_TRIMTSIP && !PARSESTREAM) */
                    395: int clk_trimtsip_bs;
                    396: #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_TRIMTSIP && !PARSESTREAM) */
                    397: 
                    398: /*
                    399:  * History:
                    400:  *
                    401:  * clk_trimtsip.c,v
                    402:  * Revision 4.19  2009/11/01 10:47:49  kardel
                    403:  * de-P()
                    404:  *
                    405:  * Revision 4.18  2009/11/01 08:46:46  kardel
                    406:  * clarify case FALLTHROUGH
                    407:  *
                    408:  * Revision 4.17  2005/04/16 17:32:10  kardel
                    409:  * update copyright
                    410:  *
                    411:  * Revision 4.16  2004/11/14 15:29:41  kardel
                    412:  * support PPSAPI, upgrade Copyright to Berkeley style
                    413:  *
                    414:  * Revision 4.13  1999/11/28 09:13:51  kardel
                    415:  * RECON_4_0_98F
                    416:  *
                    417:  * Revision 4.12  1999/02/28 13:00:08  kardel
                    418:  * *** empty log message ***
                    419:  *
                    420:  * Revision 4.11  1999/02/28 11:47:54  kardel
                    421:  * (struct trimble): new member t_utcknown
                    422:  * (cvt_trimtsip): fixed status monitoring, bad receiver states are
                    423:  * now recognized
                    424:  *
                    425:  * Revision 4.10  1999/02/27 15:57:15  kardel
                    426:  * use mmemcpy instead of bcopy
                    427:  *
                    428:  * Revision 4.9  1999/02/21 12:17:42  kardel
                    429:  * 4.91f reconcilation
                    430:  *
                    431:  * Revision 4.8  1998/11/15 20:27:58  kardel
                    432:  * Release 4.0.73e13 reconcilation
                    433:  *
                    434:  * Revision 4.7  1998/08/16 18:49:20  kardel
                    435:  * (cvt_trimtsip): initial kernel capable version (no more floats)
                    436:  * (clock_trimtsip =): new format name
                    437:  *
                    438:  * Revision 4.6  1998/08/09 22:26:05  kardel
                    439:  * Trimble TSIP support
                    440:  *
                    441:  * Revision 4.5  1998/08/02 10:37:05  kardel
                    442:  * working TSIP parser
                    443:  *
                    444:  * Revision 4.4  1998/06/28 16:50:40  kardel
                    445:  * (getflt): fixed ENDIAN issue
                    446:  * (getdbl): fixed ENDIAN issue
                    447:  * (getint): use get_msb_short()
                    448:  * (cvt_trimtsip): use gpstolfp() for conversion
                    449:  *
                    450:  * Revision 4.3  1998/06/13 12:07:31  kardel
                    451:  * fix SYSV clock name clash
                    452:  *
                    453:  * Revision 4.2  1998/06/12 15:22:30  kardel
                    454:  * fix prototypes
                    455:  *
                    456:  * Revision 4.1  1998/05/24 09:39:54  kardel
                    457:  * implementation of the new IO handling model
                    458:  *
                    459:  * Revision 4.0  1998/04/10 19:45:32  kardel
                    460:  * Start 4.0 release version numbering
                    461:  *
                    462:  * from V3 1.8 loginfo deleted 1998/04/11 kardel
                    463:  */

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