File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_fg.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>