154359Sroberto/* 254359Sroberto * This software was developed by the Software and Component Technologies 354359Sroberto * group of Trimble Navigation, Ltd. 454359Sroberto * 582498Sroberto * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd. 654359Sroberto * All rights reserved. 754359Sroberto * 854359Sroberto * Redistribution and use in source and binary forms, with or without 954359Sroberto * modification, are permitted provided that the following conditions 1054359Sroberto * are met: 1154359Sroberto * 1. Redistributions of source code must retain the above copyright 1254359Sroberto * notice, this list of conditions and the following disclaimer. 1354359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1454359Sroberto * notice, this list of conditions and the following disclaimer in the 1554359Sroberto * documentation and/or other materials provided with the distribution. 1654359Sroberto * 3. All advertising materials mentioning features or use of this software 1754359Sroberto * must display the following acknowledgement: 1854359Sroberto * This product includes software developed by Trimble Navigation, Ltd. 1954359Sroberto * 4. The name of Trimble Navigation Ltd. may not be used to endorse or 2054359Sroberto * promote products derived from this software without specific prior 2154359Sroberto * written permission. 2254359Sroberto * 2354359Sroberto * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND 2454359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2554359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2654359Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE 2754359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2854359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2954359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3054359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3154359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3254359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3354359Sroberto * SUCH DAMAGE. 3454359Sroberto */ 3554359Sroberto 3654359Sroberto/* 3754359Sroberto * refclock_palisade - clock driver for the Trimble Palisade GPS 3854359Sroberto * timing receiver 3954359Sroberto * 4054359Sroberto * For detailed information on this program, please refer to the html 4154359Sroberto * Refclock 29 page accompanying the NTP distribution. 4254359Sroberto * 4354359Sroberto * for questions / bugs / comments, contact: 4454359Sroberto * sven_dietrich@trimble.com 4554359Sroberto * 4654359Sroberto * Sven-Thorsten Dietrich 4754359Sroberto * 645 North Mary Avenue 4854359Sroberto * Post Office Box 3642 4954359Sroberto * Sunnyvale, CA 94088-3642 5054359Sroberto * 5154359Sroberto * Version 2.45; July 14, 1999 5254359Sroberto * 53290000Sglebius * 54290000Sglebius * 55290000Sglebius * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock. 56290000Sglebius * Contact: Fernando Pablo Hauscarriaga 57290000Sglebius * E-mail: fernandoph@iar.unlp.edu.ar 58290000Sglebius * Home page: www.iar.unlp.edu.ar/~fernandoph 59290000Sglebius * Instituto Argentino de Radioastronomia 60290000Sglebius * www.iar.unlp.edu.ar 61290000Sglebius * 62290000Sglebius * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed 63290000Sglebius * now we use mode 2 for decode thunderbolt packets. 64290000Sglebius * Fernando P. Hauscarriaga 65290000Sglebius * 66290000Sglebius * 30/08/09: Added support for Trimble Acutime Gold Receiver. 67290000Sglebius * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar) 6854359Sroberto */ 6954359Sroberto 7054359Sroberto#ifdef HAVE_CONFIG_H 71290000Sglebius# include "config.h" 7254359Sroberto#endif 7354359Sroberto 74290000Sglebius#if defined(REFCLOCK) && defined(CLOCK_PALISADE) 75200576Sroberto 76200576Sroberto#ifdef SYS_WINNT 77200576Srobertoextern int async_write(int, const void *, unsigned int); 78200576Sroberto#undef write 79200576Sroberto#define write(fd, data, octets) async_write(fd, data, octets) 80132451Sroberto#endif 81132451Sroberto 8254359Sroberto#include "refclock_palisade.h" 8354359Sroberto/* Table to get from month to day of the year */ 8454359Srobertoconst int days_of_year [12] = { 8554359Sroberto 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 8654359Sroberto}; 8754359Sroberto 8854359Sroberto#ifdef DEBUG 8954359Srobertoconst char * Tracking_Status[15][15] = { 90290000Sglebius { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" }, 91290000Sglebius {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" }, 92290000Sglebius { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" }, 93290000Sglebius { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" }, 94290000Sglebius { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } }; 9554359Sroberto#endif 9654359Sroberto 9754359Sroberto/* 9854359Sroberto * Transfer vector 9954359Sroberto */ 10054359Srobertostruct refclock refclock_palisade = { 10154359Sroberto palisade_start, /* start up driver */ 10254359Sroberto palisade_shutdown, /* shut down driver */ 10354359Sroberto palisade_poll, /* transmit poll message */ 10454359Sroberto noentry, /* not used */ 10554359Sroberto noentry, /* initialize driver (not used) */ 10654359Sroberto noentry, /* not used */ 10754359Sroberto NOFLAGS /* not used */ 10854359Sroberto}; 10954359Sroberto 110290000Sglebiusint day_of_year (char *dt); 11154359Sroberto 112132451Sroberto/* Extract the clock type from the mode setting */ 113132451Sroberto#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F)) 114132451Sroberto 115132451Sroberto/* Supported clock types */ 116132451Sroberto#define CLK_TRIMBLE 0 /* Trimble Palisade */ 117132451Sroberto#define CLK_PRAECIS 1 /* Endrun Technologies Praecis */ 118290000Sglebius#define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */ 119290000Sglebius#define CLK_ACUTIME 3 /* Trimble Acutime Gold */ 120290000Sglebius#define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */ 121132451Sroberto 122132451Srobertoint praecis_msg; 123132451Srobertostatic void praecis_parse(struct recvbuf *rbufp, struct peer *peer); 124132451Sroberto 125290000Sglebius/* These routines are for sending packets to the Thunderbolt receiver 126290000Sglebius * They are taken from Markus Prosch 127290000Sglebius */ 128290000Sglebius 129290000Sglebius#ifdef PALISADE_SENDCMD_RESURRECTED 13054359Sroberto/* 131290000Sglebius * sendcmd - Build data packet for sending 132290000Sglebius */ 133290000Sglebiusstatic void 134290000Sglebiussendcmd ( 135290000Sglebius struct packettx *buffer, 136290000Sglebius int c 137290000Sglebius ) 138290000Sglebius{ 139290000Sglebius *buffer->data = DLE; 140290000Sglebius *(buffer->data + 1) = (unsigned char)c; 141290000Sglebius buffer->size = 2; 142290000Sglebius} 143290000Sglebius#endif /* PALISADE_SENDCMD_RESURRECTED */ 144290000Sglebius 145290000Sglebius/* 146290000Sglebius * sendsupercmd - Build super data packet for sending 147290000Sglebius */ 148290000Sglebiusstatic void 149290000Sglebiussendsupercmd ( 150290000Sglebius struct packettx *buffer, 151290000Sglebius int c1, 152290000Sglebius int c2 153290000Sglebius ) 154290000Sglebius{ 155290000Sglebius *buffer->data = DLE; 156290000Sglebius *(buffer->data + 1) = (unsigned char)c1; 157290000Sglebius *(buffer->data + 2) = (unsigned char)c2; 158290000Sglebius buffer->size = 3; 159290000Sglebius} 160290000Sglebius 161290000Sglebius/* 162290000Sglebius * sendbyte - 163290000Sglebius */ 164290000Sglebiusstatic void 165290000Sglebiussendbyte ( 166290000Sglebius struct packettx *buffer, 167290000Sglebius int b 168290000Sglebius ) 169290000Sglebius{ 170290000Sglebius if (b == DLE) 171290000Sglebius *(buffer->data+buffer->size++) = DLE; 172290000Sglebius *(buffer->data+buffer->size++) = (unsigned char)b; 173290000Sglebius} 174290000Sglebius 175290000Sglebius/* 176290000Sglebius * sendint - 177290000Sglebius */ 178290000Sglebiusstatic void 179290000Sglebiussendint ( 180290000Sglebius struct packettx *buffer, 181290000Sglebius int a 182290000Sglebius ) 183290000Sglebius{ 184290000Sglebius sendbyte(buffer, (unsigned char)((a>>8) & 0xff)); 185290000Sglebius sendbyte(buffer, (unsigned char)(a & 0xff)); 186290000Sglebius} 187290000Sglebius 188290000Sglebius/* 189290000Sglebius * sendetx - Send packet or super packet to the device 190290000Sglebius */ 191290000Sglebiusstatic int 192290000Sglebiussendetx ( 193290000Sglebius struct packettx *buffer, 194290000Sglebius int fd 195290000Sglebius ) 196290000Sglebius{ 197290000Sglebius int result; 198290000Sglebius 199290000Sglebius *(buffer->data+buffer->size++) = DLE; 200290000Sglebius *(buffer->data+buffer->size++) = ETX; 201290000Sglebius result = write(fd, buffer->data, (unsigned long)buffer->size); 202290000Sglebius 203290000Sglebius if (result != -1) 204290000Sglebius return (result); 205290000Sglebius else 206290000Sglebius return (-1); 207290000Sglebius} 208290000Sglebius 209290000Sglebius/* 210290000Sglebius * init_thunderbolt - Prepares Thunderbolt receiver to be used with 211290000Sglebius * NTP (also taken from Markus Prosch). 212290000Sglebius */ 213290000Sglebiusstatic void 214290000Sglebiusinit_thunderbolt ( 215290000Sglebius int fd 216290000Sglebius ) 217290000Sglebius{ 218290000Sglebius struct packettx tx; 219290000Sglebius 220290000Sglebius tx.size = 0; 221290000Sglebius tx.data = (u_char *) emalloc(100); 222290000Sglebius 223290000Sglebius /* set UTC time */ 224290000Sglebius sendsupercmd (&tx, 0x8E, 0xA2); 225290000Sglebius sendbyte (&tx, 0x3); 226290000Sglebius sendetx (&tx, fd); 227290000Sglebius 228290000Sglebius /* activate packets 0x8F-AB and 0x8F-AC */ 229290000Sglebius sendsupercmd (&tx, 0x8F, 0xA5); 230290000Sglebius sendint (&tx, 0x5); 231290000Sglebius sendetx (&tx, fd); 232290000Sglebius 233290000Sglebius free(tx.data); 234290000Sglebius} 235290000Sglebius 236290000Sglebius/* 237290000Sglebius * init_acutime - Prepares Acutime Receiver to be used with NTP 238290000Sglebius */ 239290000Sglebiusstatic void 240290000Sglebiusinit_acutime ( 241290000Sglebius int fd 242290000Sglebius ) 243290000Sglebius{ 244290000Sglebius /* Disable all outputs, Enable Event-Polling on PortA so 245290000Sglebius we can ask for time packets */ 246290000Sglebius struct packettx tx; 247290000Sglebius 248290000Sglebius tx.size = 0; 249290000Sglebius tx.data = (u_char *) emalloc(100); 250290000Sglebius 251290000Sglebius sendsupercmd(&tx, 0x8E, 0xA5); 252290000Sglebius sendbyte(&tx, 0x02); 253290000Sglebius sendbyte(&tx, 0x00); 254290000Sglebius sendbyte(&tx, 0x00); 255290000Sglebius sendbyte(&tx, 0x00); 256290000Sglebius sendetx(&tx, fd); 257290000Sglebius 258290000Sglebius free(tx.data); 259290000Sglebius} 260290000Sglebius 261290000Sglebius/* 26254359Sroberto * palisade_start - open the devices and initialize data for processing 26354359Sroberto */ 26454359Srobertostatic int 26554359Srobertopalisade_start ( 26654359Sroberto int unit, 26754359Sroberto struct peer *peer 26854359Sroberto ) 26954359Sroberto{ 27054359Sroberto struct palisade_unit *up; 27154359Sroberto struct refclockproc *pp; 27254359Sroberto int fd; 27354359Sroberto char gpsdev[20]; 274290000Sglebius struct termios tio; 27554359Sroberto 276290000Sglebius snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 277290000Sglebius 27854359Sroberto /* 27954359Sroberto * Open serial port. 28054359Sroberto */ 28154359Sroberto fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 28254359Sroberto if (fd <= 0) { 28354359Sroberto#ifdef DEBUG 28454359Sroberto printf("Palisade(%d) start: open %s failed\n", unit, gpsdev); 28554359Sroberto#endif 28654359Sroberto return 0; 28754359Sroberto } 28854359Sroberto 28954359Sroberto msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd, 29054359Sroberto gpsdev); 29154359Sroberto 292290000Sglebius if (tcgetattr(fd, &tio) < 0) { 293290000Sglebius msyslog(LOG_ERR, 29454359Sroberto "Palisade(%d) tcgetattr(fd, &tio): %m",unit); 29554359Sroberto#ifdef DEBUG 296290000Sglebius printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit); 29754359Sroberto#endif 298290000Sglebius close(fd); 299290000Sglebius return (0); 300290000Sglebius } 30154359Sroberto 302290000Sglebius tio.c_cflag |= (PARENB|PARODD); 303290000Sglebius tio.c_iflag &= ~ICRNL; 30454359Sroberto 30554359Sroberto /* 30654359Sroberto * Allocate and initialize unit structure 30754359Sroberto */ 308290000Sglebius up = emalloc_zero(sizeof(*up)); 30954359Sroberto 310132451Sroberto up->type = CLK_TYPE(peer); 311132451Sroberto switch (up->type) { 312290000Sglebius case CLK_TRIMBLE: 313290000Sglebius /* Normal mode, do nothing */ 314290000Sglebius break; 315290000Sglebius case CLK_PRAECIS: 316290000Sglebius msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled" 317290000Sglebius ,unit); 318290000Sglebius break; 319290000Sglebius case CLK_THUNDERBOLT: 320290000Sglebius msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled" 321290000Sglebius ,unit); 322290000Sglebius tio.c_cflag = (CS8|CLOCAL|CREAD); 323290000Sglebius break; 324290000Sglebius case CLK_ACUTIME: 325290000Sglebius msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled" 326290000Sglebius ,unit); 327290000Sglebius break; 328290000Sglebius default: 329290000Sglebius msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit); 330290000Sglebius break; 331132451Sroberto } 332290000Sglebius if (tcsetattr(fd, TCSANOW, &tio) == -1) { 333290000Sglebius msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); 334290000Sglebius#ifdef DEBUG 335290000Sglebius printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit); 336290000Sglebius#endif 337290000Sglebius close(fd); 338290000Sglebius free(up); 339290000Sglebius return 0; 340290000Sglebius } 341132451Sroberto 34254359Sroberto pp = peer->procptr; 34354359Sroberto pp->io.clock_recv = palisade_io; 344290000Sglebius pp->io.srcclock = peer; 34554359Sroberto pp->io.datalen = 0; 34654359Sroberto pp->io.fd = fd; 34754359Sroberto if (!io_addclock(&pp->io)) { 34854359Sroberto#ifdef DEBUG 349290000Sglebius printf("Palisade(%d) io_addclock\n",unit); 35054359Sroberto#endif 351290000Sglebius close(fd); 352290000Sglebius pp->io.fd = -1; 35354359Sroberto free(up); 35454359Sroberto return (0); 35554359Sroberto } 35654359Sroberto 35754359Sroberto /* 35854359Sroberto * Initialize miscellaneous variables 35954359Sroberto */ 360290000Sglebius pp->unitptr = up; 36154359Sroberto pp->clockdesc = DESCRIPTION; 36254359Sroberto 36354359Sroberto peer->precision = PRECISION; 36454359Sroberto peer->sstclktype = CTL_SST_TS_UHF; 36554359Sroberto peer->minpoll = TRMB_MINPOLL; 36654359Sroberto peer->maxpoll = TRMB_MAXPOLL; 36754359Sroberto memcpy((char *)&pp->refid, REFID, 4); 36854359Sroberto 36954359Sroberto up->leap_status = 0; 37054359Sroberto up->unit = (short) unit; 37154359Sroberto up->rpt_status = TSIP_PARSED_EMPTY; 372290000Sglebius up->rpt_cnt = 0; 37354359Sroberto 374290000Sglebius if (up->type == CLK_THUNDERBOLT) 375290000Sglebius init_thunderbolt(fd); 376290000Sglebius if (up->type == CLK_ACUTIME) 377290000Sglebius init_acutime(fd); 378290000Sglebius 37954359Sroberto return 1; 38054359Sroberto} 38154359Sroberto 38254359Sroberto 38354359Sroberto/* 38454359Sroberto * palisade_shutdown - shut down the clock 38554359Sroberto */ 38654359Srobertostatic void 38754359Srobertopalisade_shutdown ( 38854359Sroberto int unit, 38954359Sroberto struct peer *peer 39054359Sroberto ) 39154359Sroberto{ 39254359Sroberto struct palisade_unit *up; 39354359Sroberto struct refclockproc *pp; 39454359Sroberto pp = peer->procptr; 395290000Sglebius up = pp->unitptr; 396290000Sglebius if (-1 != pp->io.fd) 397290000Sglebius io_closeclock(&pp->io); 398290000Sglebius if (NULL != up) 399290000Sglebius free(up); 40054359Sroberto} 40154359Sroberto 40254359Sroberto 40354359Sroberto 40454359Sroberto/* 40554359Sroberto * unpack_date - get day and year from date 40654359Sroberto */ 40754359Srobertoint 40854359Srobertoday_of_year ( 40954359Sroberto char * dt 41054359Sroberto ) 41154359Sroberto{ 41254359Sroberto int day, mon, year; 41354359Sroberto 41454359Sroberto mon = dt[1]; 415290000Sglebius /* Check month is inside array bounds */ 416290000Sglebius if ((mon < 1) || (mon > 12)) 41754359Sroberto return -1; 41854359Sroberto 41954359Sroberto day = dt[0] + days_of_year[mon - 1]; 42054359Sroberto year = getint((u_char *) (dt + 2)); 42154359Sroberto 42254359Sroberto if ( !(year % 4) && ((year % 100) || 423290000Sglebius (!(year % 100) && !(year%400))) 424290000Sglebius &&(mon > 2)) 425290000Sglebius day ++; /* leap year and March or later */ 42654359Sroberto 42754359Sroberto return day; 42854359Sroberto} 42954359Sroberto 43054359Sroberto 43154359Sroberto/* 43254359Sroberto * TSIP_decode - decode the TSIP data packets 43354359Sroberto */ 43454359Srobertoint 43554359SrobertoTSIP_decode ( 43654359Sroberto struct peer *peer 43754359Sroberto ) 43854359Sroberto{ 43954359Sroberto int st; 44054359Sroberto long secint; 44154359Sroberto double secs; 44254359Sroberto double secfrac; 44354359Sroberto unsigned short event = 0; 44454359Sroberto 44554359Sroberto struct palisade_unit *up; 44654359Sroberto struct refclockproc *pp; 44754359Sroberto 44854359Sroberto pp = peer->procptr; 449290000Sglebius up = pp->unitptr; 45054359Sroberto 45154359Sroberto /* 45254359Sroberto * Check the time packet, decode its contents. 45354359Sroberto * If the timecode has invalid length or is not in 45454359Sroberto * proper format, declare bad format and exit. 45554359Sroberto */ 45654359Sroberto 457290000Sglebius if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){ 458290000Sglebius if ((up->rpt_buf[0] == (char) 0x41) || 459290000Sglebius (up->rpt_buf[0] == (char) 0x46) || 460290000Sglebius (up->rpt_buf[0] == (char) 0x54) || 461290000Sglebius (up->rpt_buf[0] == (char) 0x4B) || 462290000Sglebius (up->rpt_buf[0] == (char) 0x6D)) { 46354359Sroberto 464290000Sglebius /* standard time packet - GPS time and GPS week number */ 46554359Sroberto#ifdef DEBUG 46654359Sroberto printf("Palisade Port B packets detected. Connect to Port A\n"); 46754359Sroberto#endif 46854359Sroberto 469290000Sglebius return 0; 470290000Sglebius } 47154359Sroberto } 47254359Sroberto 473132451Sroberto /* 474132451Sroberto * We cast both to u_char to as 0x8f uses the sign bit on a char 475132451Sroberto */ 476132451Sroberto if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) { 477290000Sglebius /* 478290000Sglebius * Superpackets 479290000Sglebius */ 480290000Sglebius event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff); 481290000Sglebius if (!((pp->sloppyclockflag & CLK_FLAG2) || event)) 482290000Sglebius /* Ignore Packet */ 48354359Sroberto return 0; 48454359Sroberto 485290000Sglebius switch (mb(0) & 0xff) { 486290000Sglebius int GPS_UTC_Offset; 487290000Sglebius long tow; 48854359Sroberto 489290000Sglebius case PACKET_8F0B: 49054359Sroberto 491290000Sglebius if (up->polled <= 0) 492290000Sglebius return 0; 493290000Sglebius 494290000Sglebius if (up->rpt_cnt != LENCODE_8F0B) /* check length */ 495290000Sglebius break; 49654359Sroberto 49754359Sroberto#ifdef DEBUG 498290000Sglebius if (debug > 1) { 499290000Sglebius int ts; 500290000Sglebius double lat, lon, alt; 501290000Sglebius lat = getdbl((u_char *) &mb(42)) * R2D; 502290000Sglebius lon = getdbl((u_char *) &mb(50)) * R2D; 503290000Sglebius alt = getdbl((u_char *) &mb(58)); 50454359Sroberto 505290000Sglebius printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 506290000Sglebius up->unit, lat,lon,alt); 507290000Sglebius printf("TSIP_decode: unit %d: Sats:", 508290000Sglebius up->unit); 509290000Sglebius for (st = 66, ts = 0; st <= 73; st++) 510290000Sglebius if (mb(st)) { 511290000Sglebius if (mb(st) > 0) ts++; 512290000Sglebius printf(" %02d", mb(st)); 513290000Sglebius } 514290000Sglebius printf(" : Tracking %d\n", ts); 515290000Sglebius } 51654359Sroberto#endif 51754359Sroberto 518290000Sglebius GPS_UTC_Offset = getint((u_char *) &mb(16)); 519290000Sglebius if (GPS_UTC_Offset == 0) { /* Check UTC offset */ 52054359Sroberto#ifdef DEBUG 521290000Sglebius printf("TSIP_decode: UTC Offset Unknown\n"); 52254359Sroberto#endif 523290000Sglebius break; 524290000Sglebius } 52554359Sroberto 526290000Sglebius secs = getdbl((u_char *) &mb(3)); 527290000Sglebius secint = (long) secs; 528290000Sglebius secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ 52954359Sroberto 530290000Sglebius pp->nsec = (long) (secfrac * 1000000000); 53154359Sroberto 532290000Sglebius secint %= 86400; /* Only care about today */ 533290000Sglebius pp->hour = secint / 3600; 534290000Sglebius secint %= 3600; 535290000Sglebius pp->minute = secint / 60; 536290000Sglebius secint %= 60; 537290000Sglebius pp->second = secint % 60; 53854359Sroberto 539290000Sglebius if ((pp->day = day_of_year(&mb(11))) < 0) break; 54054359Sroberto 541290000Sglebius pp->year = getint((u_char *) &mb(13)); 54254359Sroberto 54354359Sroberto#ifdef DEBUG 544290000Sglebius if (debug > 1) 545290000Sglebius printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n", 546290000Sglebius up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 547290000Sglebius pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset); 54854359Sroberto#endif 549290000Sglebius /* Only use this packet when no 550290000Sglebius * 8F-AD's are being received 551290000Sglebius */ 55254359Sroberto 553290000Sglebius if (up->leap_status) { 554290000Sglebius up->leap_status = 0; 555290000Sglebius return 0; 556290000Sglebius } 55754359Sroberto 558290000Sglebius return 2; 559290000Sglebius break; 56054359Sroberto 561290000Sglebius case PACKET_NTP: 562290000Sglebius /* Palisade-NTP Packet */ 56354359Sroberto 564290000Sglebius if (up->rpt_cnt != LENCODE_NTP) /* check length */ 565290000Sglebius break; 56654359Sroberto 567290000Sglebius up->leap_status = mb(19); 56854359Sroberto 569290000Sglebius if (up->polled <= 0) 570290000Sglebius return 0; 57154359Sroberto 572290000Sglebius /* Check Tracking Status */ 573290000Sglebius st = mb(18); 574290000Sglebius if (st < 0 || st > 14) 575290000Sglebius st = 14; 576290000Sglebius if ((st >= 2 && st <= 7) || st == 11 || st == 12) { 57754359Sroberto#ifdef DEBUG 578290000Sglebius printf("TSIP_decode: Not Tracking Sats : %s\n", 579290000Sglebius *Tracking_Status[st]); 58054359Sroberto#endif 581290000Sglebius refclock_report(peer, CEVNT_BADTIME); 582290000Sglebius up->polled = -1; 583290000Sglebius return 0; 584290000Sglebius break; 585290000Sglebius } 586290000Sglebius 587290000Sglebius up->month = mb(15); 588290000Sglebius if ( (up->leap_status & PALISADE_LEAP_PENDING) && 589290000Sglebius /* Avoid early announce: https://bugs.ntp.org/2773 */ 590290000Sglebius (6 == up->month || 12 == up->month) ) { 591290000Sglebius if (up->leap_status & PALISADE_UTC_TIME) 592290000Sglebius pp->leap = LEAP_ADDSECOND; 593290000Sglebius else 594290000Sglebius pp->leap = LEAP_DELSECOND; 595290000Sglebius } 596290000Sglebius else if (up->leap_status) 597290000Sglebius pp->leap = LEAP_NOWARNING; 598290000Sglebius 599290000Sglebius else { /* UTC flag is not set: 600290000Sglebius * Receiver may have been reset, and lost 601290000Sglebius * its UTC almanac data */ 602290000Sglebius pp->leap = LEAP_NOTINSYNC; 603290000Sglebius#ifdef DEBUG 604290000Sglebius printf("TSIP_decode: UTC Almanac unavailable: %d\n", 605290000Sglebius mb(19)); 606290000Sglebius#endif 607290000Sglebius refclock_report(peer, CEVNT_BADTIME); 608290000Sglebius up->polled = -1; 609290000Sglebius return 0; 610290000Sglebius } 611290000Sglebius 612290000Sglebius pp->nsec = (long) (getdbl((u_char *) &mb(3)) 613290000Sglebius * 1000000000); 614290000Sglebius 615290000Sglebius if ((pp->day = day_of_year(&mb(14))) < 0) 616290000Sglebius break; 617290000Sglebius pp->year = getint((u_char *) &mb(16)); 618290000Sglebius pp->hour = mb(11); 619290000Sglebius pp->minute = mb(12); 620290000Sglebius pp->second = mb(13); 621290000Sglebius up->month = mb(14); /* Save for LEAP check */ 622290000Sglebius 623290000Sglebius#ifdef DEBUG 624290000Sglebius if (debug > 1) 625290000Sglebius printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n", 626290000Sglebius up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 627290000Sglebius pp->second, pp->nsec, mb(15), mb(14), pp->year, 628290000Sglebius mb(19), *Tracking_Status[st]); 629290000Sglebius#endif 630290000Sglebius return 1; 631290000Sglebius break; 632290000Sglebius 633290000Sglebius case PACKET_8FAC: 634290000Sglebius if (up->polled <= 0) 635290000Sglebius return 0; 636290000Sglebius 637290000Sglebius if (up->rpt_cnt != LENCODE_8FAC)/* check length */ 638290000Sglebius break; 639290000Sglebius 640290000Sglebius#ifdef DEBUG 641290000Sglebius if (debug > 1) { 642290000Sglebius double lat, lon, alt; 643290000Sglebius lat = getdbl((u_char *) &mb(36)) * R2D; 644290000Sglebius lon = getdbl((u_char *) &mb(44)) * R2D; 645290000Sglebius alt = getdbl((u_char *) &mb(52)); 646290000Sglebius 647290000Sglebius printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 648290000Sglebius up->unit, lat,lon,alt); 649290000Sglebius printf("TSIP_decode: unit %d\n", up->unit); 650290000Sglebius } 651290000Sglebius#endif 652290000Sglebius if ( (getint((u_char *) &mb(10)) & 0x80) && 653290000Sglebius /* Avoid early announce: https://bugs.ntp.org/2773 */ 654290000Sglebius (6 == up->month || 12 == up->month) ) 655290000Sglebius pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */ 656290000Sglebius else 657290000Sglebius pp->leap = LEAP_NOWARNING; 658290000Sglebius 659290000Sglebius#ifdef DEBUG 660290000Sglebius if (debug > 1) 661290000Sglebius printf("TSIP_decode: unit %d: 0x%02x leap %d\n", 662290000Sglebius up->unit, mb(0) & 0xff, pp->leap); 663290000Sglebius if (debug > 1) { 664290000Sglebius printf("Receiver MODE: 0x%02X\n", (u_char)mb(1)); 665290000Sglebius if (mb(1) == 0x00) 666290000Sglebius printf(" AUTOMATIC\n"); 667290000Sglebius if (mb(1) == 0x01) 668290000Sglebius printf(" SINGLE SATELLITE\n"); 669290000Sglebius if (mb(1) == 0x03) 670290000Sglebius printf(" HORIZONTAL(2D)\n"); 671290000Sglebius if (mb(1) == 0x04) 672290000Sglebius printf(" FULL POSITION(3D)\n"); 673290000Sglebius if (mb(1) == 0x05) 674290000Sglebius printf(" DGPR REFERENCE\n"); 675290000Sglebius if (mb(1) == 0x06) 676290000Sglebius printf(" CLOCK HOLD(2D)\n"); 677290000Sglebius if (mb(1) == 0x07) 678290000Sglebius printf(" OVERDETERMINED CLOCK\n"); 679290000Sglebius 680290000Sglebius printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2)); 681290000Sglebius if (mb(2) == 0x00) 682290000Sglebius printf(" NORMAL\n"); 683290000Sglebius if (mb(2) == 0x01) 684290000Sglebius printf(" POWER-UP\n"); 685290000Sglebius if (mb(2) == 0x02) 686290000Sglebius printf(" AUTO HOLDOVER\n"); 687290000Sglebius if (mb(2) == 0x03) 688290000Sglebius printf(" MANUAL HOLDOVER\n"); 689290000Sglebius if (mb(2) == 0x04) 690290000Sglebius printf(" RECOVERY\n"); 691290000Sglebius if (mb(2) == 0x06) 692290000Sglebius printf(" DISCIPLINING DISABLED\n"); 693290000Sglebius } 694290000Sglebius#endif 69554359Sroberto return 0; 69654359Sroberto break; 69754359Sroberto 698290000Sglebius case PACKET_8FAB: 699290000Sglebius /* Thunderbolt Primary Timing Packet */ 700290000Sglebius 701290000Sglebius if (up->rpt_cnt != LENCODE_8FAB) /* check length */ 702290000Sglebius break; 703290000Sglebius 704290000Sglebius if (up->polled <= 0) 705290000Sglebius return 0; 706290000Sglebius 707290000Sglebius GPS_UTC_Offset = getint((u_char *) &mb(7)); 708290000Sglebius 709290000Sglebius if (GPS_UTC_Offset == 0){ /* Check UTC Offset */ 710290000Sglebius#ifdef DEBUG 711290000Sglebius printf("TSIP_decode: UTC Offset Unknown\n"); 712290000Sglebius#endif 713290000Sglebius break; 714290000Sglebius } 715290000Sglebius 716290000Sglebius 717290000Sglebius if ((mb(9) & 0x1d) == 0x0) { 718290000Sglebius /* if we know the GPS time and the UTC offset, 719290000Sglebius we expect UTC timing information !!! */ 720290000Sglebius 721290000Sglebius pp->leap = LEAP_NOTINSYNC; 722290000Sglebius refclock_report(peer, CEVNT_BADTIME); 723290000Sglebius up->polled = -1; 724290000Sglebius return 0; 725290000Sglebius } 726290000Sglebius 727290000Sglebius pp->nsec = 0; 728290000Sglebius#ifdef DEBUG 729290000Sglebius printf("\nTiming Flags are:\n"); 730290000Sglebius printf("Timing flag value is: 0x%X\n", mb(9)); 731290000Sglebius if ((mb(9) & 0x01) != 0) 732290000Sglebius printf (" Getting UTC time\n"); 73354359Sroberto else 734290000Sglebius printf (" Getting GPS time\n"); 735290000Sglebius if ((mb(9) & 0x02) != 0) 736290000Sglebius printf (" PPS is from UTC\n"); 737290000Sglebius else 738290000Sglebius printf (" PPS is from GPS\n"); 739290000Sglebius if ((mb(9) & 0x04) != 0) 740290000Sglebius printf (" Time is not Set\n"); 741290000Sglebius else 742290000Sglebius printf (" Time is Set\n"); 743290000Sglebius if ((mb(9) & 0x08) != 0) 744290000Sglebius printf(" I dont have UTC info\n"); 745290000Sglebius else 746290000Sglebius printf (" I have UTC info\n"); 747290000Sglebius if ((mb(9) & 0x10) != 0) 748290000Sglebius printf (" Time is from USER\n\n"); 749290000Sglebius else 750290000Sglebius printf (" Time is from GPS\n\n"); 751290000Sglebius#endif 752290000Sglebius 753290000Sglebius if ((pp->day = day_of_year(&mb(13))) < 0) 754290000Sglebius break; 755290000Sglebius tow = getlong((u_char *) &mb(1)); 756290000Sglebius#ifdef DEBUG 757290000Sglebius if (debug > 1) { 758290000Sglebius printf("pp->day: %d\n", pp->day); 759290000Sglebius printf("TOW: %ld\n", tow); 760290000Sglebius printf("DAY: %d\n", mb(13)); 761290000Sglebius } 762290000Sglebius#endif 763290000Sglebius pp->year = getint((u_char *) &mb(15)); 764290000Sglebius pp->hour = mb(12); 765290000Sglebius pp->minute = mb(11); 766290000Sglebius pp->second = mb(10); 767290000Sglebius 768290000Sglebius 76954359Sroberto#ifdef DEBUG 770290000Sglebius if (debug > 1) 771290000Sglebius printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, pp->nsec, mb(14), mb(13), pp->year); 77254359Sroberto#endif 773290000Sglebius return 1; 774290000Sglebius break; 775290000Sglebius 776290000Sglebius default: 777290000Sglebius /* Ignore Packet */ 778290000Sglebius return 0; 779290000Sglebius } /* switch */ 780290000Sglebius } /* if 8F packets */ 781290000Sglebius 782290000Sglebius else if (up->rpt_buf[0] == (u_char)0x42) { 783290000Sglebius printf("0x42\n"); 784290000Sglebius return 0; 785290000Sglebius } 786290000Sglebius else if (up->rpt_buf[0] == (u_char)0x43) { 787290000Sglebius printf("0x43\n"); 788290000Sglebius return 0; 789290000Sglebius } 790290000Sglebius else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){ 791290000Sglebius printf("Undocumented 0x41 packet on Thunderbolt\n"); 792290000Sglebius return 0; 793290000Sglebius } 794290000Sglebius else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) { 795290000Sglebius#ifdef DEBUG 796290000Sglebius printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0))); 797290000Sglebius printf("GPS WN: %d\n", getint((u_char *) &mb(4))); 798290000Sglebius printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6))); 799290000Sglebius#endif 800290000Sglebius return 0; 801290000Sglebius } 802290000Sglebius 803290000Sglebius /* Health Status for Acutime Receiver */ 804290000Sglebius else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) { 805290000Sglebius#ifdef DEBUG 806290000Sglebius if (debug > 1) 807290000Sglebius /* Status Codes */ 808290000Sglebius switch (mb(0)) { 809290000Sglebius case 0x00: 810290000Sglebius printf ("Doing Position Fixes\n"); 811290000Sglebius break; 812290000Sglebius case 0x01: 813290000Sglebius printf ("Do no have GPS time yet\n"); 814290000Sglebius break; 815290000Sglebius case 0x03: 816290000Sglebius printf ("PDOP is too high\n"); 817290000Sglebius break; 818290000Sglebius case 0x08: 819290000Sglebius printf ("No usable satellites\n"); 820290000Sglebius break; 821290000Sglebius case 0x09: 822290000Sglebius printf ("Only 1 usable satellite\n"); 823290000Sglebius break; 824290000Sglebius case 0x0A: 825290000Sglebius printf ("Only 2 usable satellites\n"); 826290000Sglebius break; 827290000Sglebius case 0x0B: 828290000Sglebius printf ("Only 3 usable satellites\n"); 829290000Sglebius break; 830290000Sglebius case 0x0C: 831290000Sglebius printf("The Chosen satellite is unusable\n"); 832290000Sglebius break; 833290000Sglebius } 834290000Sglebius#endif 835290000Sglebius /* Error Codes */ 836290000Sglebius if (mb(1) != 0) { 837290000Sglebius 83854359Sroberto refclock_report(peer, CEVNT_BADTIME); 83954359Sroberto up->polled = -1; 840290000Sglebius#ifdef DEBUG 841290000Sglebius if (debug > 1) { 842290000Sglebius if (mb(1) & 0x01) 843290000Sglebius printf ("Signal Processor Error, reset unit.\n"); 844290000Sglebius if (mb(1) & 0x02) 845290000Sglebius printf ("Alignment error, channel or chip 1, reset unit.\n"); 846290000Sglebius if (mb(1) & 0x03) 847290000Sglebius printf ("Alignment error, channel or chip 2, reset unit.\n"); 848290000Sglebius if (mb(1) & 0x04) 849290000Sglebius printf ("Antenna feed line fault (open or short)\n"); 850290000Sglebius if (mb(1) & 0x05) 851290000Sglebius printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n"); 852290000Sglebius } 853290000Sglebius#endif 854290000Sglebius 855290000Sglebius return 0; 85654359Sroberto } 857290000Sglebius } 858290000Sglebius else if (up->rpt_buf[0] == 0x54) 859290000Sglebius return 0; 86054359Sroberto 861290000Sglebius else if (up->rpt_buf[0] == PACKET_6D) { 862290000Sglebius#ifdef DEBUG 863290000Sglebius int sats; 86454359Sroberto 865290000Sglebius if ((mb(0) & 0x01) && (mb(0) & 0x02)) 866290000Sglebius printf("2d Fix Dimension\n"); 867290000Sglebius if (mb(0) & 0x04) 868290000Sglebius printf("3d Fix Dimension\n"); 86954359Sroberto 870290000Sglebius if (mb(0) & 0x08) 871290000Sglebius printf("Fix Mode is MANUAL\n"); 872290000Sglebius else 873290000Sglebius printf("Fix Mode is AUTO\n"); 874290000Sglebius 875290000Sglebius sats = mb(0) & 0xF0; 876290000Sglebius sats = sats >> 4; 877290000Sglebius printf("Tracking %d Satellites\n", sats); 87854359Sroberto#endif 87954359Sroberto return 0; 880290000Sglebius } /* else if not super packet */ 88154359Sroberto refclock_report(peer, CEVNT_BADREPLY); 88254359Sroberto up->polled = -1; 88354359Sroberto#ifdef DEBUG 88454359Sroberto printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", 885290000Sglebius up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, 886290000Sglebius event, up->rpt_cnt); 88754359Sroberto#endif 88854359Sroberto return 0; 88954359Sroberto} 89054359Sroberto 89154359Sroberto/* 89254359Sroberto * palisade__receive - receive data from the serial interface 89354359Sroberto */ 89454359Sroberto 89554359Srobertostatic void 89654359Srobertopalisade_receive ( 89754359Sroberto struct peer * peer 89854359Sroberto ) 89954359Sroberto{ 90054359Sroberto struct palisade_unit *up; 90154359Sroberto struct refclockproc *pp; 90254359Sroberto 90354359Sroberto /* 90454359Sroberto * Initialize pointers and read the timecode and timestamp. 90554359Sroberto */ 90654359Sroberto pp = peer->procptr; 907290000Sglebius up = pp->unitptr; 90854359Sroberto 90954359Sroberto if (! TSIP_decode(peer)) return; 91054359Sroberto 91154359Sroberto if (up->polled <= 0) 912290000Sglebius return; /* no poll pending, already received or timeout */ 91354359Sroberto 91454359Sroberto up->polled = 0; /* Poll reply received */ 91554359Sroberto pp->lencode = 0; /* clear time code */ 91654359Sroberto#ifdef DEBUG 91754359Sroberto if (debug) 91854359Sroberto printf( 919290000Sglebius "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n", 92054359Sroberto up->unit, pp->year, pp->day, pp->hour, pp->minute, 921132451Sroberto pp->second, pp->nsec); 92254359Sroberto#endif 92354359Sroberto 92454359Sroberto /* 92554359Sroberto * Process the sample 92654359Sroberto * Generate timecode: YYYY DoY HH:MM:SS.microsec 92754359Sroberto * report and process 92854359Sroberto */ 92954359Sroberto 930290000Sglebius snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 931290000Sglebius "%4d %03d %02d:%02d:%02d.%09ld", 932290000Sglebius pp->year, pp->day, 933290000Sglebius pp->hour,pp->minute, pp->second, pp->nsec); 93454359Sroberto pp->lencode = 24; 93554359Sroberto 936290000Sglebius if (!refclock_process(pp)) { 93754359Sroberto refclock_report(peer, CEVNT_BADTIME); 93854359Sroberto 93954359Sroberto#ifdef DEBUG 94054359Sroberto printf("palisade_receive: unit %d: refclock_process failed!\n", 941290000Sglebius up->unit); 94254359Sroberto#endif 94354359Sroberto return; 94454359Sroberto } 94554359Sroberto 94654359Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 94754359Sroberto 94854359Sroberto#ifdef DEBUG 94954359Sroberto if (debug) 950290000Sglebius printf("palisade_receive: unit %d: %s\n", 951290000Sglebius up->unit, prettydate(&pp->lastrec)); 95254359Sroberto#endif 953132451Sroberto pp->lastref = pp->lastrec; 954290000Sglebius refclock_receive(peer); 95554359Sroberto} 95654359Sroberto 95754359Sroberto 95854359Sroberto/* 95954359Sroberto * palisade_poll - called by the transmit procedure 96054359Sroberto * 96154359Sroberto */ 96254359Srobertostatic void 96354359Srobertopalisade_poll ( 96454359Sroberto int unit, 96554359Sroberto struct peer *peer 96654359Sroberto ) 96754359Sroberto{ 96854359Sroberto struct palisade_unit *up; 96954359Sroberto struct refclockproc *pp; 97054359Sroberto 97154359Sroberto pp = peer->procptr; 972290000Sglebius up = pp->unitptr; 97354359Sroberto 97454359Sroberto pp->polls++; 97554359Sroberto if (up->polled > 0) /* last reply never arrived or error */ 976290000Sglebius refclock_report(peer, CEVNT_TIMEOUT); 97754359Sroberto 97854359Sroberto up->polled = 2; /* synchronous packet + 1 event */ 97954359Sroberto 98054359Sroberto#ifdef DEBUG 98154359Sroberto if (debug) 982290000Sglebius printf("palisade_poll: unit %d: polling %s\n", unit, 983290000Sglebius (pp->sloppyclockflag & CLK_FLAG2) ? 984290000Sglebius "synchronous packet" : "event"); 98554359Sroberto#endif 98654359Sroberto 98754359Sroberto if (pp->sloppyclockflag & CLK_FLAG2) 988290000Sglebius return; /* using synchronous packet input */ 98954359Sroberto 990132451Sroberto if(up->type == CLK_PRAECIS) { 991132451Sroberto if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) 992132451Sroberto msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); 993132451Sroberto else { 994132451Sroberto praecis_msg = 1; 995132451Sroberto return; 996132451Sroberto } 997132451Sroberto } 998132451Sroberto 99954359Sroberto if (HW_poll(pp) < 0) 1000290000Sglebius refclock_report(peer, CEVNT_FAULT); 100154359Sroberto} 100254359Sroberto 1003132451Srobertostatic void 1004290000Sglebiuspraecis_parse ( 1005290000Sglebius struct recvbuf *rbufp, 1006290000Sglebius struct peer *peer 1007290000Sglebius ) 1008132451Sroberto{ 1009132451Sroberto static char buf[100]; 1010132451Sroberto static int p = 0; 1011132451Sroberto struct refclockproc *pp; 101254359Sroberto 1013132451Sroberto pp = peer->procptr; 1014132451Sroberto 1015132451Sroberto memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); 1016132451Sroberto p += rbufp->recv_length; 1017132451Sroberto 1018132451Sroberto if(buf[p-2] == '\r' && buf[p-1] == '\n') { 1019132451Sroberto buf[p-2] = '\0'; 1020132451Sroberto record_clock_stats(&peer->srcadr, buf); 1021132451Sroberto 1022132451Sroberto p = 0; 1023132451Sroberto praecis_msg = 0; 1024132451Sroberto 1025132451Sroberto if (HW_poll(pp) < 0) 1026132451Sroberto refclock_report(peer, CEVNT_FAULT); 1027132451Sroberto 1028132451Sroberto } 1029132451Sroberto} 1030132451Sroberto 103154359Srobertostatic void 103254359Srobertopalisade_io ( 103354359Sroberto struct recvbuf *rbufp 103454359Sroberto ) 103554359Sroberto{ 103654359Sroberto /* 103754359Sroberto * Initialize pointers and read the timecode and timestamp. 103854359Sroberto */ 103954359Sroberto struct palisade_unit *up; 104054359Sroberto struct refclockproc *pp; 104154359Sroberto struct peer *peer; 104254359Sroberto 104354359Sroberto char * c, * d; 104454359Sroberto 1045290000Sglebius peer = rbufp->recv_peer; 104654359Sroberto pp = peer->procptr; 1047290000Sglebius up = pp->unitptr; 104854359Sroberto 1049132451Sroberto if(up->type == CLK_PRAECIS) { 1050132451Sroberto if(praecis_msg) { 1051132451Sroberto praecis_parse(rbufp,peer); 1052132451Sroberto return; 1053132451Sroberto } 1054132451Sroberto } 1055132451Sroberto 105654359Sroberto c = (char *) &rbufp->recv_space; 105754359Sroberto d = c + rbufp->recv_length; 105854359Sroberto 105954359Sroberto while (c != d) { 106054359Sroberto 106154359Sroberto /* Build time packet */ 106254359Sroberto switch (up->rpt_status) { 106354359Sroberto 106454359Sroberto case TSIP_PARSED_DLE_1: 106554359Sroberto switch (*c) 106654359Sroberto { 106754359Sroberto case 0: 106854359Sroberto case DLE: 106954359Sroberto case ETX: 107054359Sroberto up->rpt_status = TSIP_PARSED_EMPTY; 107154359Sroberto break; 107254359Sroberto 107354359Sroberto default: 107454359Sroberto up->rpt_status = TSIP_PARSED_DATA; 107554359Sroberto /* save packet ID */ 107654359Sroberto up->rpt_buf[0] = *c; 107754359Sroberto break; 107854359Sroberto } 107954359Sroberto break; 108054359Sroberto 108154359Sroberto case TSIP_PARSED_DATA: 108254359Sroberto if (*c == DLE) 1083290000Sglebius up->rpt_status = TSIP_PARSED_DLE_2; 108454359Sroberto else 1085290000Sglebius mb(up->rpt_cnt++) = *c; 108654359Sroberto break; 108754359Sroberto 108854359Sroberto case TSIP_PARSED_DLE_2: 108954359Sroberto if (*c == DLE) { 109054359Sroberto up->rpt_status = TSIP_PARSED_DATA; 109154359Sroberto mb(up->rpt_cnt++) = 1092290000Sglebius *c; 1093290000Sglebius } 109454359Sroberto else if (*c == ETX) 1095290000Sglebius up->rpt_status = TSIP_PARSED_FULL; 109654359Sroberto else { 1097290000Sglebius /* error: start new report packet */ 109854359Sroberto up->rpt_status = TSIP_PARSED_DLE_1; 109954359Sroberto up->rpt_buf[0] = *c; 110054359Sroberto } 110154359Sroberto break; 110254359Sroberto 110354359Sroberto case TSIP_PARSED_FULL: 110454359Sroberto case TSIP_PARSED_EMPTY: 110554359Sroberto default: 1106290000Sglebius if ( *c != DLE) 1107290000Sglebius up->rpt_status = TSIP_PARSED_EMPTY; 1108290000Sglebius else 1109290000Sglebius up->rpt_status = TSIP_PARSED_DLE_1; 1110290000Sglebius break; 111154359Sroberto } 111254359Sroberto 111354359Sroberto c++; 111454359Sroberto 111554359Sroberto if (up->rpt_status == TSIP_PARSED_DLE_1) { 1116290000Sglebius up->rpt_cnt = 0; 111754359Sroberto if (pp->sloppyclockflag & CLK_FLAG2) 1118290000Sglebius /* stamp it */ 1119290000Sglebius get_systime(&pp->lastrec); 112054359Sroberto } 112154359Sroberto else if (up->rpt_status == TSIP_PARSED_EMPTY) 1122290000Sglebius up->rpt_cnt = 0; 112354359Sroberto 112454359Sroberto else if (up->rpt_cnt > BMAX) 112554359Sroberto up->rpt_status =TSIP_PARSED_EMPTY; 112654359Sroberto 112754359Sroberto if (up->rpt_status == TSIP_PARSED_FULL) 112854359Sroberto palisade_receive(peer); 112954359Sroberto 113054359Sroberto } /* while chars in buffer */ 113154359Sroberto} 113254359Sroberto 113354359Sroberto 113454359Sroberto/* 113554359Sroberto * Trigger the Palisade's event input, which is driven off the RTS 113654359Sroberto * 113754359Sroberto * Take a system time stamp to match the GPS time stamp. 113854359Sroberto * 113954359Sroberto */ 114054359Srobertolong 114154359SrobertoHW_poll ( 114254359Sroberto struct refclockproc * pp /* pointer to unit structure */ 114354359Sroberto ) 114454359Sroberto{ 114554359Sroberto int x; /* state before & after RTS set */ 114654359Sroberto struct palisade_unit *up; 114754359Sroberto 1148290000Sglebius up = pp->unitptr; 114954359Sroberto 115054359Sroberto /* read the current status, so we put things back right */ 115154359Sroberto if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { 1152290000Sglebius DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n", 1153290000Sglebius up->unit)); 115454359Sroberto msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", 115554359Sroberto up->unit); 115654359Sroberto return -1; 115754359Sroberto } 115854359Sroberto 115954359Sroberto x |= TIOCM_RTS; /* turn on RTS */ 116054359Sroberto 116154359Sroberto /* Edge trigger */ 1162290000Sglebius if (up->type == CLK_ACUTIME) 1163290000Sglebius write (pp->io.fd, "", 1); 1164290000Sglebius 116554359Sroberto if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { 116654359Sroberto#ifdef DEBUG 1167290000Sglebius if (debug) 1168290000Sglebius printf("Palisade HW_poll: unit %d: SET \n", up->unit); 116954359Sroberto#endif 117054359Sroberto msyslog(LOG_ERR, 117154359Sroberto "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", 117254359Sroberto up->unit); 117354359Sroberto return -1; 117454359Sroberto } 117554359Sroberto 117654359Sroberto x &= ~TIOCM_RTS; /* turn off RTS */ 117754359Sroberto 117854359Sroberto /* poll timestamp */ 117954359Sroberto get_systime(&pp->lastrec); 118054359Sroberto 118154359Sroberto if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { 118254359Sroberto#ifdef DEBUG 1183290000Sglebius if (debug) 1184290000Sglebius printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); 118554359Sroberto#endif 118654359Sroberto msyslog(LOG_ERR, 118754359Sroberto "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", 118854359Sroberto up->unit); 118954359Sroberto return -1; 119054359Sroberto } 119154359Sroberto 119254359Sroberto return 0; 119354359Sroberto} 119454359Sroberto 119554359Sroberto/* 1196290000Sglebius * copy/swap a big-endian palisade double into a host double 119754359Sroberto */ 1198290000Sglebiusstatic double 1199290000Sglebiusgetdbl ( 120054359Sroberto u_char *bp 120154359Sroberto ) 120254359Sroberto{ 1203290000Sglebius#ifdef WORDS_BIGENDIAN 1204290000Sglebius double out; 1205290000Sglebius 1206290000Sglebius memcpy(&out, bp, sizeof(out)); 1207290000Sglebius return out; 120854359Sroberto#else 1209290000Sglebius union { 1210290000Sglebius u_char ch[8]; 1211290000Sglebius u_int32 u32[2]; 1212290000Sglebius } ui; 1213290000Sglebius 1214290000Sglebius union { 1215290000Sglebius double out; 1216290000Sglebius u_int32 u32[2]; 1217290000Sglebius } uo; 1218290000Sglebius 1219290000Sglebius memcpy(ui.ch, bp, sizeof(ui.ch)); 1220290000Sglebius /* least-significant 32 bits of double from swapped bp[4] to bp[7] */ 1221290000Sglebius uo.u32[0] = ntohl(ui.u32[1]); 1222290000Sglebius /* most-significant 32 bits from swapped bp[0] to bp[3] */ 1223290000Sglebius uo.u32[1] = ntohl(ui.u32[0]); 1224290000Sglebius 1225290000Sglebius return uo.out; 1226290000Sglebius#endif 122754359Sroberto} 122854359Sroberto 122954359Sroberto/* 1230290000Sglebius * copy/swap a big-endian palisade short into a host short 123154359Sroberto */ 1232290000Sglebiusstatic short 1233290000Sglebiusgetint ( 123454359Sroberto u_char *bp 123554359Sroberto ) 123654359Sroberto{ 1237290000Sglebius u_short us; 1238290000Sglebius 1239290000Sglebius memcpy(&us, bp, sizeof(us)); 1240290000Sglebius return (short)ntohs(us); 124154359Sroberto} 124254359Sroberto 124354359Sroberto/* 1244290000Sglebius * copy/swap a big-endian palisade 32-bit int into a host 32-bit int 124554359Sroberto */ 1246290000Sglebiusstatic int32 1247290000Sglebiusgetlong( 124854359Sroberto u_char *bp 124954359Sroberto ) 125054359Sroberto{ 1251290000Sglebius u_int32 u32; 1252290000Sglebius 1253290000Sglebius memcpy(&u32, bp, sizeof(u32)); 1254290000Sglebius return (int32)(u_int32)ntohl(u32); 125554359Sroberto} 125654359Sroberto 1257290000Sglebius#else /* REFCLOCK && CLOCK_PALISADE*/ 1258290000Sglebiusint refclock_palisade_c_notempty; 1259290000Sglebius#endif 1260