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