182498Sroberto/* 282498Sroberto * 382498Sroberto * refclock_hopfser.c 482498Sroberto * - clock driver for hopf serial boards (GPS or DCF77) 582498Sroberto * 682498Sroberto * Date: 30.03.2000 Revision: 01.10 782498Sroberto * 882498Sroberto * latest source and further information can be found at: 982498Sroberto * http://www.ATLSoft.de/ntp 1082498Sroberto * 1182498Sroberto */ 1282498Sroberto 1382498Sroberto#ifdef HAVE_CONFIG_H 1482498Sroberto# include "config.h" 1582498Sroberto#endif 1682498Sroberto 1782498Sroberto#if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL)) 1882498Sroberto 1982498Sroberto#include "ntpd.h" 2082498Sroberto#include "ntp_io.h" 2182498Sroberto#include "ntp_control.h" 2282498Sroberto#include "ntp_refclock.h" 2382498Sroberto#include "ntp_unixtime.h" 2482498Sroberto#include "ntp_stdlib.h" 2582498Sroberto 2682498Sroberto#if defined HAVE_SYS_MODEM_H 2782498Sroberto# include <sys/modem.h> 28182007Sroberto# ifndef __QNXNTO__ 29182007Sroberto# define TIOCMSET MCSETA 30182007Sroberto# define TIOCMGET MCGETA 31182007Sroberto# define TIOCM_RTS MRTS 32182007Sroberto# endif 3382498Sroberto#endif 3482498Sroberto 3582498Sroberto#ifdef HAVE_TERMIOS_H 3682498Sroberto# ifdef TERMIOS_NEEDS__SVID3 3782498Sroberto# define _SVID3 3882498Sroberto# endif 3982498Sroberto# include <termios.h> 4082498Sroberto# ifdef TERMIOS_NEEDS__SVID3 4182498Sroberto# undef _SVID3 4282498Sroberto# endif 4382498Sroberto#endif 4482498Sroberto 4582498Sroberto#ifdef HAVE_SYS_IOCTL_H 4682498Sroberto# include <sys/ioctl.h> 4782498Sroberto#endif 4882498Sroberto 49200576Sroberto#ifdef SYS_WINNT 50200576Srobertoextern int async_write(int, const void *, unsigned int); 51200576Sroberto#undef write 52200576Sroberto#define write(fd, data, octets) async_write(fd, data, octets) 53200576Sroberto#endif 54200576Sroberto 5582498Sroberto/* 5682498Sroberto * clock definitions 5782498Sroberto */ 5882498Sroberto#define DESCRIPTION "hopf Elektronik serial clock" /* Long name */ 5982498Sroberto#define PRECISION (-10) /* precision assumed (about 1 ms) */ 6082498Sroberto#define REFID "hopf\0" /* reference ID */ 6182498Sroberto/* 6282498Sroberto * I/O definitions 6382498Sroberto */ 6482498Sroberto#define DEVICE "/dev/hopfclock%d" /* device name and unit */ 6582498Sroberto#define SPEED232 B9600 /* uart speed (9600 baud) */ 6682498Sroberto 6782498Sroberto 6882498Sroberto#define STX 0x02 6982498Sroberto#define ETX 0x03 7082498Sroberto#define CR 0x0c 7182498Sroberto#define LF 0x0a 7282498Sroberto 7382498Sroberto/* parse states */ 7482498Sroberto#define REC_QUEUE_EMPTY 0 7582498Sroberto#define REC_QUEUE_FULL 1 7682498Sroberto 7782498Sroberto#define HOPF_OPMODE 0x0C /* operation mode mask */ 7882498Sroberto#define HOPF_INVALID 0x00 /* no time code available */ 7982498Sroberto#define HOPF_INTERNAL 0x04 /* internal clock */ 8082498Sroberto#define HOPF_RADIO 0x08 /* radio clock */ 8182498Sroberto#define HOPF_RADIOHP 0x0C /* high precision radio clock */ 8282498Sroberto 8382498Sroberto/* 8482498Sroberto * hopfclock unit control structure. 8582498Sroberto */ 8682498Srobertostruct hopfclock_unit { 8782498Sroberto l_fp laststamp; /* last receive timestamp */ 8882498Sroberto short unit; /* NTP refclock unit number */ 8982498Sroberto u_long polled; /* flag to detect noreplies */ 9082498Sroberto char leap_status; /* leap second flag */ 9182498Sroberto int rpt_next; 9282498Sroberto}; 9382498Sroberto 9482498Sroberto/* 9582498Sroberto * Function prototypes 9682498Sroberto */ 9782498Sroberto 9882498Srobertostatic int hopfserial_start P((int, struct peer *)); 9982498Srobertostatic void hopfserial_shutdown P((int, struct peer *)); 10082498Srobertostatic void hopfserial_receive P((struct recvbuf *)); 10182498Srobertostatic void hopfserial_poll P((int, struct peer *)); 10282498Sroberto/* static void hopfserial_io P((struct recvbuf *)); */ 10382498Sroberto/* 10482498Sroberto * Transfer vector 10582498Sroberto */ 10682498Srobertostruct refclock refclock_hopfser = { 10782498Sroberto hopfserial_start, /* start up driver */ 10882498Sroberto hopfserial_shutdown, /* shut down driver */ 10982498Sroberto hopfserial_poll, /* transmit poll message */ 11082498Sroberto noentry, /* not used */ 11182498Sroberto noentry, /* initialize driver (not used) */ 11282498Sroberto noentry, /* not used */ 11382498Sroberto NOFLAGS /* not used */ 11482498Sroberto}; 11582498Sroberto 11682498Sroberto/* 11782498Sroberto * hopfserial_start - open the devices and initialize data for processing 11882498Sroberto */ 11982498Srobertostatic int 12082498Srobertohopfserial_start ( 12182498Sroberto int unit, 12282498Sroberto struct peer *peer 12382498Sroberto ) 12482498Sroberto{ 12582498Sroberto register struct hopfclock_unit *up; 12682498Sroberto struct refclockproc *pp; 12782498Sroberto int fd; 12882498Sroberto char gpsdev[20]; 12982498Sroberto 13082498Sroberto#ifdef SYS_WINNT 13182498Sroberto (void) sprintf(gpsdev, "COM%d:", unit); 13282498Sroberto#else 13382498Sroberto (void) sprintf(gpsdev, DEVICE, unit); 13482498Sroberto#endif 13582498Sroberto /* LDISC_STD, LDISC_RAW 13682498Sroberto * Open serial port. Use CLK line discipline, if available. 13782498Sroberto */ 13882498Sroberto fd = refclock_open(gpsdev, SPEED232, LDISC_CLK); 13982498Sroberto if (fd <= 0) { 14082498Sroberto#ifdef DEBUG 14182498Sroberto printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev); 14282498Sroberto#endif 14382498Sroberto return 0; 14482498Sroberto } 14582498Sroberto 14682498Sroberto msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd, 14782498Sroberto gpsdev); 14882498Sroberto 14982498Sroberto /* 15082498Sroberto * Allocate and initialize unit structure 15182498Sroberto */ 15282498Sroberto up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit)); 15382498Sroberto 15482498Sroberto if (!(up)) { 15582498Sroberto msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit); 15682498Sroberto#ifdef DEBUG 15782498Sroberto printf("hopfSerialClock(%d) emalloc\n",unit); 15882498Sroberto#endif 15982498Sroberto (void) close(fd); 16082498Sroberto return (0); 16182498Sroberto } 16282498Sroberto 16382498Sroberto memset((char *)up, 0, sizeof(struct hopfclock_unit)); 16482498Sroberto pp = peer->procptr; 16582498Sroberto pp->unitptr = (caddr_t)up; 16682498Sroberto pp->io.clock_recv = hopfserial_receive; 16782498Sroberto pp->io.srcclock = (caddr_t)peer; 16882498Sroberto pp->io.datalen = 0; 16982498Sroberto pp->io.fd = fd; 17082498Sroberto if (!io_addclock(&pp->io)) { 17182498Sroberto#ifdef DEBUG 17282498Sroberto printf("hopfSerialClock(%d) io_addclock\n",unit); 17382498Sroberto#endif 17482498Sroberto (void) close(fd); 17582498Sroberto free(up); 17682498Sroberto return (0); 17782498Sroberto } 17882498Sroberto 17982498Sroberto /* 18082498Sroberto * Initialize miscellaneous variables 18182498Sroberto */ 18282498Sroberto pp->clockdesc = DESCRIPTION; 18382498Sroberto peer->precision = PRECISION; 18482498Sroberto peer->burst = NSTAGE; 18582498Sroberto memcpy((char *)&pp->refid, REFID, 4); 18682498Sroberto 18782498Sroberto up->leap_status = 0; 18882498Sroberto up->unit = (short) unit; 18982498Sroberto 19082498Sroberto return (1); 19182498Sroberto} 19282498Sroberto 19382498Sroberto 19482498Sroberto/* 19582498Sroberto * hopfserial_shutdown - shut down the clock 19682498Sroberto */ 19782498Srobertostatic void 19882498Srobertohopfserial_shutdown ( 19982498Sroberto int unit, 20082498Sroberto struct peer *peer 20182498Sroberto ) 20282498Sroberto{ 20382498Sroberto register struct hopfclock_unit *up; 20482498Sroberto struct refclockproc *pp; 20582498Sroberto 20682498Sroberto pp = peer->procptr; 20782498Sroberto up = (struct hopfclock_unit *)pp->unitptr; 20882498Sroberto io_closeclock(&pp->io); 20982498Sroberto free(up); 21082498Sroberto} 21182498Sroberto 21282498Sroberto 21382498Sroberto 21482498Sroberto/* 21582498Sroberto * hopfserial_receive - receive data from the serial interface 21682498Sroberto */ 21782498Sroberto 21882498Srobertostatic void 21982498Srobertohopfserial_receive ( 22082498Sroberto struct recvbuf *rbufp 22182498Sroberto ) 22282498Sroberto{ 22382498Sroberto struct hopfclock_unit *up; 22482498Sroberto struct refclockproc *pp; 22582498Sroberto struct peer *peer; 22682498Sroberto 227132451Sroberto int synch; /* synchhronization indicator */ 22882498Sroberto int DoW; /* Dow */ 22982498Sroberto 23082498Sroberto int day, month; /* ddd conversion */ 23182498Sroberto 23282498Sroberto /* 23382498Sroberto * Initialize pointers and read the timecode and timestamp. 23482498Sroberto */ 23582498Sroberto peer = (struct peer *)rbufp->recv_srcclock; 23682498Sroberto pp = peer->procptr; 23782498Sroberto up = (struct hopfclock_unit *)pp->unitptr; 23882498Sroberto 23982498Sroberto if (up->rpt_next == 0 ) 24082498Sroberto return; 24182498Sroberto 24282498Sroberto 24382498Sroberto up->rpt_next = 0; /* wait until next poll interval occur */ 24482498Sroberto 245132451Sroberto pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); 24682498Sroberto 24782498Sroberto if (pp->lencode == 0) 24882498Sroberto return; 24982498Sroberto 25082498Sroberto sscanf(pp->a_lastcode, 25182498Sroberto#if 1 25282498Sroberto "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */ 25382498Sroberto#else 25482498Sroberto "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ 25582498Sroberto#endif 256132451Sroberto &synch, 25782498Sroberto &DoW, 25882498Sroberto &pp->hour, 25982498Sroberto &pp->minute, 26082498Sroberto &pp->second, 26182498Sroberto &day, 26282498Sroberto &month, 26382498Sroberto &pp->year); 26482498Sroberto 26582498Sroberto 26682498Sroberto /* 26782498Sroberto Validate received values at least enough to prevent internal 26882498Sroberto array-bounds problems, etc. 26982498Sroberto */ 27082498Sroberto if((pp->hour < 0) || (pp->hour > 23) || 27182498Sroberto (pp->minute < 0) || (pp->minute > 59) || 27282498Sroberto (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || 27382498Sroberto (day < 1) || (day > 31) || 27482498Sroberto (month < 1) || (month > 12) || 27582498Sroberto (pp->year < 0) || (pp->year > 99)) { 27682498Sroberto /* Data out of range. */ 27782498Sroberto refclock_report(peer, CEVNT_BADREPLY); 27882498Sroberto return; 27982498Sroberto } 28082498Sroberto /* 28182498Sroberto some preparations 28282498Sroberto */ 28382498Sroberto pp->day = ymd2yd(pp->year,month,day); 28482498Sroberto pp->leap=0; 28582498Sroberto 28682498Sroberto /* Year-2000 check! */ 28782498Sroberto /* wrap 2-digit date into 4-digit */ 28882498Sroberto 28982498Sroberto if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */ 29082498Sroberto pp->year += 1900; 29182498Sroberto 29282498Sroberto /* preparation for timecode ntpq rl command ! */ 29382498Sroberto 29482498Sroberto#if 0 29582498Sroberto wsprintf(pp->a_lastcode, 29682498Sroberto "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", 297132451Sroberto synch, 29882498Sroberto DoW, 29982498Sroberto day, 30082498Sroberto month, 30182498Sroberto pp->year, 30282498Sroberto pp->hour, 30382498Sroberto pp->minute, 30482498Sroberto pp->second); 30582498Sroberto 30682498Sroberto pp->lencode = strlen(pp->a_lastcode); 307132451Sroberto if ((synch && 0xc) == 0 ){ /* time ok? */ 30882498Sroberto refclock_report(peer, CEVNT_BADTIME); 30982498Sroberto pp->leap = LEAP_NOTINSYNC; 31082498Sroberto return; 31182498Sroberto } 31282498Sroberto#endif 31382498Sroberto /* 31482498Sroberto * If clock has no valid status then report error and exit 31582498Sroberto */ 316132451Sroberto if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ 31782498Sroberto refclock_report(peer, CEVNT_BADTIME); 31882498Sroberto pp->leap = LEAP_NOTINSYNC; 31982498Sroberto return; 32082498Sroberto } 32182498Sroberto 32282498Sroberto /* 32382498Sroberto * Test if time is running on internal quarz 32482498Sroberto * if CLK_FLAG1 is set, sychronize even if no radio operation 32582498Sroberto */ 32682498Sroberto 327132451Sroberto if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){ 32882498Sroberto if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { 32982498Sroberto refclock_report(peer, CEVNT_BADTIME); 33082498Sroberto pp->leap = LEAP_NOTINSYNC; 33182498Sroberto return; 33282498Sroberto } 33382498Sroberto } 33482498Sroberto 33582498Sroberto 33682498Sroberto if (!refclock_process(pp)) { 33782498Sroberto refclock_report(peer, CEVNT_BADTIME); 33882498Sroberto return; 33982498Sroberto } 340132451Sroberto pp->lastref = pp->lastrec; 34182498Sroberto refclock_receive(peer); 34282498Sroberto 34382498Sroberto#if 0 344132451Sroberto msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second); 34582498Sroberto#endif 34682498Sroberto 34782498Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 34882498Sroberto 34982498Sroberto return; 35082498Sroberto} 35182498Sroberto 35282498Sroberto 35382498Sroberto/* 35482498Sroberto * hopfserial_poll - called by the transmit procedure 35582498Sroberto * 35682498Sroberto */ 35782498Srobertostatic void 35882498Srobertohopfserial_poll ( 35982498Sroberto int unit, 36082498Sroberto struct peer *peer 36182498Sroberto ) 36282498Sroberto{ 36382498Sroberto register struct hopfclock_unit *up; 36482498Sroberto struct refclockproc *pp; 36582498Sroberto pp = peer->procptr; 36682498Sroberto 36782498Sroberto up = (struct hopfclock_unit *)pp->unitptr; 36882498Sroberto 36982498Sroberto pp->polls++; 37082498Sroberto up->rpt_next = 1; 37182498Sroberto 37282498Sroberto#if 0 37382498Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 37482498Sroberto#endif 37582498Sroberto 37682498Sroberto return; 37782498Sroberto} 37882498Sroberto 37982498Sroberto#else 38082498Srobertoint refclock_hopfser_bs; 38182498Sroberto#endif /* REFCLOCK */ 382