/src/ntp-dev/ntpd/refclock_palisade.c
Line | Count | Source |
1 | | /* |
2 | | * This software was developed by the Software and Component Technologies |
3 | | * group of Trimble Navigation, Ltd. |
4 | | * |
5 | | * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd. |
6 | | * All rights reserved. |
7 | | * |
8 | | * Redistribution and use in source and binary forms, with or without |
9 | | * modification, are permitted provided that the following conditions |
10 | | * are met: |
11 | | * 1. Redistributions of source code must retain the above copyright |
12 | | * notice, this list of conditions and the following disclaimer. |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in the |
15 | | * documentation and/or other materials provided with the distribution. |
16 | | * 3. All advertising materials mentioning features or use of this software |
17 | | * must display the following acknowledgement: |
18 | | * This product includes software developed by Trimble Navigation, Ltd. |
19 | | * 4. The name of Trimble Navigation Ltd. may not be used to endorse or |
20 | | * promote products derived from this software without specific prior |
21 | | * written permission. |
22 | | * |
23 | | * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND |
24 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | | * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE |
27 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 | | * SUCH DAMAGE. |
34 | | */ |
35 | | |
36 | | /* |
37 | | * refclock_palisade - clock driver for the Trimble Palisade GPS |
38 | | * timing receiver |
39 | | * |
40 | | * For detailed information on this program, please refer to the html |
41 | | * Refclock 29 page accompanying the NTP distribution. |
42 | | * |
43 | | * for questions / bugs / comments, contact: |
44 | | * sven_dietrich@trimble.com |
45 | | * |
46 | | * Sven-Thorsten Dietrich |
47 | | * 645 North Mary Avenue |
48 | | * Post Office Box 3642 |
49 | | * Sunnyvale, CA 94088-3642 |
50 | | * |
51 | | * Version 2.45; July 14, 1999 |
52 | | * |
53 | | * |
54 | | * |
55 | | * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock. |
56 | | * Contact: Fernando Pablo Hauscarriaga |
57 | | * E-mail: fernandoph@iar.unlp.edu.ar |
58 | | * Home page: www.iar.unlp.edu.ar/~fernandoph |
59 | | * Instituto Argentino de Radioastronomia |
60 | | * www.iar.unlp.edu.ar |
61 | | * |
62 | | * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed |
63 | | * now we use mode 2 for decode thunderbolt packets. |
64 | | * Fernando P. Hauscarriaga |
65 | | * |
66 | | * 30/08/09: Added support for Trimble Acutime Gold Receiver. |
67 | | * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar) |
68 | | * |
69 | | * 21/04/18: Added support for Resolution devices. |
70 | | * |
71 | | * 03/09/19: Added support for ACE III & Copernicus II. |
72 | | */ |
73 | | |
74 | | #ifdef HAVE_CONFIG_H |
75 | | # include "config.h" |
76 | | #endif |
77 | | |
78 | | #if defined(REFCLOCK) && defined(CLOCK_PALISADE) |
79 | | |
80 | | #ifdef SYS_WINNT |
81 | | extern int async_write(int, const void *, unsigned int); |
82 | | #undef write |
83 | | #define write(fd, data, octets) async_write(fd, data, octets) |
84 | | #endif |
85 | | |
86 | | #include "refclock_palisade.h" |
87 | | |
88 | | #ifdef DEBUG |
89 | | const char * Tracking_Status[15][15] = { |
90 | | { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" }, |
91 | | {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" }, |
92 | | { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" }, |
93 | | { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" }, |
94 | | { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } }; |
95 | | #endif |
96 | | |
97 | | /* |
98 | | * Transfer vector |
99 | | */ |
100 | | struct refclock refclock_palisade = { |
101 | | palisade_start, /* start up driver */ |
102 | | palisade_shutdown, /* shut down driver */ |
103 | | palisade_poll, /* transmit poll message */ |
104 | | noentry, /* not used */ |
105 | | noentry, /* initialize driver (not used) */ |
106 | | noentry, /* not used */ |
107 | | NOFLAGS /* not used */ |
108 | | }; |
109 | | |
110 | | static int decode_date(struct refclockproc *pp, const char *cp); |
111 | | |
112 | | /* Extract the clock type from the mode setting */ |
113 | 0 | #define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F)) |
114 | | |
115 | | /* Supported clock types */ |
116 | 0 | #define CLK_TRIMBLE 0 /* Trimble Palisade */ |
117 | 0 | #define CLK_PRAECIS 1 /* Endrun Technologies Praecis */ |
118 | 0 | #define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */ |
119 | 0 | #define CLK_ACUTIME 3 /* Trimble Acutime Gold */ |
120 | | #define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */ |
121 | 0 | #define CLK_RESOLUTION 5 /* Trimble Resolution Receivers */ |
122 | 0 | #define CLK_ACE 6 /* Trimble ACE III */ |
123 | 0 | #define CLK_COPERNICUS 7 /* Trimble Copernicus II */ |
124 | | |
125 | | int praecis_msg; |
126 | | static void praecis_parse(struct recvbuf *rbufp, struct peer *peer); |
127 | | |
128 | | /* These routines are for sending packets to the Thunderbolt receiver |
129 | | * They are taken from Markus Prosch |
130 | | */ |
131 | | |
132 | | /* |
133 | | * sendcmd - Build data packet for sending |
134 | | */ |
135 | | static void |
136 | | sendcmd ( |
137 | | struct packettx *buffer, |
138 | | int c |
139 | | ) |
140 | 0 | { |
141 | 0 | *buffer->data = DLE; |
142 | 0 | *(buffer->data + 1) = (unsigned char)c; |
143 | 0 | buffer->size = 2; |
144 | 0 | } |
145 | | |
146 | | /* |
147 | | * sendsupercmd - Build super data packet for sending |
148 | | */ |
149 | | static void |
150 | | sendsupercmd ( |
151 | | struct packettx *buffer, |
152 | | int c1, |
153 | | int c2 |
154 | | ) |
155 | 0 | { |
156 | 0 | *buffer->data = DLE; |
157 | 0 | *(buffer->data + 1) = (unsigned char)c1; |
158 | 0 | *(buffer->data + 2) = (unsigned char)c2; |
159 | 0 | buffer->size = 3; |
160 | 0 | } |
161 | | |
162 | | /* |
163 | | * sendbyte - |
164 | | */ |
165 | | static void |
166 | | sendbyte ( |
167 | | struct packettx *buffer, |
168 | | int b |
169 | | ) |
170 | 0 | { |
171 | 0 | if (b == DLE) |
172 | 0 | *(buffer->data+buffer->size++) = DLE; |
173 | 0 | *(buffer->data+buffer->size++) = (unsigned char)b; |
174 | 0 | } |
175 | | |
176 | | /* |
177 | | * sendint - |
178 | | */ |
179 | | static void |
180 | | sendint ( |
181 | | struct packettx *buffer, |
182 | | int a |
183 | | ) |
184 | 0 | { |
185 | 0 | sendbyte(buffer, (unsigned char)((a>>8) & 0xff)); |
186 | 0 | sendbyte(buffer, (unsigned char)(a & 0xff)); |
187 | 0 | } |
188 | | |
189 | | /* |
190 | | * sendetx - Send packet or super packet to the device |
191 | | */ |
192 | | static int |
193 | | sendetx ( |
194 | | struct packettx *buffer, |
195 | | int fd |
196 | | ) |
197 | 0 | { |
198 | 0 | int result; |
199 | | |
200 | 0 | *(buffer->data+buffer->size++) = DLE; |
201 | 0 | *(buffer->data+buffer->size++) = ETX; |
202 | 0 | result = write(fd, buffer->data, (unsigned long)buffer->size); |
203 | | |
204 | 0 | if (result != -1) |
205 | 0 | return (result); |
206 | 0 | else |
207 | 0 | return (-1); |
208 | 0 | } |
209 | | |
210 | | /* |
211 | | * init_thunderbolt - Prepares Thunderbolt receiver to be used with |
212 | | * NTP (also taken from Markus Prosch). |
213 | | */ |
214 | | static void |
215 | | init_thunderbolt ( |
216 | | int fd |
217 | | ) |
218 | 0 | { |
219 | 0 | struct packettx tx; |
220 | | |
221 | 0 | tx.size = 0; |
222 | 0 | tx.data = (u_char *) emalloc(100); |
223 | | |
224 | | /* set UTC time */ |
225 | 0 | sendsupercmd (&tx, 0x8E, 0xA2); |
226 | 0 | sendbyte (&tx, 0x3); |
227 | 0 | sendetx (&tx, fd); |
228 | | |
229 | | /* activate packets 0x8F-AB and 0x8F-AC */ |
230 | 0 | sendsupercmd (&tx, 0x8E, 0xA5); |
231 | 0 | sendint (&tx, 0x5); |
232 | 0 | sendetx (&tx, fd); |
233 | |
|
234 | 0 | free(tx.data); |
235 | 0 | } |
236 | | |
237 | | /* |
238 | | * init_acutime - Prepares Acutime Receiver to be used with NTP |
239 | | */ |
240 | | static void |
241 | | init_acutime ( |
242 | | int fd |
243 | | ) |
244 | 0 | { |
245 | | /* Disable all outputs, Enable Event-Polling on PortA so |
246 | | we can ask for time packets */ |
247 | 0 | struct packettx tx; |
248 | |
|
249 | 0 | tx.size = 0; |
250 | 0 | tx.data = (u_char *) emalloc(100); |
251 | |
|
252 | 0 | sendsupercmd(&tx, 0x8E, 0xA5); |
253 | 0 | sendbyte(&tx, 0x02); |
254 | 0 | sendbyte(&tx, 0x00); |
255 | 0 | sendbyte(&tx, 0x00); |
256 | 0 | sendbyte(&tx, 0x00); |
257 | 0 | sendetx(&tx, fd); |
258 | |
|
259 | 0 | free(tx.data); |
260 | 0 | } |
261 | | |
262 | | /* |
263 | | * init_resolution - Prepares Resolution receiver to be used with NTP |
264 | | */ |
265 | | static void |
266 | | init_resolution ( |
267 | | int fd |
268 | | ) |
269 | 0 | { |
270 | 0 | struct packettx tx; |
271 | | |
272 | 0 | tx.size = 0; |
273 | 0 | tx.data = (u_char *) emalloc(100); |
274 | | |
275 | | /* set UTC time */ |
276 | 0 | sendsupercmd (&tx, 0x8E, 0xA2); |
277 | 0 | sendbyte (&tx, 0x3); |
278 | 0 | sendetx (&tx, fd); |
279 | | |
280 | | /* squelch PPS output unless locked to at least one satellite */ |
281 | 0 | sendsupercmd (&tx, 0x8E, 0x4E); |
282 | 0 | sendbyte (&tx, 0x3); |
283 | 0 | sendetx (&tx, fd); |
284 | | |
285 | | /* activate packets 0x8F-AB and 0x8F-AC */ |
286 | 0 | sendsupercmd (&tx, 0x8E, 0xA5); |
287 | 0 | sendint (&tx, 0x5); |
288 | 0 | sendetx (&tx, fd); |
289 | |
|
290 | 0 | free(tx.data); |
291 | 0 | } |
292 | | |
293 | | /* |
294 | | * palisade_start - open the devices and initialize data for processing |
295 | | */ |
296 | | static int |
297 | | palisade_start ( |
298 | | int unit, |
299 | | struct peer *peer |
300 | | ) |
301 | 0 | { |
302 | 0 | struct palisade_unit *up; |
303 | 0 | struct refclockproc *pp; |
304 | 0 | int fd; |
305 | 0 | char gpsdev[20]; |
306 | 0 | struct termios tio; |
307 | 0 | u_int speed; |
308 | |
|
309 | 0 | snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); |
310 | | |
311 | | /* |
312 | | * Open serial port. |
313 | | */ |
314 | 0 | speed = (CLK_TYPE(peer) == CLK_COPERNICUS) ? SPEED232COP : SPEED232; |
315 | 0 | fd = refclock_open(&peer->srcadr, gpsdev, speed, LDISC_RAW); |
316 | 0 | if (fd <= 0) { |
317 | 0 | #ifdef DEBUG |
318 | 0 | printf("Palisade(%d) start: open %s failed\n", unit, gpsdev); |
319 | 0 | #endif |
320 | 0 | return 0; |
321 | 0 | } |
322 | | |
323 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd, |
324 | 0 | gpsdev); |
325 | |
|
326 | 0 | if (tcgetattr(fd, &tio) < 0) { |
327 | 0 | msyslog(LOG_ERR, |
328 | 0 | "Palisade(%d) tcgetattr(fd, &tio): %m",unit); |
329 | 0 | #ifdef DEBUG |
330 | 0 | printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit); |
331 | 0 | #endif |
332 | 0 | close(fd); |
333 | 0 | return (0); |
334 | 0 | } |
335 | | |
336 | 0 | tio.c_cflag |= (PARENB|PARODD); |
337 | 0 | tio.c_iflag &= ~ICRNL; |
338 | | |
339 | | /* |
340 | | * Allocate and initialize unit structure |
341 | | */ |
342 | 0 | up = emalloc_zero(sizeof(*up)); |
343 | |
|
344 | 0 | up->type = CLK_TYPE(peer); |
345 | 0 | switch (up->type) { |
346 | 0 | case CLK_TRIMBLE: |
347 | | /* Normal mode, do nothing */ |
348 | 0 | break; |
349 | 0 | case CLK_PRAECIS: |
350 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled" |
351 | 0 | ,unit); |
352 | 0 | break; |
353 | 0 | case CLK_THUNDERBOLT: |
354 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled" |
355 | 0 | ,unit); |
356 | 0 | tio.c_cflag = (CS8|CLOCAL|CREAD); |
357 | 0 | break; |
358 | 0 | case CLK_ACUTIME: |
359 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled" |
360 | 0 | ,unit); |
361 | 0 | break; |
362 | 0 | case CLK_RESOLUTION: |
363 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) Resolution mode enabled" |
364 | 0 | ,unit); |
365 | 0 | tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD); |
366 | 0 | break; |
367 | 0 | case CLK_ACE: |
368 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) ACE III mode enabled" |
369 | 0 | ,unit); |
370 | 0 | tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD); |
371 | 0 | break; |
372 | 0 | case CLK_COPERNICUS: |
373 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) Copernicus II mode enabled" |
374 | 0 | ,unit); |
375 | | /* Must use ORing/ANDing to set/clear c_cflag bits otherwise |
376 | | CBAUD gets set back to 0. This ought to be an issue for |
377 | | the other modes above but it seems that the baud rate |
378 | | defaults to 9600 if CBAUD gets set to 0. */ |
379 | 0 | tio.c_cflag &= ~(PARENB|PARODD); |
380 | 0 | break; |
381 | 0 | default: |
382 | 0 | msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit); |
383 | 0 | break; |
384 | 0 | } |
385 | 0 | if (tcsetattr(fd, TCSANOW, &tio) == -1) { |
386 | 0 | msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); |
387 | 0 | #ifdef DEBUG |
388 | 0 | printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit); |
389 | 0 | #endif |
390 | 0 | close(fd); |
391 | 0 | free(up); |
392 | 0 | return 0; |
393 | 0 | } |
394 | | |
395 | 0 | pp = peer->procptr; |
396 | 0 | pp->io.clock_recv = palisade_io; |
397 | 0 | pp->io.srcclock = peer; |
398 | 0 | pp->io.datalen = 0; |
399 | 0 | pp->io.fd = fd; |
400 | 0 | if (!io_addclock(&pp->io)) { |
401 | 0 | #ifdef DEBUG |
402 | 0 | printf("Palisade(%d) io_addclock\n",unit); |
403 | 0 | #endif |
404 | 0 | close(fd); |
405 | 0 | pp->io.fd = -1; |
406 | 0 | free(up); |
407 | 0 | return (0); |
408 | 0 | } |
409 | | |
410 | | /* |
411 | | * Initialize miscellaneous variables |
412 | | */ |
413 | 0 | pp->unitptr = up; |
414 | 0 | pp->clockdesc = DESCRIPTION; |
415 | |
|
416 | 0 | peer->precision = PRECISION; |
417 | 0 | peer->sstclktype = CTL_SST_TS_UHF; |
418 | 0 | peer->minpoll = TRMB_MINPOLL; |
419 | 0 | peer->maxpoll = TRMB_MAXPOLL; |
420 | 0 | memcpy((char *)&pp->refid, REFID, 4); |
421 | | |
422 | 0 | up->leap_status = 0; |
423 | 0 | up->unit = (short) unit; |
424 | 0 | up->rpt_status = TSIP_PARSED_EMPTY; |
425 | 0 | up->rpt_cnt = 0; |
426 | |
|
427 | 0 | if (up->type == CLK_THUNDERBOLT) |
428 | 0 | init_thunderbolt(fd); |
429 | 0 | if (up->type == CLK_ACUTIME) |
430 | 0 | init_acutime(fd); |
431 | 0 | if (up->type == CLK_RESOLUTION) |
432 | 0 | init_resolution(fd); |
433 | |
|
434 | 0 | return 1; |
435 | 0 | } |
436 | | |
437 | | |
438 | | /* |
439 | | * palisade_shutdown - shut down the clock |
440 | | */ |
441 | | static void |
442 | | palisade_shutdown ( |
443 | | int unit, |
444 | | struct peer *peer |
445 | | ) |
446 | 0 | { |
447 | 0 | struct palisade_unit *up; |
448 | 0 | struct refclockproc *pp; |
449 | 0 | pp = peer->procptr; |
450 | 0 | up = pp->unitptr; |
451 | 0 | if (-1 != pp->io.fd) |
452 | 0 | io_closeclock(&pp->io); |
453 | 0 | if (NULL != up) |
454 | 0 | free(up); |
455 | 0 | } |
456 | | |
457 | | |
458 | | /* |
459 | | * unpack helpers |
460 | | */ |
461 | | |
462 | | static inline uint8_t |
463 | | get_u8( |
464 | | const char *cp) |
465 | 0 | { |
466 | 0 | return ((const u_char*)cp)[0]; |
467 | 0 | } |
468 | | |
469 | | static inline uint16_t |
470 | | get_u16( |
471 | | const char *cp) |
472 | 0 | { |
473 | 0 | return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1); |
474 | 0 | } |
475 | | |
476 | | /* |
477 | | * unpack & fix date (the receiver provides a valid time for 1024 weeks |
478 | | * after 1997-12-14 and therefore folds back in 2017, 2037,...) |
479 | | * |
480 | | * Returns -1 on error, day-of-month + (month * 32) othertwise. |
481 | | */ |
482 | | int |
483 | | decode_date( |
484 | | struct refclockproc *pp, |
485 | | const char *cp) |
486 | 0 | { |
487 | 0 | static int32_t s_baseday = 0; |
488 | | |
489 | 0 | struct calendar jd; |
490 | 0 | int32_t rd; |
491 | |
|
492 | 0 | if (0 == s_baseday) { |
493 | 0 | if (!ntpcal_get_build_date(&jd)) { |
494 | 0 | jd.year = 2015; |
495 | 0 | jd.month = 1; |
496 | 0 | jd.monthday = 1; |
497 | 0 | } |
498 | 0 | s_baseday = ntpcal_date_to_rd(&jd); |
499 | 0 | } |
500 | | |
501 | | /* get date fields and convert to RDN */ |
502 | 0 | jd.monthday = get_u8 ( cp ); |
503 | 0 | jd.month = get_u8 (cp + 1); |
504 | 0 | jd.year = get_u16(cp + 2); |
505 | 0 | rd = ntpcal_date_to_rd(&jd); |
506 | | |
507 | | /* for the paranoid: do reverse calculation and cross-check */ |
508 | 0 | ntpcal_rd_to_date(&jd, rd); |
509 | 0 | if ((jd.monthday != get_u8 ( cp )) || |
510 | 0 | (jd.month != get_u8 (cp + 1)) || |
511 | 0 | (jd.year != get_u16(cp + 2)) ) |
512 | 0 | return - 1; |
513 | | |
514 | | /* calculate cycle shift to base day and calculate re-folded |
515 | | * date |
516 | | * |
517 | | * One could do a proper modulo calculation here, but a counting |
518 | | * loop is probably faster for the next few rollovers... |
519 | | */ |
520 | 0 | while (rd < s_baseday) |
521 | 0 | rd += 7*1024; |
522 | 0 | ntpcal_rd_to_date(&jd, rd); |
523 | | |
524 | | /* fill refclock structure & indicate success */ |
525 | 0 | pp->day = jd.yearday; |
526 | 0 | pp->year = jd.year; |
527 | 0 | return ((int)jd.month << 5) | jd.monthday; |
528 | 0 | } |
529 | | |
530 | | |
531 | | /* |
532 | | * TSIP_decode - decode the TSIP data packets |
533 | | */ |
534 | | int |
535 | | TSIP_decode ( |
536 | | struct peer *peer |
537 | | ) |
538 | 0 | { |
539 | 0 | int st; |
540 | 0 | long secint; |
541 | 0 | double secs; |
542 | 0 | double secfrac; |
543 | 0 | unsigned short event = 0; |
544 | 0 | int mmday; |
545 | 0 | long tow; |
546 | 0 | uint16_t wn; |
547 | 0 | int GPS_UTC_Offset; |
548 | | |
549 | 0 | struct palisade_unit *up; |
550 | 0 | struct refclockproc *pp; |
551 | |
|
552 | 0 | pp = peer->procptr; |
553 | 0 | up = pp->unitptr; |
554 | | |
555 | | /* |
556 | | * Check the time packet, decode its contents. |
557 | | * If the timecode has invalid length or is not in |
558 | | * proper format, declare bad format and exit. |
559 | | */ |
560 | |
|
561 | 0 | if ((up->type != CLK_THUNDERBOLT) && |
562 | 0 | (up->type != CLK_ACUTIME ) && |
563 | 0 | (up->type != CLK_RESOLUTION ) && |
564 | 0 | (up->type != CLK_ACE ) && |
565 | 0 | (up->type != CLK_COPERNICUS ) ) |
566 | 0 | { |
567 | 0 | if ((up->rpt_buf[0] == (char) 0x41) || |
568 | 0 | (up->rpt_buf[0] == (char) 0x46) || |
569 | 0 | (up->rpt_buf[0] == (char) 0x54) || |
570 | 0 | (up->rpt_buf[0] == (char) 0x4B) || |
571 | 0 | (up->rpt_buf[0] == (char) 0x6D)) { |
572 | | |
573 | | /* standard time packet - GPS time and GPS week number */ |
574 | 0 | #ifdef DEBUG |
575 | 0 | printf("Palisade Port B packets detected. Connect to Port A\n"); |
576 | 0 | #endif |
577 | |
|
578 | 0 | return 0; |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | | /* |
583 | | * We cast both to u_char as 0x8f uses the sign bit on a char |
584 | | */ |
585 | 0 | if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) { |
586 | | /* |
587 | | * Superpackets |
588 | | */ |
589 | 0 | event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff); |
590 | 0 | if (!((pp->sloppyclockflag & CLK_FLAG2) || event)) |
591 | | /* Ignore Packet */ |
592 | 0 | return 0; |
593 | | |
594 | 0 | switch (mb(0) & 0xff) { |
595 | | |
596 | 0 | case PACKET_8F0B: |
597 | |
|
598 | 0 | if (up->polled <= 0) |
599 | 0 | return 0; |
600 | | |
601 | 0 | if (up->rpt_cnt != LENCODE_8F0B) /* check length */ |
602 | 0 | break; |
603 | | |
604 | 0 | #ifdef DEBUG |
605 | 0 | if (debug > 1) { |
606 | 0 | int ts; |
607 | 0 | double lat, lon, alt; |
608 | 0 | lat = getdbl((u_char *) &mb(42)) * R2D; |
609 | 0 | lon = getdbl((u_char *) &mb(50)) * R2D; |
610 | 0 | alt = getdbl((u_char *) &mb(58)); |
611 | |
|
612 | 0 | printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", |
613 | 0 | up->unit, lat,lon,alt); |
614 | 0 | printf("TSIP_decode: unit %d: Sats:", |
615 | 0 | up->unit); |
616 | 0 | for (st = 66, ts = 0; st <= 73; st++) |
617 | 0 | if (mb(st)) { |
618 | 0 | if (mb(st) > 0) ts++; |
619 | 0 | printf(" %02d", mb(st)); |
620 | 0 | } |
621 | 0 | printf(" : Tracking %d\n", ts); |
622 | 0 | } |
623 | 0 | #endif |
624 | |
|
625 | 0 | GPS_UTC_Offset = getint((u_char *) &mb(16)); |
626 | 0 | if (GPS_UTC_Offset == 0) { /* Check UTC offset */ |
627 | 0 | #ifdef DEBUG |
628 | 0 | printf("TSIP_decode: UTC Offset Unknown\n"); |
629 | 0 | #endif |
630 | 0 | break; |
631 | 0 | } |
632 | | |
633 | 0 | secs = getdbl((u_char *) &mb(3)); |
634 | 0 | secint = (long) secs; |
635 | 0 | secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ |
636 | |
|
637 | 0 | pp->nsec = (long) (secfrac * 1000000000); |
638 | |
|
639 | 0 | secint %= 86400; /* Only care about today */ |
640 | 0 | pp->hour = secint / 3600; |
641 | 0 | secint %= 3600; |
642 | 0 | pp->minute = secint / 60; |
643 | 0 | secint %= 60; |
644 | 0 | pp->second = secint % 60; |
645 | |
|
646 | 0 | mmday = decode_date(pp, &mb(11)); |
647 | 0 | if (mmday < 0) |
648 | 0 | break; |
649 | | |
650 | 0 | #ifdef DEBUG |
651 | 0 | if (debug > 1) |
652 | 0 | printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n", |
653 | 0 | up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, |
654 | 0 | pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset); |
655 | 0 | #endif |
656 | | /* Only use this packet when no |
657 | | * 8F-AD's are being received |
658 | | */ |
659 | |
|
660 | 0 | if (up->leap_status) { |
661 | 0 | up->leap_status = 0; |
662 | 0 | return 0; |
663 | 0 | } |
664 | | |
665 | 0 | return 2; |
666 | 0 | break; |
667 | | |
668 | 0 | case PACKET_NTP: |
669 | | /* Palisade-NTP Packet */ |
670 | |
|
671 | 0 | if (up->rpt_cnt != LENCODE_NTP) /* check length */ |
672 | 0 | break; |
673 | | |
674 | 0 | up->leap_status = mb(19); |
675 | |
|
676 | 0 | if (up->polled <= 0) |
677 | 0 | return 0; |
678 | | |
679 | | /* Check Tracking Status */ |
680 | 0 | st = mb(18); |
681 | 0 | if (st < 0 || st > 14) |
682 | 0 | st = 14; |
683 | 0 | if ((st >= 2 && st <= 7) || st == 11 || st == 12) { |
684 | 0 | #ifdef DEBUG |
685 | 0 | printf("TSIP_decode: Not Tracking Sats : %s\n", |
686 | 0 | *Tracking_Status[st]); |
687 | 0 | #endif |
688 | 0 | refclock_report(peer, CEVNT_BADTIME); |
689 | 0 | up->polled = -1; |
690 | 0 | return 0; |
691 | 0 | break; |
692 | 0 | } |
693 | | |
694 | 0 | mmday = decode_date(pp, &mb(14)); |
695 | 0 | if (mmday < 0) |
696 | 0 | break; |
697 | 0 | up->month = (mmday >> 5); /* Save for LEAP check */ |
698 | |
|
699 | 0 | if ( (up->leap_status & PALISADE_LEAP_PENDING) && |
700 | | /* Avoid early announce: https://bugs.ntp.org/2773 */ |
701 | 0 | (6 == up->month || 12 == up->month) ) { |
702 | 0 | if (up->leap_status & PALISADE_UTC_TIME) |
703 | 0 | pp->leap = LEAP_ADDSECOND; |
704 | 0 | else |
705 | 0 | pp->leap = LEAP_DELSECOND; |
706 | 0 | } |
707 | 0 | else if (up->leap_status) |
708 | 0 | pp->leap = LEAP_NOWARNING; |
709 | | |
710 | 0 | else { /* UTC flag is not set: |
711 | | * Receiver may have been reset, and lost |
712 | | * its UTC almanac data */ |
713 | 0 | pp->leap = LEAP_NOTINSYNC; |
714 | 0 | #ifdef DEBUG |
715 | 0 | printf("TSIP_decode: UTC Almanac unavailable: %d\n", |
716 | 0 | mb(19)); |
717 | 0 | #endif |
718 | 0 | refclock_report(peer, CEVNT_BADTIME); |
719 | 0 | up->polled = -1; |
720 | 0 | return 0; |
721 | 0 | } |
722 | | |
723 | 0 | pp->nsec = (long) (getdbl((u_char *) &mb(3)) |
724 | 0 | * 1000000000); |
725 | |
|
726 | 0 | pp->hour = mb(11); |
727 | 0 | pp->minute = mb(12); |
728 | 0 | pp->second = mb(13); |
729 | |
|
730 | 0 | #ifdef DEBUG |
731 | 0 | if (debug > 1) |
732 | 0 | printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n", |
733 | 0 | up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, |
734 | 0 | pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, |
735 | 0 | mb(19), *Tracking_Status[st]); |
736 | 0 | #endif |
737 | 0 | return 1; |
738 | 0 | break; |
739 | | |
740 | 0 | case PACKET_8FAC: |
741 | 0 | if (up->polled <= 0) |
742 | 0 | return 0; |
743 | | |
744 | 0 | if (up->rpt_cnt != LENCODE_8FAC)/* check length */ |
745 | 0 | break; |
746 | | |
747 | 0 | #ifdef DEBUG |
748 | 0 | if (debug > 1) { |
749 | 0 | double lat, lon, alt; |
750 | 0 | lat = getdbl((u_char *) &mb(36)) * R2D; |
751 | 0 | lon = getdbl((u_char *) &mb(44)) * R2D; |
752 | 0 | alt = getdbl((u_char *) &mb(52)); |
753 | |
|
754 | 0 | printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", |
755 | 0 | up->unit, lat,lon,alt); |
756 | 0 | printf("TSIP_decode: unit %d\n", up->unit); |
757 | 0 | } |
758 | 0 | #endif |
759 | 0 | if ( (getint((u_char *) &mb(10)) & 0x80) && |
760 | | /* Avoid early announce: https://bugs.ntp.org/2773 */ |
761 | 0 | (6 == up->month || 12 == up->month) ) |
762 | 0 | pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */ |
763 | 0 | else |
764 | 0 | pp->leap = LEAP_NOWARNING; |
765 | |
|
766 | 0 | #ifdef DEBUG |
767 | 0 | if (debug > 1) |
768 | 0 | printf("TSIP_decode: unit %d: 0x%02x leap %d\n", |
769 | 0 | up->unit, mb(0) & 0xff, pp->leap); |
770 | 0 | if (debug > 1) { |
771 | 0 | printf("Receiver MODE: 0x%02X\n", (u_char)mb(1)); |
772 | 0 | if (mb(1) == 0x00) |
773 | 0 | printf(" AUTOMATIC\n"); |
774 | 0 | if (mb(1) == 0x01) |
775 | 0 | printf(" SINGLE SATELLITE\n"); |
776 | 0 | if (mb(1) == 0x03) |
777 | 0 | printf(" HORIZONTAL(2D)\n"); |
778 | 0 | if (mb(1) == 0x04) |
779 | 0 | printf(" FULL POSITION(3D)\n"); |
780 | 0 | if (mb(1) == 0x05) |
781 | 0 | printf(" DGPR REFERENCE\n"); |
782 | 0 | if (mb(1) == 0x06) |
783 | 0 | printf(" CLOCK HOLD(2D)\n"); |
784 | 0 | if (mb(1) == 0x07) |
785 | 0 | printf(" OVERDETERMINED CLOCK\n"); |
786 | |
|
787 | 0 | printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2)); |
788 | 0 | if (mb(2) == 0x00) |
789 | 0 | printf(" NORMAL\n"); |
790 | 0 | if (mb(2) == 0x01) |
791 | 0 | printf(" POWER-UP\n"); |
792 | 0 | if (mb(2) == 0x02) |
793 | 0 | printf(" AUTO HOLDOVER\n"); |
794 | 0 | if (mb(2) == 0x03) |
795 | 0 | printf(" MANUAL HOLDOVER\n"); |
796 | 0 | if (mb(2) == 0x04) |
797 | 0 | printf(" RECOVERY\n"); |
798 | 0 | if (mb(2) == 0x06) |
799 | 0 | printf(" DISCIPLINING DISABLED\n"); |
800 | 0 | } |
801 | 0 | #endif |
802 | 0 | return 0; |
803 | 0 | break; |
804 | | |
805 | 0 | case PACKET_8FAB: |
806 | | /* Thunderbolt Primary Timing Packet */ |
807 | |
|
808 | 0 | if (up->rpt_cnt != LENCODE_8FAB) /* check length */ |
809 | 0 | break; |
810 | | |
811 | 0 | if (up->polled <= 0) |
812 | 0 | return 0; |
813 | | |
814 | 0 | GPS_UTC_Offset = getint((u_char *) &mb(7)); |
815 | |
|
816 | 0 | if (GPS_UTC_Offset == 0){ /* Check UTC Offset */ |
817 | 0 | #ifdef DEBUG |
818 | 0 | printf("TSIP_decode: UTC Offset Unknown\n"); |
819 | 0 | #endif |
820 | 0 | break; |
821 | 0 | } |
822 | | |
823 | | |
824 | 0 | if ((mb(9) & 0x1d) == 0x0) { |
825 | | /* if we know the GPS time and the UTC offset, |
826 | | we expect UTC timing information !!! */ |
827 | |
|
828 | 0 | pp->leap = LEAP_NOTINSYNC; |
829 | 0 | refclock_report(peer, CEVNT_BADTIME); |
830 | 0 | up->polled = -1; |
831 | 0 | return 0; |
832 | 0 | } |
833 | | |
834 | 0 | pp->nsec = 0; |
835 | 0 | #ifdef DEBUG |
836 | 0 | printf("\nTiming Flags are:\n"); |
837 | 0 | printf("Timing flag value is: 0x%X\n", mb(9)); |
838 | 0 | if ((mb(9) & 0x01) != 0) |
839 | 0 | printf (" Getting UTC time\n"); |
840 | 0 | else |
841 | 0 | printf (" Getting GPS time\n"); |
842 | 0 | if ((mb(9) & 0x02) != 0) |
843 | 0 | printf (" PPS is from UTC\n"); |
844 | 0 | else |
845 | 0 | printf (" PPS is from GPS\n"); |
846 | 0 | if ((mb(9) & 0x04) != 0) |
847 | 0 | printf (" Time is not Set\n"); |
848 | 0 | else |
849 | 0 | printf (" Time is Set\n"); |
850 | 0 | if ((mb(9) & 0x08) != 0) |
851 | 0 | printf(" I dont have UTC info\n"); |
852 | 0 | else |
853 | 0 | printf (" I have UTC info\n"); |
854 | 0 | if ((mb(9) & 0x10) != 0) |
855 | 0 | printf (" Time is from USER\n\n"); |
856 | 0 | else |
857 | 0 | printf (" Time is from GPS\n\n"); |
858 | 0 | #endif |
859 | |
|
860 | 0 | mmday = decode_date(pp, &mb(13)); |
861 | 0 | if (mmday < 0) |
862 | 0 | break; |
863 | 0 | tow = getlong((u_char *) &mb(1)); |
864 | 0 | #ifdef DEBUG |
865 | 0 | if (debug > 1) { |
866 | 0 | printf("pp->day: %d\n", pp->day); |
867 | 0 | printf("TOW: %ld\n", tow); |
868 | 0 | printf("DAY: %d\n", (mmday & 31)); |
869 | 0 | } |
870 | 0 | #endif |
871 | 0 | pp->hour = mb(12); |
872 | 0 | pp->minute = mb(11); |
873 | 0 | pp->second = mb(10); |
874 | | |
875 | |
|
876 | 0 | #ifdef DEBUG |
877 | 0 | if (debug > 1) |
878 | 0 | printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ", |
879 | 0 | up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, |
880 | 0 | pp->nsec, (mmday >> 5), (mmday & 31), pp->year); |
881 | 0 | #endif |
882 | 0 | return 1; |
883 | 0 | break; |
884 | | |
885 | 0 | default: |
886 | | /* Ignore Packet */ |
887 | 0 | return 0; |
888 | 0 | } /* switch */ |
889 | 0 | } /* if 8F packets */ |
890 | | |
891 | 0 | else if (up->rpt_buf[0] == (u_char)0x42) { |
892 | 0 | printf("0x42\n"); |
893 | 0 | return 0; |
894 | 0 | } |
895 | 0 | else if (up->rpt_buf[0] == (u_char)0x43) { |
896 | 0 | printf("0x43\n"); |
897 | 0 | return 0; |
898 | 0 | } |
899 | 0 | else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){ |
900 | 0 | printf("Undocumented 0x41 packet on Thunderbolt\n"); |
901 | 0 | return 0; |
902 | 0 | } |
903 | 0 | else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) { |
904 | 0 | #ifdef DEBUG |
905 | 0 | printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0))); |
906 | 0 | printf("GPS WN: %d\n", getint((u_char *) &mb(4))); |
907 | 0 | printf("GPS UTC-GPS Offset: %ld\n", (long)getlong((u_char *) &mb(6))); |
908 | 0 | #endif |
909 | 0 | return 0; |
910 | 0 | } |
911 | | |
912 | | /* GPS time packet for ACE III or Copernicus II receiver */ |
913 | 0 | else if ((up->rpt_buf[0] == PACKET_41) && |
914 | 0 | ((up->type == CLK_ACE) || (up->type == CLK_COPERNICUS))) { |
915 | 0 | #ifdef DEBUG |
916 | 0 | if ((debug > 1) && (up->type == CLK_ACE)) |
917 | 0 | printf("TSIP_decode: Packet 0x41 seen in ACE III mode\n"); |
918 | 0 | if ((debug > 1) && (up->type == CLK_COPERNICUS)) |
919 | 0 | printf("TSIP_decode: Packet 0x41 seen in Copernicus II mode\n"); |
920 | 0 | #endif |
921 | 0 | if (up->rpt_cnt != LENCODE_41) { /* check length */ |
922 | 0 | refclock_report(peer, CEVNT_BADREPLY); |
923 | 0 | up->polled = -1; |
924 | 0 | #ifdef DEBUG |
925 | 0 | printf("TSIP_decode: unit %d: bad packet %02x len %d\n", |
926 | 0 | up->unit, up->rpt_buf[0] & 0xff, up->rpt_cnt); |
927 | 0 | #endif |
928 | 0 | return 0; |
929 | 0 | } |
930 | 0 | if (up->polled <= 0) |
931 | 0 | return 0; |
932 | 0 | tow = (long)getsingle((u_char *) &mb(0)); |
933 | 0 | wn = (uint16_t)getint((u_char *) &mb(4)); |
934 | 0 | GPS_UTC_Offset = (int)getsingle((u_char *) &mb(6)); |
935 | 0 | if (GPS_UTC_Offset == 0){ /* Check UTC Offset */ |
936 | 0 | #ifdef DEBUG |
937 | 0 | printf("TSIP_decode: UTC Offset Unknown\n"); |
938 | 0 | #endif |
939 | 0 | refclock_report(peer, CEVNT_BADREPLY); |
940 | 0 | up->polled = -1; |
941 | 0 | return 0; |
942 | 0 | } |
943 | | /* Get date & time from WN & ToW minus offset */ |
944 | 0 | { |
945 | 0 | TCivilDate cd; |
946 | 0 | TGpsDatum wd; |
947 | 0 | l_fp ugo; /* UTC-GPS offset, negative number */ |
948 | 0 | ugo.Ul_i.Xl_i = (int32_t)-GPS_UTC_Offset; |
949 | 0 | ugo.l_uf = 0; |
950 | 0 | wd = gpscal_from_gpsweek((wn % 1024), (int32_t)tow, ugo); |
951 | 0 | gpscal_to_calendar(&cd, &wd); |
952 | 0 | pp->year = cd.year; |
953 | 0 | pp->day = cd.yearday; |
954 | 0 | pp->hour = cd.hour; |
955 | 0 | pp->minute = cd.minute; |
956 | 0 | pp->second = cd.second; |
957 | 0 | pp->nsec = 0; |
958 | 0 | pp->leap = LEAP_NOWARNING; |
959 | 0 | #ifdef DEBUG |
960 | 0 | if (debug > 1) { |
961 | 0 | printf("GPS TOW: %ld\n", tow); |
962 | 0 | printf("GPS WN: %d\n", wn); |
963 | 0 | printf("GPS UTC-GPS Offset: %d\n", GPS_UTC_Offset); |
964 | 0 | printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ", |
965 | 0 | up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, |
966 | 0 | pp->nsec, cd.month, cd.monthday, pp->year); |
967 | 0 | } |
968 | 0 | #endif |
969 | 0 | } |
970 | 0 | return 1; |
971 | 0 | } |
972 | | |
973 | | /* Health Status for Acutime Receiver */ |
974 | 0 | else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) { |
975 | 0 | #ifdef DEBUG |
976 | 0 | if (debug > 1) |
977 | | /* Status Codes */ |
978 | 0 | switch (mb(0)) { |
979 | 0 | case 0x00: |
980 | 0 | printf ("Doing Position Fixes\n"); |
981 | 0 | break; |
982 | 0 | case 0x01: |
983 | 0 | printf ("Do not have GPS time yet\n"); |
984 | 0 | break; |
985 | 0 | case 0x03: |
986 | 0 | printf ("PDOP is too high\n"); |
987 | 0 | break; |
988 | 0 | case 0x08: |
989 | 0 | printf ("No usable satellites\n"); |
990 | 0 | break; |
991 | 0 | case 0x09: |
992 | 0 | printf ("Only 1 usable satellite\n"); |
993 | 0 | break; |
994 | 0 | case 0x0A: |
995 | 0 | printf ("Only 2 usable satellites\n"); |
996 | 0 | break; |
997 | 0 | case 0x0B: |
998 | 0 | printf ("Only 3 usable satellites\n"); |
999 | 0 | break; |
1000 | 0 | case 0x0C: |
1001 | 0 | printf("The Chosen satellite is unusable\n"); |
1002 | 0 | break; |
1003 | 0 | } |
1004 | 0 | #endif |
1005 | | /* Error Codes */ |
1006 | 0 | if (mb(1) != 0) { |
1007 | | |
1008 | 0 | refclock_report(peer, CEVNT_BADTIME); |
1009 | 0 | up->polled = -1; |
1010 | 0 | #ifdef DEBUG |
1011 | 0 | if (debug > 1) { |
1012 | 0 | if (mb(1) & 0x01) |
1013 | 0 | printf ("Signal Processor Error, reset unit.\n"); |
1014 | 0 | if (mb(1) & 0x02) |
1015 | 0 | printf ("Alignment error, channel or chip 1, reset unit.\n"); |
1016 | 0 | if (mb(1) & 0x03) |
1017 | 0 | printf ("Alignment error, channel or chip 2, reset unit.\n"); |
1018 | 0 | if (mb(1) & 0x04) |
1019 | 0 | printf ("Antenna feed line fault (open or short)\n"); |
1020 | 0 | if (mb(1) & 0x05) |
1021 | 0 | printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n"); |
1022 | 0 | } |
1023 | 0 | #endif |
1024 | | |
1025 | 0 | return 0; |
1026 | 0 | } |
1027 | 0 | } |
1028 | | |
1029 | | /* Health Status for Copernicus II Receiver */ |
1030 | 0 | else if ((up->rpt_buf[0] == PACKET_46) && (up->type == CLK_COPERNICUS)) { |
1031 | 0 | #ifdef DEBUG |
1032 | 0 | if (debug > 1) |
1033 | | /* Status Codes */ |
1034 | 0 | switch (mb(0)) { |
1035 | 0 | case 0x00: |
1036 | 0 | printf ("Doing Position Fixes\n"); |
1037 | 0 | break; |
1038 | 0 | case 0x01: |
1039 | 0 | printf ("Do not have GPS time yet\n"); |
1040 | 0 | break; |
1041 | 0 | case 0x03: |
1042 | 0 | printf ("PDOP is too high\n"); |
1043 | 0 | break; |
1044 | 0 | case 0x04: |
1045 | 0 | printf("The Chosen satellite is unusable\n"); |
1046 | 0 | break; |
1047 | 0 | case 0x08: |
1048 | 0 | printf ("No usable satellites\n"); |
1049 | 0 | break; |
1050 | 0 | case 0x09: |
1051 | 0 | printf ("Only 1 usable satellite\n"); |
1052 | 0 | break; |
1053 | 0 | case 0x0A: |
1054 | 0 | printf ("Only 2 usable satellites\n"); |
1055 | 0 | break; |
1056 | 0 | case 0x0B: |
1057 | 0 | printf ("Only 3 usable satellites\n"); |
1058 | 0 | break; |
1059 | 0 | } |
1060 | 0 | #endif |
1061 | | /* Error Codes */ |
1062 | 0 | if ((mb(1) & 0x3E) != 0) { /* Don't regard bits 0 and 6 as errors */ |
1063 | 0 | refclock_report(peer, CEVNT_BADTIME); |
1064 | 0 | up->polled = -1; |
1065 | 0 | #ifdef DEBUG |
1066 | 0 | if (debug > 1) { |
1067 | 0 | if ((mb(1) & 0x18) == 0x08) |
1068 | 0 | printf ("Antenna feed line fault (open)\n"); |
1069 | 0 | if ((mb(1) & 0x18) == 0x18) |
1070 | 0 | printf ("Antenna feed line fault (short)\n"); |
1071 | 0 | } |
1072 | 0 | #endif |
1073 | 0 | } |
1074 | 0 | return 0; |
1075 | 0 | } |
1076 | | |
1077 | | /* Other packets output by ACE III & Copernicus II Receivers, dropped silently */ |
1078 | 0 | else if (((up->rpt_buf[0] == (char) 0x4A) || |
1079 | 0 | (up->rpt_buf[0] == (char) 0x4B) || |
1080 | 0 | (up->rpt_buf[0] == (char) 0x56) || |
1081 | 0 | (up->rpt_buf[0] == (char) 0x5F) || |
1082 | 0 | (up->rpt_buf[0] == (char) 0x6D) || |
1083 | 0 | (up->rpt_buf[0] == (char) 0x82) || |
1084 | 0 | (up->rpt_buf[0] == (char) 0x84)) && |
1085 | 0 | ((up->type == CLK_ACE) || (up->type == CLK_COPERNICUS))) { |
1086 | 0 | #ifdef DEBUG |
1087 | 0 | if ((debug > 1) && (up->type == CLK_ACE)) |
1088 | 0 | printf("TSIP_decode: Packet 0x%2x seen in ACE III mode\n", (up->rpt_buf[0] & 0XFF)); |
1089 | 0 | if ((debug > 1) && (up->type == CLK_COPERNICUS)) |
1090 | 0 | printf("TSIP_decode: Packet 0x%2x seen in Copernicus II mode\n", (up->rpt_buf[0] & 0XFF)); |
1091 | 0 | #endif |
1092 | 0 | return 0; |
1093 | 0 | } |
1094 | | |
1095 | 0 | else if (up->rpt_buf[0] == 0x54) |
1096 | 0 | return 0; |
1097 | | |
1098 | 0 | else if (up->rpt_buf[0] == PACKET_6D) { |
1099 | 0 | #ifdef DEBUG |
1100 | 0 | int sats; |
1101 | |
|
1102 | 0 | if ((mb(0) & 0x01) && (mb(0) & 0x02)) |
1103 | 0 | printf("2d Fix Dimension\n"); |
1104 | 0 | if (mb(0) & 0x04) |
1105 | 0 | printf("3d Fix Dimension\n"); |
1106 | |
|
1107 | 0 | if (mb(0) & 0x08) |
1108 | 0 | printf("Fix Mode is MANUAL\n"); |
1109 | 0 | else |
1110 | 0 | printf("Fix Mode is AUTO\n"); |
1111 | | |
1112 | 0 | sats = mb(0) & 0xF0; |
1113 | 0 | sats = sats >> 4; |
1114 | 0 | printf("Tracking %d Satellites\n", sats); |
1115 | 0 | #endif |
1116 | 0 | return 0; |
1117 | 0 | } /* else if not super packet */ |
1118 | 0 | refclock_report(peer, CEVNT_BADREPLY); |
1119 | 0 | up->polled = -1; |
1120 | 0 | #ifdef DEBUG |
1121 | 0 | printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", |
1122 | 0 | up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, |
1123 | 0 | event, up->rpt_cnt); |
1124 | 0 | #endif |
1125 | 0 | return 0; |
1126 | 0 | } |
1127 | | |
1128 | | /* |
1129 | | * palisade__receive - receive data from the serial interface |
1130 | | */ |
1131 | | |
1132 | | static void |
1133 | | palisade_receive ( |
1134 | | struct peer * peer |
1135 | | ) |
1136 | 0 | { |
1137 | 0 | struct palisade_unit *up; |
1138 | 0 | struct refclockproc *pp; |
1139 | | |
1140 | | /* |
1141 | | * Initialize pointers and read the timecode and timestamp. |
1142 | | */ |
1143 | 0 | pp = peer->procptr; |
1144 | 0 | up = pp->unitptr; |
1145 | | |
1146 | 0 | if (! TSIP_decode(peer)) return; |
1147 | | |
1148 | 0 | if (up->polled <= 0) |
1149 | 0 | return; /* no poll pending, already received or timeout */ |
1150 | | |
1151 | 0 | up->polled = 0; /* Poll reply received */ |
1152 | 0 | pp->lencode = 0; /* clear time code */ |
1153 | 0 | #ifdef DEBUG |
1154 | 0 | if (debug) |
1155 | 0 | printf( |
1156 | 0 | "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n", |
1157 | 0 | up->unit, pp->year, pp->day, pp->hour, pp->minute, |
1158 | 0 | pp->second, pp->nsec); |
1159 | 0 | #endif |
1160 | | |
1161 | | /* |
1162 | | * Process the sample |
1163 | | * Generate timecode: YYYY DoY HH:MM:SS.microsec |
1164 | | * report and process |
1165 | | */ |
1166 | |
|
1167 | 0 | snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), |
1168 | 0 | "%4d %03d %02d:%02d:%02d.%09ld", |
1169 | 0 | pp->year, pp->day, |
1170 | 0 | pp->hour,pp->minute, pp->second, pp->nsec); |
1171 | 0 | pp->lencode = 24; |
1172 | |
|
1173 | 0 | if (!refclock_process(pp)) { |
1174 | 0 | refclock_report(peer, CEVNT_BADTIME); |
1175 | |
|
1176 | 0 | #ifdef DEBUG |
1177 | 0 | printf("palisade_receive: unit %d: refclock_process failed!\n", |
1178 | 0 | up->unit); |
1179 | 0 | #endif |
1180 | 0 | return; |
1181 | 0 | } |
1182 | | |
1183 | 0 | record_clock_stats(&peer->srcadr, pp->a_lastcode); |
1184 | |
|
1185 | 0 | #ifdef DEBUG |
1186 | 0 | if (debug) |
1187 | 0 | printf("palisade_receive: unit %d: %s\n", |
1188 | 0 | up->unit, prettydate(&pp->lastrec)); |
1189 | 0 | #endif |
1190 | 0 | pp->lastref = pp->lastrec; |
1191 | 0 | refclock_receive(peer); |
1192 | 0 | } |
1193 | | |
1194 | | |
1195 | | /* |
1196 | | * palisade_poll - called by the transmit procedure |
1197 | | * |
1198 | | */ |
1199 | | static void |
1200 | | palisade_poll ( |
1201 | | int unit, |
1202 | | struct peer *peer |
1203 | | ) |
1204 | 0 | { |
1205 | 0 | struct palisade_unit *up; |
1206 | 0 | struct refclockproc *pp; |
1207 | | |
1208 | 0 | pp = peer->procptr; |
1209 | 0 | up = pp->unitptr; |
1210 | |
|
1211 | 0 | pp->polls++; |
1212 | 0 | if (up->polled > 0) /* last reply never arrived or error */ |
1213 | 0 | refclock_report(peer, CEVNT_TIMEOUT); |
1214 | |
|
1215 | 0 | up->polled = 2; /* synchronous packet + 1 event */ |
1216 | | |
1217 | 0 | #ifdef DEBUG |
1218 | 0 | if (debug) |
1219 | 0 | printf("palisade_poll: unit %d: polling %s\n", unit, |
1220 | 0 | (pp->sloppyclockflag & CLK_FLAG2) ? |
1221 | 0 | "synchronous packet" : "event"); |
1222 | 0 | #endif |
1223 | |
|
1224 | 0 | if (pp->sloppyclockflag & CLK_FLAG2) |
1225 | 0 | return; /* using synchronous packet input */ |
1226 | | |
1227 | 0 | if(up->type == CLK_PRAECIS) { |
1228 | 0 | if (write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) { |
1229 | 0 | msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); |
1230 | 0 | } else { |
1231 | 0 | praecis_msg = 1; |
1232 | 0 | return; |
1233 | 0 | } |
1234 | 0 | } |
1235 | | |
1236 | 0 | if (HW_poll(pp) < 0) |
1237 | 0 | refclock_report(peer, CEVNT_FAULT); |
1238 | 0 | } |
1239 | | |
1240 | | static void |
1241 | | praecis_parse ( |
1242 | | struct recvbuf *rbufp, |
1243 | | struct peer *peer |
1244 | | ) |
1245 | 0 | { |
1246 | 0 | static char buf[100]; |
1247 | 0 | static int p = 0; |
1248 | 0 | struct refclockproc *pp; |
1249 | |
|
1250 | 0 | pp = peer->procptr; |
1251 | |
|
1252 | 0 | if (p + rbufp->recv_length >= sizeof buf) { |
1253 | 0 | struct palisade_unit *up; |
1254 | 0 | up = pp->unitptr; |
1255 | | |
1256 | | /* |
1257 | | * We COULD see if there is a \r\n in the incoming |
1258 | | * buffer before it overflows, and then process the |
1259 | | * current line. |
1260 | | * |
1261 | | * Similarly, if we already have a hunk of data that |
1262 | | * we're now flushing, that will cause the line of |
1263 | | * data we're in the process of collecting to be garbage. |
1264 | | * |
1265 | | * Since we now check for this overflow and log when it |
1266 | | * happens, we're now in a better place to easily see |
1267 | | * what's going on and perhaps better choices can be made. |
1268 | | */ |
1269 | | |
1270 | | /* Do we need to log the size of the overflow? */ |
1271 | 0 | msyslog(LOG_ERR, "Palisade(%d) praecis_parse(): input buffer overflow", |
1272 | 0 | up->unit); |
1273 | |
|
1274 | 0 | p = 0; |
1275 | 0 | praecis_msg = 0; |
1276 | |
|
1277 | 0 | refclock_report(peer, CEVNT_BADREPLY); |
1278 | |
|
1279 | 0 | return; |
1280 | 0 | } |
1281 | | |
1282 | 0 | memcpy(buf+p, rbufp->recv_buffer, rbufp->recv_length); |
1283 | 0 | p += rbufp->recv_length; |
1284 | |
|
1285 | 0 | if ( p >= 2 |
1286 | 0 | && buf[p-2] == '\r' |
1287 | 0 | && buf[p-1] == '\n') { |
1288 | 0 | buf[p-2] = '\0'; |
1289 | 0 | record_clock_stats(&peer->srcadr, buf); |
1290 | |
|
1291 | 0 | p = 0; |
1292 | 0 | praecis_msg = 0; |
1293 | |
|
1294 | 0 | if (HW_poll(pp) < 0) { |
1295 | 0 | refclock_report(peer, CEVNT_FAULT); |
1296 | 0 | } |
1297 | 0 | } |
1298 | 0 | return; |
1299 | 0 | } |
1300 | | |
1301 | | static void |
1302 | | palisade_io ( |
1303 | | struct recvbuf *rbufp |
1304 | | ) |
1305 | 0 | { |
1306 | | /* |
1307 | | * Initialize pointers and read the timecode and timestamp. |
1308 | | */ |
1309 | 0 | struct palisade_unit *up; |
1310 | 0 | struct refclockproc *pp; |
1311 | 0 | struct peer *peer; |
1312 | |
|
1313 | 0 | char * c, * d; |
1314 | |
|
1315 | 0 | peer = rbufp->recv_peer; |
1316 | 0 | pp = peer->procptr; |
1317 | 0 | up = pp->unitptr; |
1318 | |
|
1319 | 0 | if(up->type == CLK_PRAECIS) { |
1320 | 0 | if(praecis_msg) { |
1321 | 0 | praecis_parse(rbufp,peer); |
1322 | 0 | return; |
1323 | 0 | } |
1324 | 0 | } |
1325 | | |
1326 | 0 | c = (char *) &rbufp->recv_space; |
1327 | 0 | d = c + rbufp->recv_length; |
1328 | | |
1329 | 0 | while (c != d) { |
1330 | | |
1331 | | /* Build time packet */ |
1332 | 0 | switch (up->rpt_status) { |
1333 | | |
1334 | 0 | case TSIP_PARSED_DLE_1: |
1335 | 0 | switch (*c) |
1336 | 0 | { |
1337 | 0 | case 0: |
1338 | 0 | case DLE: |
1339 | 0 | case ETX: |
1340 | 0 | up->rpt_status = TSIP_PARSED_EMPTY; |
1341 | 0 | break; |
1342 | | |
1343 | 0 | default: |
1344 | 0 | up->rpt_status = TSIP_PARSED_DATA; |
1345 | | /* save packet ID */ |
1346 | 0 | up->rpt_buf[0] = *c; |
1347 | 0 | break; |
1348 | 0 | } |
1349 | 0 | break; |
1350 | | |
1351 | 0 | case TSIP_PARSED_DATA: |
1352 | 0 | if (*c == DLE) |
1353 | 0 | up->rpt_status = TSIP_PARSED_DLE_2; |
1354 | 0 | else |
1355 | 0 | mb(up->rpt_cnt++) = *c; |
1356 | 0 | break; |
1357 | | |
1358 | 0 | case TSIP_PARSED_DLE_2: |
1359 | 0 | if (*c == DLE) { |
1360 | 0 | up->rpt_status = TSIP_PARSED_DATA; |
1361 | 0 | mb(up->rpt_cnt++) = |
1362 | 0 | *c; |
1363 | 0 | } |
1364 | 0 | else if (*c == ETX) |
1365 | 0 | up->rpt_status = TSIP_PARSED_FULL; |
1366 | 0 | else { |
1367 | | /* error: start new report packet */ |
1368 | 0 | up->rpt_status = TSIP_PARSED_DLE_1; |
1369 | 0 | up->rpt_buf[0] = *c; |
1370 | 0 | } |
1371 | 0 | break; |
1372 | | |
1373 | 0 | case TSIP_PARSED_FULL: |
1374 | 0 | case TSIP_PARSED_EMPTY: |
1375 | 0 | default: |
1376 | 0 | if ( *c != DLE) |
1377 | 0 | up->rpt_status = TSIP_PARSED_EMPTY; |
1378 | 0 | else |
1379 | 0 | up->rpt_status = TSIP_PARSED_DLE_1; |
1380 | 0 | break; |
1381 | 0 | } |
1382 | | |
1383 | 0 | c++; |
1384 | |
|
1385 | 0 | if (up->rpt_status == TSIP_PARSED_DLE_1) { |
1386 | 0 | up->rpt_cnt = 0; |
1387 | 0 | if (pp->sloppyclockflag & CLK_FLAG2) |
1388 | | /* stamp it */ |
1389 | 0 | get_systime(&pp->lastrec); |
1390 | 0 | } |
1391 | 0 | else if (up->rpt_status == TSIP_PARSED_EMPTY) |
1392 | 0 | up->rpt_cnt = 0; |
1393 | | |
1394 | 0 | else if (up->rpt_cnt > BMAX) |
1395 | 0 | up->rpt_status =TSIP_PARSED_EMPTY; |
1396 | |
|
1397 | 0 | if (up->rpt_status == TSIP_PARSED_FULL) |
1398 | 0 | palisade_receive(peer); |
1399 | |
|
1400 | 0 | } /* while chars in buffer */ |
1401 | 0 | } |
1402 | | |
1403 | | |
1404 | | /* |
1405 | | * Trigger the Palisade's event input, which is driven off the RTS |
1406 | | * |
1407 | | * Take a system time stamp to match the GPS time stamp. |
1408 | | * |
1409 | | */ |
1410 | | long |
1411 | | HW_poll ( |
1412 | | struct refclockproc * pp /* pointer to unit structure */ |
1413 | | ) |
1414 | 0 | { |
1415 | 0 | int x; /* state before & after RTS set */ |
1416 | 0 | struct palisade_unit *up; |
1417 | 0 | struct packettx tx; |
1418 | |
|
1419 | 0 | up = pp->unitptr; |
1420 | |
|
1421 | 0 | if (up->type == CLK_ACE) { |
1422 | | /* Poll by sending a 0x21 command */ |
1423 | 0 | tx.size = 0; |
1424 | 0 | tx.data = (u_char *) emalloc(100); |
1425 | 0 | sendcmd (&tx, 0x21); |
1426 | 0 | sendetx (&tx, pp->io.fd); |
1427 | 0 | free(tx.data); |
1428 | 0 | } else { |
1429 | | |
1430 | | /* read the current status, so we put things back right */ |
1431 | 0 | if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { |
1432 | 0 | DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n", |
1433 | 0 | up->unit)); |
1434 | 0 | msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", |
1435 | 0 | up->unit); |
1436 | 0 | return -1; |
1437 | 0 | } |
1438 | | |
1439 | 0 | x |= TIOCM_RTS; /* turn on RTS */ |
1440 | | |
1441 | | /* Edge trigger */ |
1442 | 0 | if (up->type == CLK_ACUTIME) |
1443 | 0 | if (write (pp->io.fd, "", 1) != 1) |
1444 | 0 | msyslog(LOG_WARNING, |
1445 | 0 | "Palisade(%d) HW_poll: failed to send trigger: %m", |
1446 | 0 | up->unit); |
1447 | | |
1448 | 0 | if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { |
1449 | 0 | #ifdef DEBUG |
1450 | 0 | if (debug) |
1451 | 0 | printf("Palisade HW_poll: unit %d: SET \n", up->unit); |
1452 | 0 | #endif |
1453 | 0 | msyslog(LOG_ERR, |
1454 | 0 | "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", |
1455 | 0 | up->unit); |
1456 | 0 | return -1; |
1457 | 0 | } |
1458 | | |
1459 | 0 | x &= ~TIOCM_RTS; /* turn off RTS */ |
1460 | | |
1461 | 0 | } /* (up->type != CLK_ACE) */ |
1462 | | |
1463 | | /* poll timestamp */ |
1464 | 0 | get_systime(&pp->lastrec); |
1465 | |
|
1466 | 0 | if (up->type != CLK_ACE) { |
1467 | 0 | if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { |
1468 | 0 | #ifdef DEBUG |
1469 | 0 | if (debug) |
1470 | 0 | printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); |
1471 | 0 | #endif |
1472 | 0 | msyslog(LOG_ERR, |
1473 | 0 | "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", |
1474 | 0 | up->unit); |
1475 | 0 | return -1; |
1476 | 0 | } |
1477 | 0 | } |
1478 | | |
1479 | 0 | return 0; |
1480 | 0 | } |
1481 | | |
1482 | | /* |
1483 | | * copy/swap a big-endian palisade double into a host double |
1484 | | */ |
1485 | | static double |
1486 | | getdbl ( |
1487 | | u_char *bp |
1488 | | ) |
1489 | 0 | { |
1490 | | #ifdef WORDS_BIGENDIAN |
1491 | | double out; |
1492 | | |
1493 | | memcpy(&out, bp, sizeof(out)); |
1494 | | return out; |
1495 | | #else |
1496 | 0 | union { |
1497 | 0 | u_char ch[8]; |
1498 | 0 | u_int32 u32[2]; |
1499 | 0 | } ui; |
1500 | | |
1501 | 0 | union { |
1502 | 0 | double out; |
1503 | 0 | u_int32 u32[2]; |
1504 | 0 | } uo; |
1505 | |
|
1506 | 0 | memcpy(ui.ch, bp, sizeof(ui.ch)); |
1507 | | /* least-significant 32 bits of double from swapped bp[4] to bp[7] */ |
1508 | 0 | uo.u32[0] = ntohl(ui.u32[1]); |
1509 | | /* most-significant 32 bits from swapped bp[0] to bp[3] */ |
1510 | 0 | uo.u32[1] = ntohl(ui.u32[0]); |
1511 | |
|
1512 | 0 | return uo.out; |
1513 | 0 | #endif |
1514 | 0 | } |
1515 | | |
1516 | | /* |
1517 | | * copy/swap a big-endian palisade short into a host short |
1518 | | */ |
1519 | | static short |
1520 | | getint ( |
1521 | | u_char *bp |
1522 | | ) |
1523 | 0 | { |
1524 | 0 | u_short us; |
1525 | |
|
1526 | 0 | memcpy(&us, bp, sizeof(us)); |
1527 | 0 | return (short)ntohs(us); |
1528 | 0 | } |
1529 | | |
1530 | | /* |
1531 | | * copy/swap a big-endian palisade 32-bit int into a host 32-bit int |
1532 | | */ |
1533 | | static int32 |
1534 | | getlong( |
1535 | | u_char *bp |
1536 | | ) |
1537 | 0 | { |
1538 | 0 | u_int32 u32; |
1539 | |
|
1540 | 0 | memcpy(&u32, bp, sizeof(u32)); |
1541 | 0 | return (int32)(u_int32)ntohl(u32); |
1542 | 0 | } |
1543 | | |
1544 | | /* |
1545 | | * copy/swap a big-endian 32-bit single-precision floating point into a host 32-bit int |
1546 | | */ |
1547 | | static int32 |
1548 | | getsingle( |
1549 | | u_char *bp |
1550 | | ) |
1551 | 0 | { |
1552 | 0 | u_int32 mantissa; |
1553 | 0 | int8_t exponent; |
1554 | 0 | uint8_t sign, exp_field; |
1555 | 0 | int32 res; |
1556 | |
|
1557 | 0 | memcpy(&mantissa, bp, sizeof(mantissa)); |
1558 | 0 | mantissa = ((u_int32)ntohl(mantissa) & 0x7FFFFF) | 0x800000; |
1559 | 0 | exp_field = ((uint8_t)bp[0] << 1) + ((uint8_t)bp[1] >> 7); |
1560 | 0 | exponent = (int8_t)exp_field - 127; |
1561 | 0 | sign = ((uint8_t)bp[0] >> 7); |
1562 | 0 | if (exponent > 23) |
1563 | 0 | res = (int32)(mantissa << (exponent - 23)); |
1564 | 0 | else |
1565 | 0 | res = (int32)(mantissa >> (23 - exponent)); |
1566 | 0 | return sign ? -res : res; |
1567 | 0 | } |
1568 | | |
1569 | | #else /* REFCLOCK && CLOCK_PALISADE*/ |
1570 | | NONEMPTY_TRANSLATION_UNIT |
1571 | | #endif |