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 * 53285612Sdelphij * 54285612Sdelphij * 55285612Sdelphij * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock. 56285612Sdelphij * Contact: Fernando Pablo Hauscarriaga 57285612Sdelphij * E-mail: fernandoph@iar.unlp.edu.ar 58285612Sdelphij * Home page: www.iar.unlp.edu.ar/~fernandoph 59285612Sdelphij * Instituto Argentino de Radioastronomia 60285612Sdelphij * www.iar.unlp.edu.ar 61285612Sdelphij * 62285612Sdelphij * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed 63285612Sdelphij * now we use mode 2 for decode thunderbolt packets. 64285612Sdelphij * Fernando P. Hauscarriaga 65285612Sdelphij * 66285612Sdelphij * 30/08/09: Added support for Trimble Acutime Gold Receiver. 67285612Sdelphij * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar) 6854359Sroberto */ 6954359Sroberto 7054359Sroberto#ifdef HAVE_CONFIG_H 71285612Sdelphij# include "config.h" 7254359Sroberto#endif 7354359Sroberto 74285612Sdelphij#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 8454359Sroberto#ifdef DEBUG 8554359Srobertoconst char * Tracking_Status[15][15] = { 86285612Sdelphij { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" }, 87285612Sdelphij {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" }, 88285612Sdelphij { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" }, 89285612Sdelphij { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" }, 90285612Sdelphij { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } }; 9154359Sroberto#endif 9254359Sroberto 9354359Sroberto/* 9454359Sroberto * Transfer vector 9554359Sroberto */ 9654359Srobertostruct refclock refclock_palisade = { 9754359Sroberto palisade_start, /* start up driver */ 9854359Sroberto palisade_shutdown, /* shut down driver */ 9954359Sroberto palisade_poll, /* transmit poll message */ 10054359Sroberto noentry, /* not used */ 10154359Sroberto noentry, /* initialize driver (not used) */ 10254359Sroberto noentry, /* not used */ 10354359Sroberto NOFLAGS /* not used */ 10454359Sroberto}; 10554359Sroberto 106330141Sdelphijstatic int decode_date(struct refclockproc *pp, const char *cp); 10754359Sroberto 108132451Sroberto/* Extract the clock type from the mode setting */ 109132451Sroberto#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F)) 110132451Sroberto 111132451Sroberto/* Supported clock types */ 112132451Sroberto#define CLK_TRIMBLE 0 /* Trimble Palisade */ 113132451Sroberto#define CLK_PRAECIS 1 /* Endrun Technologies Praecis */ 114285612Sdelphij#define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */ 115285612Sdelphij#define CLK_ACUTIME 3 /* Trimble Acutime Gold */ 116285612Sdelphij#define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */ 117132451Sroberto 118132451Srobertoint praecis_msg; 119132451Srobertostatic void praecis_parse(struct recvbuf *rbufp, struct peer *peer); 120132451Sroberto 121285612Sdelphij/* These routines are for sending packets to the Thunderbolt receiver 122285612Sdelphij * They are taken from Markus Prosch 123285612Sdelphij */ 124285612Sdelphij 125285612Sdelphij#ifdef PALISADE_SENDCMD_RESURRECTED 12654359Sroberto/* 127285612Sdelphij * sendcmd - Build data packet for sending 128285612Sdelphij */ 129285612Sdelphijstatic void 130285612Sdelphijsendcmd ( 131285612Sdelphij struct packettx *buffer, 132285612Sdelphij int c 133285612Sdelphij ) 134285612Sdelphij{ 135285612Sdelphij *buffer->data = DLE; 136285612Sdelphij *(buffer->data + 1) = (unsigned char)c; 137285612Sdelphij buffer->size = 2; 138285612Sdelphij} 139285612Sdelphij#endif /* PALISADE_SENDCMD_RESURRECTED */ 140285612Sdelphij 141285612Sdelphij/* 142285612Sdelphij * sendsupercmd - Build super data packet for sending 143285612Sdelphij */ 144285612Sdelphijstatic void 145285612Sdelphijsendsupercmd ( 146285612Sdelphij struct packettx *buffer, 147285612Sdelphij int c1, 148285612Sdelphij int c2 149285612Sdelphij ) 150285612Sdelphij{ 151285612Sdelphij *buffer->data = DLE; 152285612Sdelphij *(buffer->data + 1) = (unsigned char)c1; 153285612Sdelphij *(buffer->data + 2) = (unsigned char)c2; 154285612Sdelphij buffer->size = 3; 155285612Sdelphij} 156285612Sdelphij 157285612Sdelphij/* 158285612Sdelphij * sendbyte - 159285612Sdelphij */ 160285612Sdelphijstatic void 161285612Sdelphijsendbyte ( 162285612Sdelphij struct packettx *buffer, 163285612Sdelphij int b 164285612Sdelphij ) 165285612Sdelphij{ 166285612Sdelphij if (b == DLE) 167285612Sdelphij *(buffer->data+buffer->size++) = DLE; 168285612Sdelphij *(buffer->data+buffer->size++) = (unsigned char)b; 169285612Sdelphij} 170285612Sdelphij 171285612Sdelphij/* 172285612Sdelphij * sendint - 173285612Sdelphij */ 174285612Sdelphijstatic void 175285612Sdelphijsendint ( 176285612Sdelphij struct packettx *buffer, 177285612Sdelphij int a 178285612Sdelphij ) 179285612Sdelphij{ 180285612Sdelphij sendbyte(buffer, (unsigned char)((a>>8) & 0xff)); 181285612Sdelphij sendbyte(buffer, (unsigned char)(a & 0xff)); 182285612Sdelphij} 183285612Sdelphij 184285612Sdelphij/* 185285612Sdelphij * sendetx - Send packet or super packet to the device 186285612Sdelphij */ 187285612Sdelphijstatic int 188285612Sdelphijsendetx ( 189285612Sdelphij struct packettx *buffer, 190285612Sdelphij int fd 191285612Sdelphij ) 192285612Sdelphij{ 193285612Sdelphij int result; 194285612Sdelphij 195285612Sdelphij *(buffer->data+buffer->size++) = DLE; 196285612Sdelphij *(buffer->data+buffer->size++) = ETX; 197285612Sdelphij result = write(fd, buffer->data, (unsigned long)buffer->size); 198285612Sdelphij 199285612Sdelphij if (result != -1) 200285612Sdelphij return (result); 201285612Sdelphij else 202285612Sdelphij return (-1); 203285612Sdelphij} 204285612Sdelphij 205285612Sdelphij/* 206285612Sdelphij * init_thunderbolt - Prepares Thunderbolt receiver to be used with 207285612Sdelphij * NTP (also taken from Markus Prosch). 208285612Sdelphij */ 209285612Sdelphijstatic void 210285612Sdelphijinit_thunderbolt ( 211285612Sdelphij int fd 212285612Sdelphij ) 213285612Sdelphij{ 214285612Sdelphij struct packettx tx; 215285612Sdelphij 216285612Sdelphij tx.size = 0; 217289997Sglebius tx.data = (u_char *) emalloc(100); 218285612Sdelphij 219285612Sdelphij /* set UTC time */ 220285612Sdelphij sendsupercmd (&tx, 0x8E, 0xA2); 221285612Sdelphij sendbyte (&tx, 0x3); 222285612Sdelphij sendetx (&tx, fd); 223285612Sdelphij 224285612Sdelphij /* activate packets 0x8F-AB and 0x8F-AC */ 225330141Sdelphij sendsupercmd (&tx, 0x8E, 0xA5); 226285612Sdelphij sendint (&tx, 0x5); 227285612Sdelphij sendetx (&tx, fd); 228285612Sdelphij 229285612Sdelphij free(tx.data); 230285612Sdelphij} 231285612Sdelphij 232285612Sdelphij/* 233285612Sdelphij * init_acutime - Prepares Acutime Receiver to be used with NTP 234285612Sdelphij */ 235285612Sdelphijstatic void 236285612Sdelphijinit_acutime ( 237285612Sdelphij int fd 238285612Sdelphij ) 239285612Sdelphij{ 240285612Sdelphij /* Disable all outputs, Enable Event-Polling on PortA so 241285612Sdelphij we can ask for time packets */ 242285612Sdelphij struct packettx tx; 243285612Sdelphij 244285612Sdelphij tx.size = 0; 245289997Sglebius tx.data = (u_char *) emalloc(100); 246285612Sdelphij 247285612Sdelphij sendsupercmd(&tx, 0x8E, 0xA5); 248285612Sdelphij sendbyte(&tx, 0x02); 249285612Sdelphij sendbyte(&tx, 0x00); 250285612Sdelphij sendbyte(&tx, 0x00); 251285612Sdelphij sendbyte(&tx, 0x00); 252285612Sdelphij sendetx(&tx, fd); 253285612Sdelphij 254285612Sdelphij free(tx.data); 255285612Sdelphij} 256285612Sdelphij 257285612Sdelphij/* 25854359Sroberto * palisade_start - open the devices and initialize data for processing 25954359Sroberto */ 26054359Srobertostatic int 26154359Srobertopalisade_start ( 26254359Sroberto int unit, 26354359Sroberto struct peer *peer 26454359Sroberto ) 26554359Sroberto{ 26654359Sroberto struct palisade_unit *up; 26754359Sroberto struct refclockproc *pp; 26854359Sroberto int fd; 26954359Sroberto char gpsdev[20]; 270285612Sdelphij struct termios tio; 27154359Sroberto 272285612Sdelphij snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 273285612Sdelphij 27454359Sroberto /* 27554359Sroberto * Open serial port. 27654359Sroberto */ 27754359Sroberto fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 27854359Sroberto if (fd <= 0) { 27954359Sroberto#ifdef DEBUG 28054359Sroberto printf("Palisade(%d) start: open %s failed\n", unit, gpsdev); 28154359Sroberto#endif 28254359Sroberto return 0; 28354359Sroberto } 28454359Sroberto 28554359Sroberto msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd, 28654359Sroberto gpsdev); 28754359Sroberto 288285612Sdelphij if (tcgetattr(fd, &tio) < 0) { 289285612Sdelphij msyslog(LOG_ERR, 29054359Sroberto "Palisade(%d) tcgetattr(fd, &tio): %m",unit); 29154359Sroberto#ifdef DEBUG 292285612Sdelphij printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit); 29354359Sroberto#endif 294285612Sdelphij close(fd); 295285612Sdelphij return (0); 296285612Sdelphij } 29754359Sroberto 298285612Sdelphij tio.c_cflag |= (PARENB|PARODD); 299285612Sdelphij tio.c_iflag &= ~ICRNL; 30054359Sroberto 30154359Sroberto /* 30254359Sroberto * Allocate and initialize unit structure 30354359Sroberto */ 304285612Sdelphij up = emalloc_zero(sizeof(*up)); 30554359Sroberto 306132451Sroberto up->type = CLK_TYPE(peer); 307132451Sroberto switch (up->type) { 308285612Sdelphij case CLK_TRIMBLE: 309285612Sdelphij /* Normal mode, do nothing */ 310285612Sdelphij break; 311285612Sdelphij case CLK_PRAECIS: 312285612Sdelphij msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled" 313285612Sdelphij ,unit); 314285612Sdelphij break; 315285612Sdelphij case CLK_THUNDERBOLT: 316285612Sdelphij msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled" 317285612Sdelphij ,unit); 318285612Sdelphij tio.c_cflag = (CS8|CLOCAL|CREAD); 319285612Sdelphij break; 320285612Sdelphij case CLK_ACUTIME: 321285612Sdelphij msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled" 322285612Sdelphij ,unit); 323285612Sdelphij break; 324285612Sdelphij default: 325285612Sdelphij msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit); 326285612Sdelphij break; 327132451Sroberto } 328285612Sdelphij if (tcsetattr(fd, TCSANOW, &tio) == -1) { 329285612Sdelphij msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); 330285612Sdelphij#ifdef DEBUG 331285612Sdelphij printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit); 332285612Sdelphij#endif 333285612Sdelphij close(fd); 334285612Sdelphij free(up); 335285612Sdelphij return 0; 336285612Sdelphij } 337132451Sroberto 33854359Sroberto pp = peer->procptr; 33954359Sroberto pp->io.clock_recv = palisade_io; 340285612Sdelphij pp->io.srcclock = peer; 34154359Sroberto pp->io.datalen = 0; 34254359Sroberto pp->io.fd = fd; 34354359Sroberto if (!io_addclock(&pp->io)) { 34454359Sroberto#ifdef DEBUG 345285612Sdelphij printf("Palisade(%d) io_addclock\n",unit); 34654359Sroberto#endif 347285612Sdelphij close(fd); 348285612Sdelphij pp->io.fd = -1; 34954359Sroberto free(up); 35054359Sroberto return (0); 35154359Sroberto } 35254359Sroberto 35354359Sroberto /* 35454359Sroberto * Initialize miscellaneous variables 35554359Sroberto */ 356285612Sdelphij pp->unitptr = up; 35754359Sroberto pp->clockdesc = DESCRIPTION; 35854359Sroberto 35954359Sroberto peer->precision = PRECISION; 36054359Sroberto peer->sstclktype = CTL_SST_TS_UHF; 36154359Sroberto peer->minpoll = TRMB_MINPOLL; 36254359Sroberto peer->maxpoll = TRMB_MAXPOLL; 36354359Sroberto memcpy((char *)&pp->refid, REFID, 4); 36454359Sroberto 36554359Sroberto up->leap_status = 0; 36654359Sroberto up->unit = (short) unit; 36754359Sroberto up->rpt_status = TSIP_PARSED_EMPTY; 368285612Sdelphij up->rpt_cnt = 0; 36954359Sroberto 370285612Sdelphij if (up->type == CLK_THUNDERBOLT) 371285612Sdelphij init_thunderbolt(fd); 372285612Sdelphij if (up->type == CLK_ACUTIME) 373285612Sdelphij init_acutime(fd); 374285612Sdelphij 37554359Sroberto return 1; 37654359Sroberto} 37754359Sroberto 37854359Sroberto 37954359Sroberto/* 38054359Sroberto * palisade_shutdown - shut down the clock 38154359Sroberto */ 38254359Srobertostatic void 38354359Srobertopalisade_shutdown ( 38454359Sroberto int unit, 38554359Sroberto struct peer *peer 38654359Sroberto ) 38754359Sroberto{ 38854359Sroberto struct palisade_unit *up; 38954359Sroberto struct refclockproc *pp; 39054359Sroberto pp = peer->procptr; 391285612Sdelphij up = pp->unitptr; 392285612Sdelphij if (-1 != pp->io.fd) 393285612Sdelphij io_closeclock(&pp->io); 394285612Sdelphij if (NULL != up) 395285612Sdelphij free(up); 39654359Sroberto} 39754359Sroberto 39854359Sroberto 39954359Sroberto/* 400330141Sdelphij * unpack helpers 40154359Sroberto */ 402330141Sdelphij 403330141Sdelphijstatic inline uint8_t 404330141Sdelphijget_u8( 405330141Sdelphij const char *cp) 406330141Sdelphij{ 407330141Sdelphij return ((const u_char*)cp)[0]; 408330141Sdelphij} 409330141Sdelphij 410330141Sdelphijstatic inline uint16_t 411330141Sdelphijget_u16( 412330141Sdelphij const char *cp) 413330141Sdelphij{ 414330141Sdelphij return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1); 415330141Sdelphij} 416330141Sdelphij 417330141Sdelphij/* 418330141Sdelphij * unpack & fix date (the receiver provides a valid time for 1024 weeks 419330141Sdelphij * after 1997-12-14 and therefore folds back in 2017, 2037,...) 420330141Sdelphij * 421330141Sdelphij * Returns -1 on error, day-of-month + (month * 32) othertwise. 422330141Sdelphij */ 42354359Srobertoint 424330141Sdelphijdecode_date( 425330141Sdelphij struct refclockproc *pp, 426330141Sdelphij const char *cp) 42754359Sroberto{ 428330141Sdelphij static int32_t s_baseday = 0; 429330141Sdelphij 430330141Sdelphij struct calendar jd; 431330141Sdelphij int32_t rd; 43254359Sroberto 433330141Sdelphij if (0 == s_baseday) { 434330141Sdelphij if (!ntpcal_get_build_date(&jd)) { 435330141Sdelphij jd.year = 2015; 436330141Sdelphij jd.month = 1; 437330141Sdelphij jd.monthday = 1; 438330141Sdelphij } 439330141Sdelphij s_baseday = ntpcal_date_to_rd(&jd); 440330141Sdelphij } 44154359Sroberto 442330141Sdelphij /* get date fields and convert to RDN */ 443330141Sdelphij jd.monthday = get_u8 ( cp ); 444330141Sdelphij jd.month = get_u8 (cp + 1); 445330141Sdelphij jd.year = get_u16(cp + 2); 446330141Sdelphij rd = ntpcal_date_to_rd(&jd); 44754359Sroberto 448330141Sdelphij /* for the paranoid: do reverse calculation and cross-check */ 449330141Sdelphij ntpcal_rd_to_date(&jd, rd); 450330141Sdelphij if ((jd.monthday != get_u8 ( cp )) || 451330141Sdelphij (jd.month != get_u8 (cp + 1)) || 452330141Sdelphij (jd.year != get_u16(cp + 2)) ) 453330141Sdelphij return - 1; 454330141Sdelphij 455330141Sdelphij /* calculate cycle shift to base day and calculate re-folded 456330141Sdelphij * date 457330141Sdelphij * 458330141Sdelphij * One could do a proper modulo calculation here, but a counting 459330141Sdelphij * loop is probably faster for the next few rollovers... 460330141Sdelphij */ 461330141Sdelphij while (rd < s_baseday) 462330141Sdelphij rd += 7*1024; 463330141Sdelphij ntpcal_rd_to_date(&jd, rd); 46454359Sroberto 465330141Sdelphij /* fill refclock structure & indicate success */ 466330141Sdelphij pp->day = jd.yearday; 467330141Sdelphij pp->year = jd.year; 468330141Sdelphij return ((int)jd.month << 5) | jd.monthday; 46954359Sroberto} 470330141Sdelphij 47154359Sroberto 47254359Sroberto/* 47354359Sroberto * TSIP_decode - decode the TSIP data packets 47454359Sroberto */ 47554359Srobertoint 47654359SrobertoTSIP_decode ( 47754359Sroberto struct peer *peer 47854359Sroberto ) 47954359Sroberto{ 48054359Sroberto int st; 48154359Sroberto long secint; 48254359Sroberto double secs; 48354359Sroberto double secfrac; 48454359Sroberto unsigned short event = 0; 485330141Sdelphij int mmday; 486330141Sdelphij 48754359Sroberto struct palisade_unit *up; 48854359Sroberto struct refclockproc *pp; 48954359Sroberto 49054359Sroberto pp = peer->procptr; 491285612Sdelphij up = pp->unitptr; 49254359Sroberto 49354359Sroberto /* 49454359Sroberto * Check the time packet, decode its contents. 49554359Sroberto * If the timecode has invalid length or is not in 49654359Sroberto * proper format, declare bad format and exit. 49754359Sroberto */ 49854359Sroberto 499285612Sdelphij if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){ 500285612Sdelphij if ((up->rpt_buf[0] == (char) 0x41) || 501285612Sdelphij (up->rpt_buf[0] == (char) 0x46) || 502285612Sdelphij (up->rpt_buf[0] == (char) 0x54) || 503285612Sdelphij (up->rpt_buf[0] == (char) 0x4B) || 504285612Sdelphij (up->rpt_buf[0] == (char) 0x6D)) { 50554359Sroberto 506285612Sdelphij /* standard time packet - GPS time and GPS week number */ 50754359Sroberto#ifdef DEBUG 50854359Sroberto printf("Palisade Port B packets detected. Connect to Port A\n"); 50954359Sroberto#endif 51054359Sroberto 511285612Sdelphij return 0; 512285612Sdelphij } 51354359Sroberto } 51454359Sroberto 515132451Sroberto /* 516132451Sroberto * We cast both to u_char to as 0x8f uses the sign bit on a char 517132451Sroberto */ 518132451Sroberto if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) { 519285612Sdelphij /* 520285612Sdelphij * Superpackets 521285612Sdelphij */ 522285612Sdelphij event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff); 523285612Sdelphij if (!((pp->sloppyclockflag & CLK_FLAG2) || event)) 524285612Sdelphij /* Ignore Packet */ 52554359Sroberto return 0; 52654359Sroberto 527285612Sdelphij switch (mb(0) & 0xff) { 528285612Sdelphij int GPS_UTC_Offset; 529285612Sdelphij long tow; 53054359Sroberto 531285612Sdelphij case PACKET_8F0B: 53254359Sroberto 533285612Sdelphij if (up->polled <= 0) 534285612Sdelphij return 0; 535285612Sdelphij 536285612Sdelphij if (up->rpt_cnt != LENCODE_8F0B) /* check length */ 537285612Sdelphij break; 53854359Sroberto 53954359Sroberto#ifdef DEBUG 540285612Sdelphij if (debug > 1) { 541285612Sdelphij int ts; 542285612Sdelphij double lat, lon, alt; 543285612Sdelphij lat = getdbl((u_char *) &mb(42)) * R2D; 544285612Sdelphij lon = getdbl((u_char *) &mb(50)) * R2D; 545285612Sdelphij alt = getdbl((u_char *) &mb(58)); 54654359Sroberto 547285612Sdelphij printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 548285612Sdelphij up->unit, lat,lon,alt); 549285612Sdelphij printf("TSIP_decode: unit %d: Sats:", 550285612Sdelphij up->unit); 551285612Sdelphij for (st = 66, ts = 0; st <= 73; st++) 552285612Sdelphij if (mb(st)) { 553285612Sdelphij if (mb(st) > 0) ts++; 554285612Sdelphij printf(" %02d", mb(st)); 555285612Sdelphij } 556285612Sdelphij printf(" : Tracking %d\n", ts); 557285612Sdelphij } 55854359Sroberto#endif 55954359Sroberto 560285612Sdelphij GPS_UTC_Offset = getint((u_char *) &mb(16)); 561285612Sdelphij if (GPS_UTC_Offset == 0) { /* Check UTC offset */ 56254359Sroberto#ifdef DEBUG 563285612Sdelphij printf("TSIP_decode: UTC Offset Unknown\n"); 56454359Sroberto#endif 565285612Sdelphij break; 566285612Sdelphij } 56754359Sroberto 568285612Sdelphij secs = getdbl((u_char *) &mb(3)); 569285612Sdelphij secint = (long) secs; 570285612Sdelphij secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ 57154359Sroberto 572285612Sdelphij pp->nsec = (long) (secfrac * 1000000000); 57354359Sroberto 574285612Sdelphij secint %= 86400; /* Only care about today */ 575285612Sdelphij pp->hour = secint / 3600; 576285612Sdelphij secint %= 3600; 577285612Sdelphij pp->minute = secint / 60; 578285612Sdelphij secint %= 60; 579285612Sdelphij pp->second = secint % 60; 58054359Sroberto 581330141Sdelphij mmday = decode_date(pp, &mb(11)); 582330141Sdelphij if (mmday < 0) 583330141Sdelphij break; 58454359Sroberto 58554359Sroberto#ifdef DEBUG 586285612Sdelphij if (debug > 1) 587285612Sdelphij printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n", 588285612Sdelphij up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 589330141Sdelphij pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset); 59054359Sroberto#endif 591285612Sdelphij /* Only use this packet when no 592285612Sdelphij * 8F-AD's are being received 593285612Sdelphij */ 59454359Sroberto 595285612Sdelphij if (up->leap_status) { 596285612Sdelphij up->leap_status = 0; 597285612Sdelphij return 0; 598285612Sdelphij } 59954359Sroberto 600285612Sdelphij return 2; 601285612Sdelphij break; 60254359Sroberto 603285612Sdelphij case PACKET_NTP: 604285612Sdelphij /* Palisade-NTP Packet */ 60554359Sroberto 606285612Sdelphij if (up->rpt_cnt != LENCODE_NTP) /* check length */ 607285612Sdelphij break; 60854359Sroberto 609285612Sdelphij up->leap_status = mb(19); 61054359Sroberto 611285612Sdelphij if (up->polled <= 0) 612285612Sdelphij return 0; 61354359Sroberto 614285612Sdelphij /* Check Tracking Status */ 615285612Sdelphij st = mb(18); 616285612Sdelphij if (st < 0 || st > 14) 617285612Sdelphij st = 14; 618285612Sdelphij if ((st >= 2 && st <= 7) || st == 11 || st == 12) { 61954359Sroberto#ifdef DEBUG 620285612Sdelphij printf("TSIP_decode: Not Tracking Sats : %s\n", 621285612Sdelphij *Tracking_Status[st]); 62254359Sroberto#endif 623285612Sdelphij refclock_report(peer, CEVNT_BADTIME); 624285612Sdelphij up->polled = -1; 625285612Sdelphij return 0; 626285612Sdelphij break; 627285612Sdelphij } 628285612Sdelphij 629330141Sdelphij mmday = decode_date(pp, &mb(14)); 630330141Sdelphij if (mmday < 0) 631330141Sdelphij break; 632330141Sdelphij up->month = (mmday >> 5); /* Save for LEAP check */ 633330141Sdelphij 634285612Sdelphij if ( (up->leap_status & PALISADE_LEAP_PENDING) && 635285612Sdelphij /* Avoid early announce: https://bugs.ntp.org/2773 */ 636285612Sdelphij (6 == up->month || 12 == up->month) ) { 637285612Sdelphij if (up->leap_status & PALISADE_UTC_TIME) 638285612Sdelphij pp->leap = LEAP_ADDSECOND; 639285612Sdelphij else 640285612Sdelphij pp->leap = LEAP_DELSECOND; 641285612Sdelphij } 642285612Sdelphij else if (up->leap_status) 643285612Sdelphij pp->leap = LEAP_NOWARNING; 644285612Sdelphij 645285612Sdelphij else { /* UTC flag is not set: 646285612Sdelphij * Receiver may have been reset, and lost 647285612Sdelphij * its UTC almanac data */ 648285612Sdelphij pp->leap = LEAP_NOTINSYNC; 649285612Sdelphij#ifdef DEBUG 650285612Sdelphij printf("TSIP_decode: UTC Almanac unavailable: %d\n", 651285612Sdelphij mb(19)); 652285612Sdelphij#endif 653285612Sdelphij refclock_report(peer, CEVNT_BADTIME); 654285612Sdelphij up->polled = -1; 655285612Sdelphij return 0; 656285612Sdelphij } 657285612Sdelphij 658285612Sdelphij pp->nsec = (long) (getdbl((u_char *) &mb(3)) 659285612Sdelphij * 1000000000); 660285612Sdelphij 661285612Sdelphij pp->hour = mb(11); 662285612Sdelphij pp->minute = mb(12); 663285612Sdelphij pp->second = mb(13); 664285612Sdelphij 665285612Sdelphij#ifdef DEBUG 666285612Sdelphij if (debug > 1) 667285612Sdelphij printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n", 668285612Sdelphij up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 669330141Sdelphij pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, 670285612Sdelphij mb(19), *Tracking_Status[st]); 671285612Sdelphij#endif 672285612Sdelphij return 1; 673285612Sdelphij break; 674285612Sdelphij 675285612Sdelphij case PACKET_8FAC: 676285612Sdelphij if (up->polled <= 0) 677285612Sdelphij return 0; 678285612Sdelphij 679285612Sdelphij if (up->rpt_cnt != LENCODE_8FAC)/* check length */ 680285612Sdelphij break; 681285612Sdelphij 682285612Sdelphij#ifdef DEBUG 683285612Sdelphij if (debug > 1) { 684285612Sdelphij double lat, lon, alt; 685285612Sdelphij lat = getdbl((u_char *) &mb(36)) * R2D; 686285612Sdelphij lon = getdbl((u_char *) &mb(44)) * R2D; 687285612Sdelphij alt = getdbl((u_char *) &mb(52)); 688285612Sdelphij 689285612Sdelphij printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 690285612Sdelphij up->unit, lat,lon,alt); 691285612Sdelphij printf("TSIP_decode: unit %d\n", up->unit); 692285612Sdelphij } 693285612Sdelphij#endif 694285612Sdelphij if ( (getint((u_char *) &mb(10)) & 0x80) && 695285612Sdelphij /* Avoid early announce: https://bugs.ntp.org/2773 */ 696285612Sdelphij (6 == up->month || 12 == up->month) ) 697285612Sdelphij pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */ 698285612Sdelphij else 699285612Sdelphij pp->leap = LEAP_NOWARNING; 700285612Sdelphij 701285612Sdelphij#ifdef DEBUG 702285612Sdelphij if (debug > 1) 703285612Sdelphij printf("TSIP_decode: unit %d: 0x%02x leap %d\n", 704285612Sdelphij up->unit, mb(0) & 0xff, pp->leap); 705285612Sdelphij if (debug > 1) { 706285612Sdelphij printf("Receiver MODE: 0x%02X\n", (u_char)mb(1)); 707285612Sdelphij if (mb(1) == 0x00) 708285612Sdelphij printf(" AUTOMATIC\n"); 709285612Sdelphij if (mb(1) == 0x01) 710285612Sdelphij printf(" SINGLE SATELLITE\n"); 711285612Sdelphij if (mb(1) == 0x03) 712285612Sdelphij printf(" HORIZONTAL(2D)\n"); 713285612Sdelphij if (mb(1) == 0x04) 714285612Sdelphij printf(" FULL POSITION(3D)\n"); 715285612Sdelphij if (mb(1) == 0x05) 716285612Sdelphij printf(" DGPR REFERENCE\n"); 717285612Sdelphij if (mb(1) == 0x06) 718285612Sdelphij printf(" CLOCK HOLD(2D)\n"); 719285612Sdelphij if (mb(1) == 0x07) 720285612Sdelphij printf(" OVERDETERMINED CLOCK\n"); 721285612Sdelphij 722285612Sdelphij printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2)); 723285612Sdelphij if (mb(2) == 0x00) 724285612Sdelphij printf(" NORMAL\n"); 725285612Sdelphij if (mb(2) == 0x01) 726285612Sdelphij printf(" POWER-UP\n"); 727285612Sdelphij if (mb(2) == 0x02) 728285612Sdelphij printf(" AUTO HOLDOVER\n"); 729285612Sdelphij if (mb(2) == 0x03) 730285612Sdelphij printf(" MANUAL HOLDOVER\n"); 731285612Sdelphij if (mb(2) == 0x04) 732285612Sdelphij printf(" RECOVERY\n"); 733285612Sdelphij if (mb(2) == 0x06) 734285612Sdelphij printf(" DISCIPLINING DISABLED\n"); 735285612Sdelphij } 736285612Sdelphij#endif 73754359Sroberto return 0; 73854359Sroberto break; 73954359Sroberto 740285612Sdelphij case PACKET_8FAB: 741285612Sdelphij /* Thunderbolt Primary Timing Packet */ 742285612Sdelphij 743285612Sdelphij if (up->rpt_cnt != LENCODE_8FAB) /* check length */ 744285612Sdelphij break; 745285612Sdelphij 746285612Sdelphij if (up->polled <= 0) 747285612Sdelphij return 0; 748285612Sdelphij 749285612Sdelphij GPS_UTC_Offset = getint((u_char *) &mb(7)); 750285612Sdelphij 751285612Sdelphij if (GPS_UTC_Offset == 0){ /* Check UTC Offset */ 752285612Sdelphij#ifdef DEBUG 753285612Sdelphij printf("TSIP_decode: UTC Offset Unknown\n"); 754285612Sdelphij#endif 755285612Sdelphij break; 756285612Sdelphij } 757285612Sdelphij 758285612Sdelphij 759285612Sdelphij if ((mb(9) & 0x1d) == 0x0) { 760285612Sdelphij /* if we know the GPS time and the UTC offset, 761285612Sdelphij we expect UTC timing information !!! */ 762285612Sdelphij 763285612Sdelphij pp->leap = LEAP_NOTINSYNC; 764285612Sdelphij refclock_report(peer, CEVNT_BADTIME); 765285612Sdelphij up->polled = -1; 766285612Sdelphij return 0; 767285612Sdelphij } 768285612Sdelphij 769285612Sdelphij pp->nsec = 0; 770285612Sdelphij#ifdef DEBUG 771285612Sdelphij printf("\nTiming Flags are:\n"); 772285612Sdelphij printf("Timing flag value is: 0x%X\n", mb(9)); 773285612Sdelphij if ((mb(9) & 0x01) != 0) 774285612Sdelphij printf (" Getting UTC time\n"); 77554359Sroberto else 776285612Sdelphij printf (" Getting GPS time\n"); 777285612Sdelphij if ((mb(9) & 0x02) != 0) 778285612Sdelphij printf (" PPS is from UTC\n"); 779285612Sdelphij else 780285612Sdelphij printf (" PPS is from GPS\n"); 781285612Sdelphij if ((mb(9) & 0x04) != 0) 782285612Sdelphij printf (" Time is not Set\n"); 783285612Sdelphij else 784285612Sdelphij printf (" Time is Set\n"); 785285612Sdelphij if ((mb(9) & 0x08) != 0) 786285612Sdelphij printf(" I dont have UTC info\n"); 787285612Sdelphij else 788285612Sdelphij printf (" I have UTC info\n"); 789285612Sdelphij if ((mb(9) & 0x10) != 0) 790285612Sdelphij printf (" Time is from USER\n\n"); 791285612Sdelphij else 792285612Sdelphij printf (" Time is from GPS\n\n"); 793285612Sdelphij#endif 794285612Sdelphij 795330141Sdelphij mmday = decode_date(pp, &mb(13)); 796330141Sdelphij if (mmday < 0) 797285612Sdelphij break; 798285612Sdelphij tow = getlong((u_char *) &mb(1)); 799285612Sdelphij#ifdef DEBUG 800285612Sdelphij if (debug > 1) { 801285612Sdelphij printf("pp->day: %d\n", pp->day); 802285612Sdelphij printf("TOW: %ld\n", tow); 803330141Sdelphij printf("DAY: %d\n", (mmday & 31)); 804285612Sdelphij } 805285612Sdelphij#endif 806285612Sdelphij pp->hour = mb(12); 807285612Sdelphij pp->minute = mb(11); 808285612Sdelphij pp->second = mb(10); 809285612Sdelphij 810285612Sdelphij 81154359Sroberto#ifdef DEBUG 812285612Sdelphij if (debug > 1) 813330141Sdelphij printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ", 814330141Sdelphij up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, 815330141Sdelphij pp->nsec, (mmday >> 5), (mmday & 31), pp->year); 81654359Sroberto#endif 817285612Sdelphij return 1; 818285612Sdelphij break; 819285612Sdelphij 820285612Sdelphij default: 821285612Sdelphij /* Ignore Packet */ 822285612Sdelphij return 0; 823285612Sdelphij } /* switch */ 824285612Sdelphij } /* if 8F packets */ 825285612Sdelphij 826285612Sdelphij else if (up->rpt_buf[0] == (u_char)0x42) { 827285612Sdelphij printf("0x42\n"); 828285612Sdelphij return 0; 829285612Sdelphij } 830285612Sdelphij else if (up->rpt_buf[0] == (u_char)0x43) { 831285612Sdelphij printf("0x43\n"); 832285612Sdelphij return 0; 833285612Sdelphij } 834285612Sdelphij else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){ 835285612Sdelphij printf("Undocumented 0x41 packet on Thunderbolt\n"); 836285612Sdelphij return 0; 837285612Sdelphij } 838285612Sdelphij else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) { 839285612Sdelphij#ifdef DEBUG 840285612Sdelphij printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0))); 841285612Sdelphij printf("GPS WN: %d\n", getint((u_char *) &mb(4))); 842285612Sdelphij printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6))); 843285612Sdelphij#endif 844285612Sdelphij return 0; 845285612Sdelphij } 846285612Sdelphij 847285612Sdelphij /* Health Status for Acutime Receiver */ 848285612Sdelphij else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) { 849285612Sdelphij#ifdef DEBUG 850285612Sdelphij if (debug > 1) 851285612Sdelphij /* Status Codes */ 852285612Sdelphij switch (mb(0)) { 853285612Sdelphij case 0x00: 854285612Sdelphij printf ("Doing Position Fixes\n"); 855285612Sdelphij break; 856285612Sdelphij case 0x01: 857285612Sdelphij printf ("Do no have GPS time yet\n"); 858285612Sdelphij break; 859285612Sdelphij case 0x03: 860285612Sdelphij printf ("PDOP is too high\n"); 861285612Sdelphij break; 862285612Sdelphij case 0x08: 863285612Sdelphij printf ("No usable satellites\n"); 864285612Sdelphij break; 865285612Sdelphij case 0x09: 866285612Sdelphij printf ("Only 1 usable satellite\n"); 867285612Sdelphij break; 868285612Sdelphij case 0x0A: 869285612Sdelphij printf ("Only 2 usable satellites\n"); 870285612Sdelphij break; 871285612Sdelphij case 0x0B: 872285612Sdelphij printf ("Only 3 usable satellites\n"); 873285612Sdelphij break; 874285612Sdelphij case 0x0C: 875285612Sdelphij printf("The Chosen satellite is unusable\n"); 876285612Sdelphij break; 877285612Sdelphij } 878285612Sdelphij#endif 879285612Sdelphij /* Error Codes */ 880285612Sdelphij if (mb(1) != 0) { 881285612Sdelphij 88254359Sroberto refclock_report(peer, CEVNT_BADTIME); 88354359Sroberto up->polled = -1; 884285612Sdelphij#ifdef DEBUG 885285612Sdelphij if (debug > 1) { 886285612Sdelphij if (mb(1) & 0x01) 887285612Sdelphij printf ("Signal Processor Error, reset unit.\n"); 888285612Sdelphij if (mb(1) & 0x02) 889285612Sdelphij printf ("Alignment error, channel or chip 1, reset unit.\n"); 890285612Sdelphij if (mb(1) & 0x03) 891285612Sdelphij printf ("Alignment error, channel or chip 2, reset unit.\n"); 892285612Sdelphij if (mb(1) & 0x04) 893285612Sdelphij printf ("Antenna feed line fault (open or short)\n"); 894285612Sdelphij if (mb(1) & 0x05) 895285612Sdelphij printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n"); 896285612Sdelphij } 897285612Sdelphij#endif 898285612Sdelphij 899285612Sdelphij return 0; 90054359Sroberto } 901285612Sdelphij } 902285612Sdelphij else if (up->rpt_buf[0] == 0x54) 903285612Sdelphij return 0; 90454359Sroberto 905285612Sdelphij else if (up->rpt_buf[0] == PACKET_6D) { 906285612Sdelphij#ifdef DEBUG 907285612Sdelphij int sats; 90854359Sroberto 909285612Sdelphij if ((mb(0) & 0x01) && (mb(0) & 0x02)) 910285612Sdelphij printf("2d Fix Dimension\n"); 911285612Sdelphij if (mb(0) & 0x04) 912285612Sdelphij printf("3d Fix Dimension\n"); 91354359Sroberto 914285612Sdelphij if (mb(0) & 0x08) 915285612Sdelphij printf("Fix Mode is MANUAL\n"); 916285612Sdelphij else 917285612Sdelphij printf("Fix Mode is AUTO\n"); 918285612Sdelphij 919285612Sdelphij sats = mb(0) & 0xF0; 920285612Sdelphij sats = sats >> 4; 921285612Sdelphij printf("Tracking %d Satellites\n", sats); 92254359Sroberto#endif 92354359Sroberto return 0; 924285612Sdelphij } /* else if not super packet */ 92554359Sroberto refclock_report(peer, CEVNT_BADREPLY); 92654359Sroberto up->polled = -1; 92754359Sroberto#ifdef DEBUG 92854359Sroberto printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", 929285612Sdelphij up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, 930285612Sdelphij event, up->rpt_cnt); 93154359Sroberto#endif 93254359Sroberto return 0; 93354359Sroberto} 93454359Sroberto 93554359Sroberto/* 93654359Sroberto * palisade__receive - receive data from the serial interface 93754359Sroberto */ 93854359Sroberto 93954359Srobertostatic void 94054359Srobertopalisade_receive ( 94154359Sroberto struct peer * peer 94254359Sroberto ) 94354359Sroberto{ 94454359Sroberto struct palisade_unit *up; 94554359Sroberto struct refclockproc *pp; 94654359Sroberto 94754359Sroberto /* 94854359Sroberto * Initialize pointers and read the timecode and timestamp. 94954359Sroberto */ 95054359Sroberto pp = peer->procptr; 951285612Sdelphij up = pp->unitptr; 95254359Sroberto 95354359Sroberto if (! TSIP_decode(peer)) return; 95454359Sroberto 95554359Sroberto if (up->polled <= 0) 956285612Sdelphij return; /* no poll pending, already received or timeout */ 95754359Sroberto 95854359Sroberto up->polled = 0; /* Poll reply received */ 95954359Sroberto pp->lencode = 0; /* clear time code */ 96054359Sroberto#ifdef DEBUG 96154359Sroberto if (debug) 96254359Sroberto printf( 963285612Sdelphij "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n", 96454359Sroberto up->unit, pp->year, pp->day, pp->hour, pp->minute, 965132451Sroberto pp->second, pp->nsec); 96654359Sroberto#endif 96754359Sroberto 96854359Sroberto /* 96954359Sroberto * Process the sample 97054359Sroberto * Generate timecode: YYYY DoY HH:MM:SS.microsec 97154359Sroberto * report and process 97254359Sroberto */ 97354359Sroberto 974285612Sdelphij snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 975285612Sdelphij "%4d %03d %02d:%02d:%02d.%09ld", 976285612Sdelphij pp->year, pp->day, 977285612Sdelphij pp->hour,pp->minute, pp->second, pp->nsec); 97854359Sroberto pp->lencode = 24; 97954359Sroberto 980285612Sdelphij if (!refclock_process(pp)) { 98154359Sroberto refclock_report(peer, CEVNT_BADTIME); 98254359Sroberto 98354359Sroberto#ifdef DEBUG 98454359Sroberto printf("palisade_receive: unit %d: refclock_process failed!\n", 985285612Sdelphij up->unit); 98654359Sroberto#endif 98754359Sroberto return; 98854359Sroberto } 98954359Sroberto 99054359Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 99154359Sroberto 99254359Sroberto#ifdef DEBUG 99354359Sroberto if (debug) 994285612Sdelphij printf("palisade_receive: unit %d: %s\n", 995285612Sdelphij up->unit, prettydate(&pp->lastrec)); 99654359Sroberto#endif 997132451Sroberto pp->lastref = pp->lastrec; 998285612Sdelphij refclock_receive(peer); 99954359Sroberto} 100054359Sroberto 100154359Sroberto 100254359Sroberto/* 100354359Sroberto * palisade_poll - called by the transmit procedure 100454359Sroberto * 100554359Sroberto */ 100654359Srobertostatic void 100754359Srobertopalisade_poll ( 100854359Sroberto int unit, 100954359Sroberto struct peer *peer 101054359Sroberto ) 101154359Sroberto{ 101254359Sroberto struct palisade_unit *up; 101354359Sroberto struct refclockproc *pp; 101454359Sroberto 101554359Sroberto pp = peer->procptr; 1016285612Sdelphij up = pp->unitptr; 101754359Sroberto 101854359Sroberto pp->polls++; 101954359Sroberto if (up->polled > 0) /* last reply never arrived or error */ 1020285612Sdelphij refclock_report(peer, CEVNT_TIMEOUT); 102154359Sroberto 102254359Sroberto up->polled = 2; /* synchronous packet + 1 event */ 102354359Sroberto 102454359Sroberto#ifdef DEBUG 102554359Sroberto if (debug) 1026285612Sdelphij printf("palisade_poll: unit %d: polling %s\n", unit, 1027285612Sdelphij (pp->sloppyclockflag & CLK_FLAG2) ? 1028285612Sdelphij "synchronous packet" : "event"); 102954359Sroberto#endif 103054359Sroberto 103154359Sroberto if (pp->sloppyclockflag & CLK_FLAG2) 1032285612Sdelphij return; /* using synchronous packet input */ 103354359Sroberto 1034132451Sroberto if(up->type == CLK_PRAECIS) { 1035132451Sroberto if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) 1036132451Sroberto msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); 1037132451Sroberto else { 1038132451Sroberto praecis_msg = 1; 1039132451Sroberto return; 1040132451Sroberto } 1041132451Sroberto } 1042132451Sroberto 104354359Sroberto if (HW_poll(pp) < 0) 1044285612Sdelphij refclock_report(peer, CEVNT_FAULT); 104554359Sroberto} 104654359Sroberto 1047132451Srobertostatic void 1048285612Sdelphijpraecis_parse ( 1049285612Sdelphij struct recvbuf *rbufp, 1050285612Sdelphij struct peer *peer 1051285612Sdelphij ) 1052132451Sroberto{ 1053132451Sroberto static char buf[100]; 1054132451Sroberto static int p = 0; 1055132451Sroberto struct refclockproc *pp; 105654359Sroberto 1057132451Sroberto pp = peer->procptr; 1058132451Sroberto 1059132451Sroberto memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); 1060132451Sroberto p += rbufp->recv_length; 1061132451Sroberto 1062132451Sroberto if(buf[p-2] == '\r' && buf[p-1] == '\n') { 1063132451Sroberto buf[p-2] = '\0'; 1064132451Sroberto record_clock_stats(&peer->srcadr, buf); 1065132451Sroberto 1066132451Sroberto p = 0; 1067132451Sroberto praecis_msg = 0; 1068132451Sroberto 1069132451Sroberto if (HW_poll(pp) < 0) 1070132451Sroberto refclock_report(peer, CEVNT_FAULT); 1071132451Sroberto 1072132451Sroberto } 1073132451Sroberto} 1074132451Sroberto 107554359Srobertostatic void 107654359Srobertopalisade_io ( 107754359Sroberto struct recvbuf *rbufp 107854359Sroberto ) 107954359Sroberto{ 108054359Sroberto /* 108154359Sroberto * Initialize pointers and read the timecode and timestamp. 108254359Sroberto */ 108354359Sroberto struct palisade_unit *up; 108454359Sroberto struct refclockproc *pp; 108554359Sroberto struct peer *peer; 108654359Sroberto 108754359Sroberto char * c, * d; 108854359Sroberto 1089285612Sdelphij peer = rbufp->recv_peer; 109054359Sroberto pp = peer->procptr; 1091285612Sdelphij up = pp->unitptr; 109254359Sroberto 1093132451Sroberto if(up->type == CLK_PRAECIS) { 1094132451Sroberto if(praecis_msg) { 1095132451Sroberto praecis_parse(rbufp,peer); 1096132451Sroberto return; 1097132451Sroberto } 1098132451Sroberto } 1099132451Sroberto 110054359Sroberto c = (char *) &rbufp->recv_space; 110154359Sroberto d = c + rbufp->recv_length; 110254359Sroberto 110354359Sroberto while (c != d) { 110454359Sroberto 110554359Sroberto /* Build time packet */ 110654359Sroberto switch (up->rpt_status) { 110754359Sroberto 110854359Sroberto case TSIP_PARSED_DLE_1: 110954359Sroberto switch (*c) 111054359Sroberto { 111154359Sroberto case 0: 111254359Sroberto case DLE: 111354359Sroberto case ETX: 111454359Sroberto up->rpt_status = TSIP_PARSED_EMPTY; 111554359Sroberto break; 111654359Sroberto 111754359Sroberto default: 111854359Sroberto up->rpt_status = TSIP_PARSED_DATA; 111954359Sroberto /* save packet ID */ 112054359Sroberto up->rpt_buf[0] = *c; 112154359Sroberto break; 112254359Sroberto } 112354359Sroberto break; 112454359Sroberto 112554359Sroberto case TSIP_PARSED_DATA: 112654359Sroberto if (*c == DLE) 1127285612Sdelphij up->rpt_status = TSIP_PARSED_DLE_2; 112854359Sroberto else 1129285612Sdelphij mb(up->rpt_cnt++) = *c; 113054359Sroberto break; 113154359Sroberto 113254359Sroberto case TSIP_PARSED_DLE_2: 113354359Sroberto if (*c == DLE) { 113454359Sroberto up->rpt_status = TSIP_PARSED_DATA; 113554359Sroberto mb(up->rpt_cnt++) = 1136285612Sdelphij *c; 1137285612Sdelphij } 113854359Sroberto else if (*c == ETX) 1139285612Sdelphij up->rpt_status = TSIP_PARSED_FULL; 114054359Sroberto else { 1141285612Sdelphij /* error: start new report packet */ 114254359Sroberto up->rpt_status = TSIP_PARSED_DLE_1; 114354359Sroberto up->rpt_buf[0] = *c; 114454359Sroberto } 114554359Sroberto break; 114654359Sroberto 114754359Sroberto case TSIP_PARSED_FULL: 114854359Sroberto case TSIP_PARSED_EMPTY: 114954359Sroberto default: 1150285612Sdelphij if ( *c != DLE) 1151285612Sdelphij up->rpt_status = TSIP_PARSED_EMPTY; 1152285612Sdelphij else 1153285612Sdelphij up->rpt_status = TSIP_PARSED_DLE_1; 1154285612Sdelphij break; 115554359Sroberto } 115654359Sroberto 115754359Sroberto c++; 115854359Sroberto 115954359Sroberto if (up->rpt_status == TSIP_PARSED_DLE_1) { 1160285612Sdelphij up->rpt_cnt = 0; 116154359Sroberto if (pp->sloppyclockflag & CLK_FLAG2) 1162285612Sdelphij /* stamp it */ 1163285612Sdelphij get_systime(&pp->lastrec); 116454359Sroberto } 116554359Sroberto else if (up->rpt_status == TSIP_PARSED_EMPTY) 1166285612Sdelphij up->rpt_cnt = 0; 116754359Sroberto 116854359Sroberto else if (up->rpt_cnt > BMAX) 116954359Sroberto up->rpt_status =TSIP_PARSED_EMPTY; 117054359Sroberto 117154359Sroberto if (up->rpt_status == TSIP_PARSED_FULL) 117254359Sroberto palisade_receive(peer); 117354359Sroberto 117454359Sroberto } /* while chars in buffer */ 117554359Sroberto} 117654359Sroberto 117754359Sroberto 117854359Sroberto/* 117954359Sroberto * Trigger the Palisade's event input, which is driven off the RTS 118054359Sroberto * 118154359Sroberto * Take a system time stamp to match the GPS time stamp. 118254359Sroberto * 118354359Sroberto */ 118454359Srobertolong 118554359SrobertoHW_poll ( 118654359Sroberto struct refclockproc * pp /* pointer to unit structure */ 118754359Sroberto ) 118854359Sroberto{ 118954359Sroberto int x; /* state before & after RTS set */ 119054359Sroberto struct palisade_unit *up; 119154359Sroberto 1192285612Sdelphij up = pp->unitptr; 119354359Sroberto 119454359Sroberto /* read the current status, so we put things back right */ 119554359Sroberto if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { 1196285612Sdelphij DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n", 1197285612Sdelphij up->unit)); 119854359Sroberto msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", 119954359Sroberto up->unit); 120054359Sroberto return -1; 120154359Sroberto } 120254359Sroberto 120354359Sroberto x |= TIOCM_RTS; /* turn on RTS */ 120454359Sroberto 120554359Sroberto /* Edge trigger */ 1206285612Sdelphij if (up->type == CLK_ACUTIME) 1207285612Sdelphij write (pp->io.fd, "", 1); 1208285612Sdelphij 120954359Sroberto if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { 121054359Sroberto#ifdef DEBUG 1211285612Sdelphij if (debug) 1212285612Sdelphij printf("Palisade HW_poll: unit %d: SET \n", up->unit); 121354359Sroberto#endif 121454359Sroberto msyslog(LOG_ERR, 121554359Sroberto "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", 121654359Sroberto up->unit); 121754359Sroberto return -1; 121854359Sroberto } 121954359Sroberto 122054359Sroberto x &= ~TIOCM_RTS; /* turn off RTS */ 122154359Sroberto 122254359Sroberto /* poll timestamp */ 122354359Sroberto get_systime(&pp->lastrec); 122454359Sroberto 122554359Sroberto if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { 122654359Sroberto#ifdef DEBUG 1227285612Sdelphij if (debug) 1228285612Sdelphij printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); 122954359Sroberto#endif 123054359Sroberto msyslog(LOG_ERR, 123154359Sroberto "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", 123254359Sroberto up->unit); 123354359Sroberto return -1; 123454359Sroberto } 123554359Sroberto 123654359Sroberto return 0; 123754359Sroberto} 123854359Sroberto 123954359Sroberto/* 1240285612Sdelphij * copy/swap a big-endian palisade double into a host double 124154359Sroberto */ 1242285612Sdelphijstatic double 1243285612Sdelphijgetdbl ( 124454359Sroberto u_char *bp 124554359Sroberto ) 124654359Sroberto{ 1247285612Sdelphij#ifdef WORDS_BIGENDIAN 1248285612Sdelphij double out; 1249285612Sdelphij 1250285612Sdelphij memcpy(&out, bp, sizeof(out)); 1251285612Sdelphij return out; 125254359Sroberto#else 1253285612Sdelphij union { 1254285612Sdelphij u_char ch[8]; 1255285612Sdelphij u_int32 u32[2]; 1256285612Sdelphij } ui; 1257285612Sdelphij 1258285612Sdelphij union { 1259285612Sdelphij double out; 1260285612Sdelphij u_int32 u32[2]; 1261285612Sdelphij } uo; 1262285612Sdelphij 1263285612Sdelphij memcpy(ui.ch, bp, sizeof(ui.ch)); 1264285612Sdelphij /* least-significant 32 bits of double from swapped bp[4] to bp[7] */ 1265285612Sdelphij uo.u32[0] = ntohl(ui.u32[1]); 1266285612Sdelphij /* most-significant 32 bits from swapped bp[0] to bp[3] */ 1267285612Sdelphij uo.u32[1] = ntohl(ui.u32[0]); 1268285612Sdelphij 1269285612Sdelphij return uo.out; 1270285612Sdelphij#endif 127154359Sroberto} 127254359Sroberto 127354359Sroberto/* 1274285612Sdelphij * copy/swap a big-endian palisade short into a host short 127554359Sroberto */ 1276285612Sdelphijstatic short 1277285612Sdelphijgetint ( 127854359Sroberto u_char *bp 127954359Sroberto ) 128054359Sroberto{ 1281285612Sdelphij u_short us; 1282285612Sdelphij 1283285612Sdelphij memcpy(&us, bp, sizeof(us)); 1284285612Sdelphij return (short)ntohs(us); 128554359Sroberto} 128654359Sroberto 128754359Sroberto/* 1288285612Sdelphij * copy/swap a big-endian palisade 32-bit int into a host 32-bit int 128954359Sroberto */ 1290285612Sdelphijstatic int32 1291285612Sdelphijgetlong( 129254359Sroberto u_char *bp 129354359Sroberto ) 129454359Sroberto{ 1295285612Sdelphij u_int32 u32; 1296285612Sdelphij 1297285612Sdelphij memcpy(&u32, bp, sizeof(u32)); 1298285612Sdelphij return (int32)(u_int32)ntohl(u32); 129954359Sroberto} 130054359Sroberto 1301285612Sdelphij#else /* REFCLOCK && CLOCK_PALISADE*/ 1302285612Sdelphijint refclock_palisade_c_notempty; 1303285612Sdelphij#endif 1304