1224ba2bdSOllivier Robert /* 2224ba2bdSOllivier Robert * 3224ba2bdSOllivier Robert * refclock_hopfser.c 4224ba2bdSOllivier Robert * - clock driver for hopf serial boards (GPS or DCF77) 5224ba2bdSOllivier Robert * 6224ba2bdSOllivier Robert * Date: 30.03.2000 Revision: 01.10 7224ba2bdSOllivier Robert * 8224ba2bdSOllivier Robert * latest source and further information can be found at: 9224ba2bdSOllivier Robert * http://www.ATLSoft.de/ntp 10224ba2bdSOllivier Robert * 11224ba2bdSOllivier Robert */ 12224ba2bdSOllivier Robert 13224ba2bdSOllivier Robert #ifdef HAVE_CONFIG_H 14224ba2bdSOllivier Robert # include "config.h" 15224ba2bdSOllivier Robert #endif 16224ba2bdSOllivier Robert 17224ba2bdSOllivier Robert #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL)) 18224ba2bdSOllivier Robert 19224ba2bdSOllivier Robert #include "ntpd.h" 20224ba2bdSOllivier Robert #include "ntp_io.h" 21224ba2bdSOllivier Robert #include "ntp_control.h" 22224ba2bdSOllivier Robert #include "ntp_refclock.h" 23224ba2bdSOllivier Robert #include "ntp_unixtime.h" 24224ba2bdSOllivier Robert #include "ntp_stdlib.h" 25224ba2bdSOllivier Robert 26224ba2bdSOllivier Robert #if defined HAVE_SYS_MODEM_H 27224ba2bdSOllivier Robert # include <sys/modem.h> 28ea906c41SOllivier Robert # ifndef __QNXNTO__ 29224ba2bdSOllivier Robert # define TIOCMSET MCSETA 30224ba2bdSOllivier Robert # define TIOCMGET MCGETA 31224ba2bdSOllivier Robert # define TIOCM_RTS MRTS 32224ba2bdSOllivier Robert # endif 33ea906c41SOllivier Robert #endif 34224ba2bdSOllivier Robert 35224ba2bdSOllivier Robert #ifdef HAVE_TERMIOS_H 36224ba2bdSOllivier Robert # ifdef TERMIOS_NEEDS__SVID3 37224ba2bdSOllivier Robert # define _SVID3 38224ba2bdSOllivier Robert # endif 39224ba2bdSOllivier Robert # include <termios.h> 40224ba2bdSOllivier Robert # ifdef TERMIOS_NEEDS__SVID3 41224ba2bdSOllivier Robert # undef _SVID3 42224ba2bdSOllivier Robert # endif 43224ba2bdSOllivier Robert #endif 44224ba2bdSOllivier Robert 45224ba2bdSOllivier Robert #ifdef HAVE_SYS_IOCTL_H 46224ba2bdSOllivier Robert # include <sys/ioctl.h> 47224ba2bdSOllivier Robert #endif 48224ba2bdSOllivier Robert 49224ba2bdSOllivier Robert /* 50224ba2bdSOllivier Robert * clock definitions 51224ba2bdSOllivier Robert */ 52224ba2bdSOllivier Robert #define DESCRIPTION "hopf Elektronik serial clock" /* Long name */ 53224ba2bdSOllivier Robert #define PRECISION (-10) /* precision assumed (about 1 ms) */ 54224ba2bdSOllivier Robert #define REFID "hopf\0" /* reference ID */ 55224ba2bdSOllivier Robert /* 56224ba2bdSOllivier Robert * I/O definitions 57224ba2bdSOllivier Robert */ 58224ba2bdSOllivier Robert #define DEVICE "/dev/hopfclock%d" /* device name and unit */ 59224ba2bdSOllivier Robert #define SPEED232 B9600 /* uart speed (9600 baud) */ 60224ba2bdSOllivier Robert 61224ba2bdSOllivier Robert 62224ba2bdSOllivier Robert #define STX 0x02 63224ba2bdSOllivier Robert #define ETX 0x03 64224ba2bdSOllivier Robert #define CR 0x0c 65224ba2bdSOllivier Robert #define LF 0x0a 66224ba2bdSOllivier Robert 67224ba2bdSOllivier Robert /* parse states */ 68224ba2bdSOllivier Robert #define REC_QUEUE_EMPTY 0 69224ba2bdSOllivier Robert #define REC_QUEUE_FULL 1 70224ba2bdSOllivier Robert 71224ba2bdSOllivier Robert #define HOPF_OPMODE 0x0C /* operation mode mask */ 72224ba2bdSOllivier Robert #define HOPF_INVALID 0x00 /* no time code available */ 73224ba2bdSOllivier Robert #define HOPF_INTERNAL 0x04 /* internal clock */ 74224ba2bdSOllivier Robert #define HOPF_RADIO 0x08 /* radio clock */ 75224ba2bdSOllivier Robert #define HOPF_RADIOHP 0x0C /* high precision radio clock */ 76224ba2bdSOllivier Robert 77224ba2bdSOllivier Robert /* 78224ba2bdSOllivier Robert * hopfclock unit control structure. 79224ba2bdSOllivier Robert */ 80224ba2bdSOllivier Robert struct hopfclock_unit { 81224ba2bdSOllivier Robert l_fp laststamp; /* last receive timestamp */ 82224ba2bdSOllivier Robert short unit; /* NTP refclock unit number */ 83224ba2bdSOllivier Robert u_long polled; /* flag to detect noreplies */ 84224ba2bdSOllivier Robert char leap_status; /* leap second flag */ 85224ba2bdSOllivier Robert int rpt_next; 86224ba2bdSOllivier Robert }; 87224ba2bdSOllivier Robert 88224ba2bdSOllivier Robert /* 89224ba2bdSOllivier Robert * Function prototypes 90224ba2bdSOllivier Robert */ 91224ba2bdSOllivier Robert 922b15cb3dSCy Schubert static int hopfserial_start (int, struct peer *); 932b15cb3dSCy Schubert static void hopfserial_shutdown (int, struct peer *); 942b15cb3dSCy Schubert static void hopfserial_receive (struct recvbuf *); 952b15cb3dSCy Schubert static void hopfserial_poll (int, struct peer *); 962b15cb3dSCy Schubert /* static void hopfserial_io (struct recvbuf *); */ 97224ba2bdSOllivier Robert /* 98224ba2bdSOllivier Robert * Transfer vector 99224ba2bdSOllivier Robert */ 100224ba2bdSOllivier Robert struct refclock refclock_hopfser = { 101224ba2bdSOllivier Robert hopfserial_start, /* start up driver */ 102224ba2bdSOllivier Robert hopfserial_shutdown, /* shut down driver */ 103224ba2bdSOllivier Robert hopfserial_poll, /* transmit poll message */ 104224ba2bdSOllivier Robert noentry, /* not used */ 105224ba2bdSOllivier Robert noentry, /* initialize driver (not used) */ 106224ba2bdSOllivier Robert noentry, /* not used */ 107224ba2bdSOllivier Robert NOFLAGS /* not used */ 108224ba2bdSOllivier Robert }; 109224ba2bdSOllivier Robert 110224ba2bdSOllivier Robert /* 111224ba2bdSOllivier Robert * hopfserial_start - open the devices and initialize data for processing 112224ba2bdSOllivier Robert */ 113224ba2bdSOllivier Robert static int 114224ba2bdSOllivier Robert hopfserial_start ( 115224ba2bdSOllivier Robert int unit, 116224ba2bdSOllivier Robert struct peer *peer 117224ba2bdSOllivier Robert ) 118224ba2bdSOllivier Robert { 119224ba2bdSOllivier Robert register struct hopfclock_unit *up; 120224ba2bdSOllivier Robert struct refclockproc *pp; 121224ba2bdSOllivier Robert int fd; 122224ba2bdSOllivier Robert char gpsdev[20]; 123224ba2bdSOllivier Robert 1242b15cb3dSCy Schubert snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 1252b15cb3dSCy Schubert 126224ba2bdSOllivier Robert /* LDISC_STD, LDISC_RAW 127224ba2bdSOllivier Robert * Open serial port. Use CLK line discipline, if available. 128224ba2bdSOllivier Robert */ 129a466cc55SCy Schubert fd = refclock_open(&peer->srcadr, gpsdev, SPEED232, LDISC_CLK); 130224ba2bdSOllivier Robert if (fd <= 0) { 131224ba2bdSOllivier Robert #ifdef DEBUG 132224ba2bdSOllivier Robert printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev); 133224ba2bdSOllivier Robert #endif 134224ba2bdSOllivier Robert return 0; 135224ba2bdSOllivier Robert } 136224ba2bdSOllivier Robert 137224ba2bdSOllivier Robert msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd, 138224ba2bdSOllivier Robert gpsdev); 139224ba2bdSOllivier Robert 140224ba2bdSOllivier Robert /* 141224ba2bdSOllivier Robert * Allocate and initialize unit structure 142224ba2bdSOllivier Robert */ 1432b15cb3dSCy Schubert up = emalloc_zero(sizeof(*up)); 144224ba2bdSOllivier Robert pp = peer->procptr; 1452b15cb3dSCy Schubert pp->unitptr = up; 146224ba2bdSOllivier Robert pp->io.clock_recv = hopfserial_receive; 1472b15cb3dSCy Schubert pp->io.srcclock = peer; 148224ba2bdSOllivier Robert pp->io.datalen = 0; 149224ba2bdSOllivier Robert pp->io.fd = fd; 150224ba2bdSOllivier Robert if (!io_addclock(&pp->io)) { 151224ba2bdSOllivier Robert #ifdef DEBUG 152224ba2bdSOllivier Robert printf("hopfSerialClock(%d) io_addclock\n", unit); 153224ba2bdSOllivier Robert #endif 1542b15cb3dSCy Schubert close(fd); 1552b15cb3dSCy Schubert pp->io.fd = -1; 156224ba2bdSOllivier Robert free(up); 1572b15cb3dSCy Schubert pp->unitptr = NULL; 158224ba2bdSOllivier Robert return (0); 159224ba2bdSOllivier Robert } 160224ba2bdSOllivier Robert 161224ba2bdSOllivier Robert /* 162224ba2bdSOllivier Robert * Initialize miscellaneous variables 163224ba2bdSOllivier Robert */ 164224ba2bdSOllivier Robert pp->clockdesc = DESCRIPTION; 165224ba2bdSOllivier Robert peer->precision = PRECISION; 166224ba2bdSOllivier Robert memcpy((char *)&pp->refid, REFID, 4); 167224ba2bdSOllivier Robert 168224ba2bdSOllivier Robert up->leap_status = 0; 169224ba2bdSOllivier Robert up->unit = (short) unit; 170224ba2bdSOllivier Robert 171224ba2bdSOllivier Robert return (1); 172224ba2bdSOllivier Robert } 173224ba2bdSOllivier Robert 174224ba2bdSOllivier Robert 175224ba2bdSOllivier Robert /* 176224ba2bdSOllivier Robert * hopfserial_shutdown - shut down the clock 177224ba2bdSOllivier Robert */ 178224ba2bdSOllivier Robert static void 179224ba2bdSOllivier Robert hopfserial_shutdown ( 180224ba2bdSOllivier Robert int unit, 181224ba2bdSOllivier Robert struct peer *peer 182224ba2bdSOllivier Robert ) 183224ba2bdSOllivier Robert { 184224ba2bdSOllivier Robert register struct hopfclock_unit *up; 185224ba2bdSOllivier Robert struct refclockproc *pp; 186224ba2bdSOllivier Robert 187224ba2bdSOllivier Robert pp = peer->procptr; 1882b15cb3dSCy Schubert up = pp->unitptr; 1892b15cb3dSCy Schubert 1902b15cb3dSCy Schubert if (-1 != pp->io.fd) 191224ba2bdSOllivier Robert io_closeclock(&pp->io); 1922b15cb3dSCy Schubert if (NULL != up) 193224ba2bdSOllivier Robert free(up); 194224ba2bdSOllivier Robert } 195224ba2bdSOllivier Robert 196224ba2bdSOllivier Robert 197224ba2bdSOllivier Robert 198224ba2bdSOllivier Robert /* 199224ba2bdSOllivier Robert * hopfserial_receive - receive data from the serial interface 200224ba2bdSOllivier Robert */ 201224ba2bdSOllivier Robert 202224ba2bdSOllivier Robert static void 203224ba2bdSOllivier Robert hopfserial_receive ( 204224ba2bdSOllivier Robert struct recvbuf *rbufp 205224ba2bdSOllivier Robert ) 206224ba2bdSOllivier Robert { 207224ba2bdSOllivier Robert struct hopfclock_unit *up; 208224ba2bdSOllivier Robert struct refclockproc *pp; 209224ba2bdSOllivier Robert struct peer *peer; 210224ba2bdSOllivier Robert 2119c2daa00SOllivier Robert int synch; /* synchhronization indicator */ 2122b15cb3dSCy Schubert int DoW; /* Day of Week */ 213224ba2bdSOllivier Robert 214224ba2bdSOllivier Robert int day, month; /* ddd conversion */ 2152b15cb3dSCy Schubert int converted; 216224ba2bdSOllivier Robert 217224ba2bdSOllivier Robert /* 218224ba2bdSOllivier Robert * Initialize pointers and read the timecode and timestamp. 219224ba2bdSOllivier Robert */ 2202b15cb3dSCy Schubert peer = rbufp->recv_peer; 221224ba2bdSOllivier Robert pp = peer->procptr; 2222b15cb3dSCy Schubert up = pp->unitptr; 223224ba2bdSOllivier Robert 224224ba2bdSOllivier Robert if (up->rpt_next == 0 ) 225224ba2bdSOllivier Robert return; 226224ba2bdSOllivier Robert 227224ba2bdSOllivier Robert up->rpt_next = 0; /* wait until next poll interval occur */ 228224ba2bdSOllivier Robert 2292b15cb3dSCy Schubert pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, 2302b15cb3dSCy Schubert sizeof(pp->a_lastcode), 2312b15cb3dSCy Schubert &pp->lastrec); 232224ba2bdSOllivier Robert if (pp->lencode == 0) 233224ba2bdSOllivier Robert return; 234224ba2bdSOllivier Robert 2352b15cb3dSCy Schubert converted = sscanf(pp->a_lastcode, 236224ba2bdSOllivier Robert #if 1 237224ba2bdSOllivier Robert "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */ 238224ba2bdSOllivier Robert #else 239224ba2bdSOllivier Robert "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ 240224ba2bdSOllivier Robert #endif 2419c2daa00SOllivier Robert &synch, 242224ba2bdSOllivier Robert &DoW, 243224ba2bdSOllivier Robert &pp->hour, 244224ba2bdSOllivier Robert &pp->minute, 245224ba2bdSOllivier Robert &pp->second, 246224ba2bdSOllivier Robert &day, 247224ba2bdSOllivier Robert &month, 248224ba2bdSOllivier Robert &pp->year); 249224ba2bdSOllivier Robert 250224ba2bdSOllivier Robert 251224ba2bdSOllivier Robert /* 252224ba2bdSOllivier Robert Validate received values at least enough to prevent internal 253224ba2bdSOllivier Robert array-bounds problems, etc. 254224ba2bdSOllivier Robert */ 2552b15cb3dSCy Schubert if ((8 != converted) || (pp->hour < 0) || (pp->hour > 23) || 2562b15cb3dSCy Schubert (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || 2572b15cb3dSCy Schubert (pp->second > 60) /*Allow for leap seconds.*/ || 258224ba2bdSOllivier Robert (day < 1) || (day > 31) || 259224ba2bdSOllivier Robert (month < 1) || (month > 12) || 260224ba2bdSOllivier Robert (pp->year < 0) || (pp->year > 99)) { 261224ba2bdSOllivier Robert /* Data out of range. */ 262224ba2bdSOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 263224ba2bdSOllivier Robert return; 264224ba2bdSOllivier Robert } 265224ba2bdSOllivier Robert /* 266224ba2bdSOllivier Robert some preparations 267224ba2bdSOllivier Robert */ 268224ba2bdSOllivier Robert pp->day = ymd2yd(pp->year,month,day); 269224ba2bdSOllivier Robert pp->leap=0; 270224ba2bdSOllivier Robert 271224ba2bdSOllivier Robert /* Year-2000 check! */ 272224ba2bdSOllivier Robert /* wrap 2-digit date into 4-digit */ 273224ba2bdSOllivier Robert 274224ba2bdSOllivier Robert if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */ 275224ba2bdSOllivier Robert pp->year += 1900; 276224ba2bdSOllivier Robert 277224ba2bdSOllivier Robert /* preparation for timecode ntpq rl command ! */ 278224ba2bdSOllivier Robert 279224ba2bdSOllivier Robert #if 0 2802b15cb3dSCy Schubert snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 281224ba2bdSOllivier Robert "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", 2829c2daa00SOllivier Robert synch, 283224ba2bdSOllivier Robert DoW, 284224ba2bdSOllivier Robert day, 285224ba2bdSOllivier Robert month, 286224ba2bdSOllivier Robert pp->year, 287224ba2bdSOllivier Robert pp->hour, 288224ba2bdSOllivier Robert pp->minute, 289224ba2bdSOllivier Robert pp->second); 290224ba2bdSOllivier Robert 291224ba2bdSOllivier Robert pp->lencode = strlen(pp->a_lastcode); 2929c2daa00SOllivier Robert if ((synch && 0xc) == 0 ){ /* time ok? */ 293224ba2bdSOllivier Robert refclock_report(peer, CEVNT_BADTIME); 294224ba2bdSOllivier Robert pp->leap = LEAP_NOTINSYNC; 295224ba2bdSOllivier Robert return; 296224ba2bdSOllivier Robert } 297224ba2bdSOllivier Robert #endif 298224ba2bdSOllivier Robert /* 299224ba2bdSOllivier Robert * If clock has no valid status then report error and exit 300224ba2bdSOllivier Robert */ 3019c2daa00SOllivier Robert if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ 302224ba2bdSOllivier Robert refclock_report(peer, CEVNT_BADTIME); 303224ba2bdSOllivier Robert pp->leap = LEAP_NOTINSYNC; 304224ba2bdSOllivier Robert return; 305224ba2bdSOllivier Robert } 306224ba2bdSOllivier Robert 307224ba2bdSOllivier Robert /* 308224ba2bdSOllivier Robert * Test if time is running on internal quarz 309224ba2bdSOllivier Robert * if CLK_FLAG1 is set, sychronize even if no radio operation 310224ba2bdSOllivier Robert */ 311224ba2bdSOllivier Robert 3129c2daa00SOllivier Robert if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){ 313224ba2bdSOllivier Robert if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { 314224ba2bdSOllivier Robert refclock_report(peer, CEVNT_BADTIME); 315224ba2bdSOllivier Robert pp->leap = LEAP_NOTINSYNC; 316224ba2bdSOllivier Robert return; 317224ba2bdSOllivier Robert } 318224ba2bdSOllivier Robert } 319224ba2bdSOllivier Robert 320224ba2bdSOllivier Robert 321224ba2bdSOllivier Robert if (!refclock_process(pp)) { 322224ba2bdSOllivier Robert refclock_report(peer, CEVNT_BADTIME); 323224ba2bdSOllivier Robert return; 324224ba2bdSOllivier Robert } 3259c2daa00SOllivier Robert pp->lastref = pp->lastrec; 326224ba2bdSOllivier Robert refclock_receive(peer); 327224ba2bdSOllivier Robert 328224ba2bdSOllivier Robert #if 0 3299c2daa00SOllivier Robert msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second); 330224ba2bdSOllivier Robert #endif 331224ba2bdSOllivier Robert 332224ba2bdSOllivier Robert record_clock_stats(&peer->srcadr, pp->a_lastcode); 333224ba2bdSOllivier Robert 334224ba2bdSOllivier Robert return; 335224ba2bdSOllivier Robert } 336224ba2bdSOllivier Robert 337224ba2bdSOllivier Robert 338224ba2bdSOllivier Robert /* 339224ba2bdSOllivier Robert * hopfserial_poll - called by the transmit procedure 340224ba2bdSOllivier Robert * 341224ba2bdSOllivier Robert */ 342224ba2bdSOllivier Robert static void 343224ba2bdSOllivier Robert hopfserial_poll ( 344224ba2bdSOllivier Robert int unit, 345224ba2bdSOllivier Robert struct peer *peer 346224ba2bdSOllivier Robert ) 347224ba2bdSOllivier Robert { 348224ba2bdSOllivier Robert register struct hopfclock_unit *up; 349224ba2bdSOllivier Robert struct refclockproc *pp; 350224ba2bdSOllivier Robert pp = peer->procptr; 351224ba2bdSOllivier Robert 3522b15cb3dSCy Schubert up = pp->unitptr; 353224ba2bdSOllivier Robert 354224ba2bdSOllivier Robert pp->polls++; 355224ba2bdSOllivier Robert up->rpt_next = 1; 356224ba2bdSOllivier Robert 357224ba2bdSOllivier Robert #if 0 358224ba2bdSOllivier Robert record_clock_stats(&peer->srcadr, pp->a_lastcode); 359224ba2bdSOllivier Robert #endif 360224ba2bdSOllivier Robert 361224ba2bdSOllivier Robert return; 362224ba2bdSOllivier Robert } 363224ba2bdSOllivier Robert 364224ba2bdSOllivier Robert #else 365*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT 366224ba2bdSOllivier Robert #endif /* REFCLOCK */ 367