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