Annotation of embedaddon/ntp/ntpd/refclock_fg.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * refclock_fg - clock driver for the Forum Graphic GPS datating station
                      3:  */
                      4: 
                      5: #ifdef HAVE_CONFIG_H
                      6: # include <config.h>
                      7: #endif
                      8: 
                      9: #if defined(REFCLOCK) && defined(CLOCK_FG)
                     10: 
                     11: #include "ntpd.h"
                     12: #include "ntp_io.h"
                     13: #include "ntp_refclock.h"
                     14: #include "ntp_calendar.h"
                     15: #include "ntp_stdlib.h"
                     16: 
                     17: /*
                     18:  * This driver supports the Forum Graphic GPS dating station.
                     19:  * More information about FG GPS is available on http://www.forumgraphic.com
                     20:  * Contact das@amt.ru for any question about this driver.
                     21:  */
                     22: 
                     23: /*
                     24:  * Interface definitions
                     25:  */
                     26: #define        DEVICE          "/dev/fgclock%d"
                     27: #define        PRECISION       (-10)   /* precision assumed (about 1 ms) */
                     28: #define REFID          "GPS"
                     29: #define DESCRIPTION    "Forum Graphic GPS dating station"
                     30: #define LENFG          26      /* timecode length */
                     31: #define SPEED232        B9600   /* uart speed (9600 baud) */
                     32: 
                     33: /*
                     34:  * Function prototypes
                     35:  */
                     36: static int     fg_init         (int);
                     37: static int     fg_start        (int, struct peer *);
                     38: static void    fg_shutdown     (int, struct peer *);
                     39: static void    fg_poll         (int, struct peer *);
                     40: static  void    fg_receive     (struct recvbuf *);
                     41: 
                     42: /* 
                     43:  * Forum Graphic unit control structure
                     44:  */
                     45: 
                     46: struct fgunit {
                     47:        int pollnum;    /* Use peer.poll instead? */
                     48:        int status;     /* Hug to check status information on GPS */
                     49:        int y2kwarn;            /* Y2K bug */
                     50: };
                     51: 
                     52: /* 
                     53:  * Queries definition
                     54:  */
                     55: static char fginit[] = { 0x10, 0x48, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     56: 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                     57: static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     58: 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                     59: 
                     60: /*
                     61:  * Transfer vector
                     62:  */
                     63: struct  refclock refclock_fg = {
                     64:        fg_start,              /* start up driver */
                     65:        fg_shutdown,           /* shut down driver */
                     66:        fg_poll,               /* transmit poll message */
                     67:        noentry,                /* not used */
                     68:        noentry,                /* initialize driver (not used) */
                     69:        noentry,                /* not used */
                     70:        NOFLAGS                 /* not used */
                     71: };
                     72: 
                     73: /*
                     74:  * fg_init - Initialization of FG GPS.
                     75:  */
                     76: 
                     77: static int
                     78: fg_init(
                     79:        int fd
                     80:        )
                     81: {
                     82:        if (write(fd, fginit, LENFG) != LENFG)
                     83:                 return 0;
                     84: 
                     85:        return (1);
                     86: 
                     87: }
                     88: 
                     89: /*
                     90:  * fg_start - open the device and initialize data for processing
                     91:  */
                     92: static int
                     93: fg_start(
                     94:        int unit,
                     95:        struct peer *peer
                     96:        )
                     97: {
                     98:        struct refclockproc *pp;
                     99:        struct fgunit *up;
                    100:        int fd;
                    101:        char device[20];
                    102: 
                    103: 
                    104:        /*
                    105:         * Open device file for reading.
                    106:         */
                    107:        (void)sprintf(device, DEVICE, unit);
                    108: 
                    109: #ifdef DEBUG
                    110:        if (debug)
                    111:                printf ("starting FG with device %s\n",device);
                    112: #endif
                    113:         if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
                    114:                 return (0);
                    115:        
                    116:         /*
                    117:          * Allocate and initialize unit structure
                    118:          */
                    119: 
                    120:        if (!(up = (struct fgunit *)
                    121:               emalloc(sizeof(struct fgunit)))) {
                    122:                 (void) close(fd);
                    123:                 return (0);
                    124:         }
                    125:        memset((char *)up, 0, sizeof(struct fgunit));
                    126:        pp = peer->procptr;
                    127:        pp->unitptr = (caddr_t)up;
                    128:        pp->io.clock_recv = fg_receive;
                    129:        pp->io.srcclock = (caddr_t)peer;
                    130:        pp->io.datalen = 0;
                    131:        pp->io.fd = fd;
                    132:        if (!io_addclock(&pp->io)) {
                    133:                 (void) close(fd);
                    134:                 return (0);
                    135:         }
                    136: 
                    137:        
                    138:        /*
                    139:         * Initialize miscellaneous variables
                    140:         */
                    141:        peer->precision = PRECISION;
                    142:        pp->clockdesc = DESCRIPTION;
                    143:        memcpy((char *)&pp->refid, REFID, 3);
                    144:        up->pollnum = 0;
                    145:        
                    146:        /* 
                    147:         * Setup dating station to use GPS receiver.
                    148:         * GPS receiver should work before this operation.
                    149:          */
                    150:        if(!fg_init(pp->io.fd))
                    151:                refclock_report(peer, CEVNT_FAULT);
                    152: 
                    153:        return (1);
                    154: }
                    155: 
                    156: 
                    157: /*
                    158:  * fg_shutdown - shut down the clock
                    159:  */
                    160: static void
                    161: fg_shutdown(
                    162:        int unit,
                    163:        struct peer *peer
                    164:        )
                    165: {
                    166:        struct refclockproc *pp;
                    167:        struct fgunit *up;
                    168:        
                    169:        pp = peer->procptr;
                    170:        up = (struct fgunit *)pp->unitptr;
                    171:         io_closeclock(&pp->io);
                    172:        free(up);
                    173: }
                    174: 
                    175: 
                    176: /*
                    177:  * fg_poll - called by the transmit procedure
                    178:  */
                    179: static void
                    180: fg_poll(
                    181:        int unit,
                    182:        struct peer *peer
                    183:        )
                    184: {
                    185:        struct refclockproc *pp;
                    186:        
                    187:        pp = peer->procptr;
                    188: 
                    189:         /*
                    190:          * Time to poll the clock. The FG clock responds to a
                    191:          * "<DLE>D<DLE><CR>" by returning a timecode in the format specified
                    192:          * above. If nothing is heard from the clock for two polls,
                    193:          * declare a timeout and keep going.
                    194:          */
                    195: 
                    196:        if (write(pp->io.fd, fgdate, LENFG) != LENFG)
                    197:                 refclock_report(peer, CEVNT_FAULT);
                    198:         else
                    199:                 pp->polls++;
                    200: 
                    201:         if (peer->burst > 0)
                    202:                 return;
                    203:        /*
                    204:         if (pp->coderecv == pp->codeproc) {
                    205:                 refclock_report(peer, CEVNT_TIMEOUT);
                    206:                 return;
                    207:         }
                    208:        */
                    209:         peer->burst = NSTAGE;
                    210: 
                    211:         record_clock_stats(&peer->srcadr, pp->a_lastcode);
                    212:         
                    213:        
                    214:        return;
                    215: 
                    216: }
                    217: 
                    218: /*
                    219:  * fg_receive - receive data from the serial interface
                    220:  */
                    221: static void
                    222: fg_receive(
                    223:         struct recvbuf *rbufp
                    224:         )
                    225: {
                    226:         struct refclockproc *pp;
                    227:        struct fgunit *up;
                    228:         struct peer *peer;
                    229:        char *bpt;
                    230: 
                    231:         /*
                    232:          * Initialize pointers and read the timecode and timestamp
                    233:         * We can't use gtlin function because we need bynary data in buf */
                    234: 
                    235:         peer = (struct peer *)rbufp->recv_srcclock;
                    236:         pp = peer->procptr;
                    237:         up = (struct fgunit *)pp->unitptr;
                    238: 
                    239:        /*
                    240:          * Below hug to implement receiving of status information
                    241:          */
                    242:        if(!up->pollnum)
                    243:        {
                    244:                up->pollnum++;
                    245:                return;
                    246:        }
                    247: 
                    248:        
                    249:        if (rbufp->recv_length < (LENFG-2))
                    250:        {
                    251:                refclock_report(peer, CEVNT_BADREPLY);
                    252:                return; /* The reply is invalid discard it. */
                    253:        }
                    254: 
                    255:        /* Below I trying to find a correct reply in buffer.
                    256:         * Sometime GPS reply located in the beginnig of buffer,
                    257:         * sometime you can find it with some offset.
                    258:         */
                    259: 
                    260:        bpt = (char *)rbufp->recv_space.X_recv_buffer;
                    261:        while(*bpt != '')
                    262:                bpt++;
                    263: 
                    264: #define BP2(x) ( bpt[x] & 15 )
                    265: #define BP1(x) (( bpt[x] & 240 ) >> 4)
                    266:        
                    267:         pp->year = BP1(2)*10 + BP2(2);
                    268:        
                    269:        if(pp->year == 94)
                    270:        {
                    271:                refclock_report(peer, CEVNT_BADREPLY);
                    272:                if(!fg_init(pp->io.fd))
                    273:                        refclock_report(peer, CEVNT_FAULT);
                    274:                return;
                    275:                 /* GPS is just powered up. The date is invalid -
                    276:                 discarding it. Initilize GPS one more time */
                    277:                /* Sorry - this driver will broken in 2094 ;) */
                    278:        }       
                    279:        
                    280:        if (pp->year < 99)
                    281:                 pp->year += 100;
                    282: 
                    283:         pp->year +=  1900;
                    284:         pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);
                    285: 
                    286: /*
                    287:    After Jan, 10 2000 Forum Graphic GPS receiver had a very strange
                    288:    benahour. It doubles day number for an hours in replys after 10:10:10 UTC
                    289:    and doubles min every hour at HH:10:ss for a minute.
                    290:    Hope it is a problem of my unit only and not a Y2K problem of FG GPS. 
                    291:    Below small code to avoid such situation.
                    292: */
                    293:        if(up->y2kwarn > 10)
                    294:                pp->hour = BP1(6)*10 + BP2(6);
                    295:        else
                    296:                pp->hour = BP1(5)*10 + BP2(5);
                    297: 
                    298:        if((up->y2kwarn > 10) && (pp->hour == 10))
                    299:        {
                    300:                pp->minute = BP1(7)*10 + BP2(7);
                    301:                pp->second = BP1(8)*10 + BP2(8);
                    302:                pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000;
                    303:                pp->nsec += BP1(10) * 1000;
                    304:        } else {
                    305:                pp->hour = BP1(5)*10 + BP2(5);
                    306:                pp->minute = BP1(6)*10 + BP2(6);
                    307:                pp->second = BP1(7)*10 + BP2(7);
                    308:                pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000;
                    309:                pp->nsec += BP1(9) * 1000;
                    310:        }
                    311:         
                    312:        if((pp->hour == 10) && (pp->minute == 10))
                    313:        {
                    314:                up->y2kwarn++;
                    315:        }
                    316: 
                    317:        sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second);
                    318:        pp->lencode = strlen(pp->a_lastcode);
                    319:         /*get_systime(&pp->lastrec);*/
                    320: 
                    321: #ifdef DEBUG
                    322:         if (debug)
                    323:                 printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
                    324:                          pp->year, pp->day, pp->hour, pp->minute, pp->second);
                    325: #endif
                    326:         pp->disp =  (10e-6);
                    327:        pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */
                    328:        /* pp->leap = LEAP_NOWARNING; */
                    329: 
                    330:         /*
                    331:          * Process the new sample in the median filter and determine the
                    332:          * timecode timestamp.
                    333:          */
                    334: 
                    335:         if (!refclock_process(pp))
                    336:                 refclock_report(peer, CEVNT_BADTIME);
                    337:         pp->lastref = pp->lastrec;
                    338:        refclock_receive(peer);
                    339:        return;
                    340: }
                    341: 
                    342: 
                    343: #else
                    344: int refclock_fg_bs;
                    345: #endif /* REFCLOCK */

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