1/* 2 * refclock_wwvb - clock driver for Spectracom WWVB receivers 3 */ 4 5#ifdef HAVE_CONFIG_H 6#include <config.h> 7#endif 8 9#if defined(REFCLOCK) && defined(CLOCK_SPECTRACOM) 10 11#include "ntpd.h" 12#include "ntp_io.h" 13#include "ntp_refclock.h" 14#include "ntp_calendar.h" 15#include "ntp_stdlib.h" 16 17#include <stdio.h> 18#include <ctype.h> 19 20/* 21 * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB 22 * Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB 23 * and GPS clocks have proven reliable sources of time; however, the 24 * WWVB clocks have proven vulnerable to high ambient conductive RF 25 * interference. The claimed accuracy of the WWVB clocks is 100 us 26 * relative to the broadcast signal, while the claimed accuracy of the 27 * GPS clock is 50 ns; however, in most cases the actual accuracy is 28 * limited by the resolution of the timecode and the latencies of the 29 * serial interface and operating system. 30 * 31 * The WWVB and GPS clocks should be configured for 24-hour display, 32 * AUTO DST off, time zone 0 (UTC), data format 0 or 2 (see below) and 33 * baud rate 9600. If the clock is to used as the source for the IRIG 34 * Audio Decoder (refclock_irig.c in this distribution), it should be 35 * configured for AM IRIG output and IRIG format 1 (IRIG B with 36 * signature control). The GPS clock can be configured either to respond 37 * to a 'T' poll character or left running continuously. 38 * 39 * There are two timecode formats used by these clocks. Format 0, which 40 * is available with both the Netclock/2 and 8170, and format 2, which 41 * is available only with the Netclock/2, specially modified 8170 and 42 * GPS. 43 * 44 * Format 0 (22 ASCII printing characters): 45 * 46 * <cr><lf>i ddd hh:mm:ss TZ=zz<cr><lf> 47 * 48 * on-time = first <cr> 49 * hh:mm:ss = hours, minutes, seconds 50 * i = synchronization flag (' ' = in synch, '?' = out of synch) 51 * 52 * The alarm condition is indicated by other than ' ' at a, which occurs 53 * during initial synchronization and when received signal is lost for 54 * about ten hours. 55 * 56 * Format 2 (24 ASCII printing characters): 57 * 58 * <cr><lf>iqyy ddd hh:mm:ss.fff ld 59 * 60 * on-time = <cr> 61 * i = synchronization flag (' ' = in synch, '?' = out of synch) 62 * q = quality indicator (' ' = locked, 'A'...'D' = unlocked) 63 * yy = year (as broadcast) 64 * ddd = day of year 65 * hh:mm:ss.fff = hours, minutes, seconds, milliseconds 66 * 67 * The alarm condition is indicated by other than ' ' at a, which occurs 68 * during initial synchronization and when received signal is lost for 69 * about ten hours. The unlock condition is indicated by other than ' ' 70 * at q. 71 * 72 * The q is normally ' ' when the time error is less than 1 ms and a 73 * character in the set 'A'...'D' when the time error is less than 10, 74 * 100, 500 and greater than 500 ms respectively. The l is normally ' ', 75 * but is set to 'L' early in the month of an upcoming UTC leap second 76 * and reset to ' ' on the first day of the following month. The d is 77 * set to 'S' for standard time 'I' on the day preceding a switch to 78 * daylight time, 'D' for daylight time and 'O' on the day preceding a 79 * switch to standard time. The start bit of the first <cr> is 80 * synchronized to the indicated time as returned. 81 * 82 * This driver does not need to be told which format is in use - it 83 * figures out which one from the length of the message.The driver makes 84 * no attempt to correct for the intrinsic jitter of the radio itself, 85 * which is a known problem with the older radios. 86 * 87 * Fudge Factors 88 * 89 * This driver can retrieve a table of quality data maintained 90 * internally by the Netclock/2 clock. If flag4 of the fudge 91 * configuration command is set to 1, the driver will retrieve this 92 * table and write it to the clockstats file on when the first timecode 93 * message of a new day is received. 94 */ 95 96/* 97 * Interface definitions 98 */ 99#define DEVICE "/dev/wwvb%d" /* device name and unit */ 100#define SPEED232 B9600 /* uart speed (9600 baud) */ 101#define PRECISION (-13) /* precision assumed (about 100 us) */ 102#define REFID "WWVB" /* reference ID */ 103#define DESCRIPTION "Spectracom WWVB/GPS Receivers" /* WRU */ 104 105#define LENWWVB0 22 /* format 0 timecode length */
| 1/* 2 * refclock_wwvb - clock driver for Spectracom WWVB receivers 3 */ 4 5#ifdef HAVE_CONFIG_H 6#include <config.h> 7#endif 8 9#if defined(REFCLOCK) && defined(CLOCK_SPECTRACOM) 10 11#include "ntpd.h" 12#include "ntp_io.h" 13#include "ntp_refclock.h" 14#include "ntp_calendar.h" 15#include "ntp_stdlib.h" 16 17#include <stdio.h> 18#include <ctype.h> 19 20/* 21 * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB 22 * Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB 23 * and GPS clocks have proven reliable sources of time; however, the 24 * WWVB clocks have proven vulnerable to high ambient conductive RF 25 * interference. The claimed accuracy of the WWVB clocks is 100 us 26 * relative to the broadcast signal, while the claimed accuracy of the 27 * GPS clock is 50 ns; however, in most cases the actual accuracy is 28 * limited by the resolution of the timecode and the latencies of the 29 * serial interface and operating system. 30 * 31 * The WWVB and GPS clocks should be configured for 24-hour display, 32 * AUTO DST off, time zone 0 (UTC), data format 0 or 2 (see below) and 33 * baud rate 9600. If the clock is to used as the source for the IRIG 34 * Audio Decoder (refclock_irig.c in this distribution), it should be 35 * configured for AM IRIG output and IRIG format 1 (IRIG B with 36 * signature control). The GPS clock can be configured either to respond 37 * to a 'T' poll character or left running continuously. 38 * 39 * There are two timecode formats used by these clocks. Format 0, which 40 * is available with both the Netclock/2 and 8170, and format 2, which 41 * is available only with the Netclock/2, specially modified 8170 and 42 * GPS. 43 * 44 * Format 0 (22 ASCII printing characters): 45 * 46 * <cr><lf>i ddd hh:mm:ss TZ=zz<cr><lf> 47 * 48 * on-time = first <cr> 49 * hh:mm:ss = hours, minutes, seconds 50 * i = synchronization flag (' ' = in synch, '?' = out of synch) 51 * 52 * The alarm condition is indicated by other than ' ' at a, which occurs 53 * during initial synchronization and when received signal is lost for 54 * about ten hours. 55 * 56 * Format 2 (24 ASCII printing characters): 57 * 58 * <cr><lf>iqyy ddd hh:mm:ss.fff ld 59 * 60 * on-time = <cr> 61 * i = synchronization flag (' ' = in synch, '?' = out of synch) 62 * q = quality indicator (' ' = locked, 'A'...'D' = unlocked) 63 * yy = year (as broadcast) 64 * ddd = day of year 65 * hh:mm:ss.fff = hours, minutes, seconds, milliseconds 66 * 67 * The alarm condition is indicated by other than ' ' at a, which occurs 68 * during initial synchronization and when received signal is lost for 69 * about ten hours. The unlock condition is indicated by other than ' ' 70 * at q. 71 * 72 * The q is normally ' ' when the time error is less than 1 ms and a 73 * character in the set 'A'...'D' when the time error is less than 10, 74 * 100, 500 and greater than 500 ms respectively. The l is normally ' ', 75 * but is set to 'L' early in the month of an upcoming UTC leap second 76 * and reset to ' ' on the first day of the following month. The d is 77 * set to 'S' for standard time 'I' on the day preceding a switch to 78 * daylight time, 'D' for daylight time and 'O' on the day preceding a 79 * switch to standard time. The start bit of the first <cr> is 80 * synchronized to the indicated time as returned. 81 * 82 * This driver does not need to be told which format is in use - it 83 * figures out which one from the length of the message.The driver makes 84 * no attempt to correct for the intrinsic jitter of the radio itself, 85 * which is a known problem with the older radios. 86 * 87 * Fudge Factors 88 * 89 * This driver can retrieve a table of quality data maintained 90 * internally by the Netclock/2 clock. If flag4 of the fudge 91 * configuration command is set to 1, the driver will retrieve this 92 * table and write it to the clockstats file on when the first timecode 93 * message of a new day is received. 94 */ 95 96/* 97 * Interface definitions 98 */ 99#define DEVICE "/dev/wwvb%d" /* device name and unit */ 100#define SPEED232 B9600 /* uart speed (9600 baud) */ 101#define PRECISION (-13) /* precision assumed (about 100 us) */ 102#define REFID "WWVB" /* reference ID */ 103#define DESCRIPTION "Spectracom WWVB/GPS Receivers" /* WRU */ 104 105#define LENWWVB0 22 /* format 0 timecode length */
|
| 106#define LENWWVB1 22 /* format 1 timecode length */
|
106#define LENWWVB2 24 /* format 2 timecode length */ 107#define LENWWVB3 29 /* format 3 timecode length */ 108#define MONLIN 15 /* number of monitoring lines */ 109 110/* 111 * WWVB unit control structure 112 */ 113struct wwvbunit { 114 u_char tcswitch; /* timecode switch */ 115 l_fp laststamp; /* last receive timestamp */ 116 u_char lasthour; /* last hour (for monitor) */ 117 u_char linect; /* count ignored lines (for monitor */ 118}; 119 120/* 121 * Function prototypes 122 */ 123static int wwvb_start P((int, struct peer *)); 124static void wwvb_shutdown P((int, struct peer *)); 125static void wwvb_receive P((struct recvbuf *)); 126static void wwvb_poll P((int, struct peer *)); 127 128/* 129 * Transfer vector 130 */ 131struct refclock refclock_wwvb = { 132 wwvb_start, /* start up driver */ 133 wwvb_shutdown, /* shut down driver */ 134 wwvb_poll, /* transmit poll message */ 135 noentry, /* not used (old wwvb_control) */ 136 noentry, /* initialize driver (not used) */ 137 noentry, /* not used (old wwvb_buginfo) */ 138 NOFLAGS /* not used */ 139}; 140 141 142/* 143 * wwvb_start - open the devices and initialize data for processing 144 */ 145static int 146wwvb_start( 147 int unit, 148 struct peer *peer 149 ) 150{ 151 register struct wwvbunit *up; 152 struct refclockproc *pp; 153 int fd; 154 char device[20]; 155 156 /* 157 * Open serial port. Use CLK line discipline, if available. 158 */ 159 (void)sprintf(device, DEVICE, unit); 160 if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) 161 return (0); 162 163 /* 164 * Allocate and initialize unit structure 165 */ 166 if (!(up = (struct wwvbunit *) 167 emalloc(sizeof(struct wwvbunit)))) { 168 (void) close(fd); 169 return (0); 170 } 171 memset((char *)up, 0, sizeof(struct wwvbunit)); 172 pp = peer->procptr; 173 pp->unitptr = (caddr_t)up; 174 pp->io.clock_recv = wwvb_receive; 175 pp->io.srcclock = (caddr_t)peer; 176 pp->io.datalen = 0; 177 pp->io.fd = fd; 178 if (!io_addclock(&pp->io)) { 179 (void) close(fd); 180 free(up); 181 return (0); 182 } 183 184 /* 185 * Initialize miscellaneous variables 186 */ 187 peer->precision = PRECISION; 188 pp->clockdesc = DESCRIPTION; 189 memcpy((char *)&pp->refid, REFID, 4);
| 107#define LENWWVB2 24 /* format 2 timecode length */ 108#define LENWWVB3 29 /* format 3 timecode length */ 109#define MONLIN 15 /* number of monitoring lines */ 110 111/* 112 * WWVB unit control structure 113 */ 114struct wwvbunit { 115 u_char tcswitch; /* timecode switch */ 116 l_fp laststamp; /* last receive timestamp */ 117 u_char lasthour; /* last hour (for monitor) */ 118 u_char linect; /* count ignored lines (for monitor */ 119}; 120 121/* 122 * Function prototypes 123 */ 124static int wwvb_start P((int, struct peer *)); 125static void wwvb_shutdown P((int, struct peer *)); 126static void wwvb_receive P((struct recvbuf *)); 127static void wwvb_poll P((int, struct peer *)); 128 129/* 130 * Transfer vector 131 */ 132struct refclock refclock_wwvb = { 133 wwvb_start, /* start up driver */ 134 wwvb_shutdown, /* shut down driver */ 135 wwvb_poll, /* transmit poll message */ 136 noentry, /* not used (old wwvb_control) */ 137 noentry, /* initialize driver (not used) */ 138 noentry, /* not used (old wwvb_buginfo) */ 139 NOFLAGS /* not used */ 140}; 141 142 143/* 144 * wwvb_start - open the devices and initialize data for processing 145 */ 146static int 147wwvb_start( 148 int unit, 149 struct peer *peer 150 ) 151{ 152 register struct wwvbunit *up; 153 struct refclockproc *pp; 154 int fd; 155 char device[20]; 156 157 /* 158 * Open serial port. Use CLK line discipline, if available. 159 */ 160 (void)sprintf(device, DEVICE, unit); 161 if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) 162 return (0); 163 164 /* 165 * Allocate and initialize unit structure 166 */ 167 if (!(up = (struct wwvbunit *) 168 emalloc(sizeof(struct wwvbunit)))) { 169 (void) close(fd); 170 return (0); 171 } 172 memset((char *)up, 0, sizeof(struct wwvbunit)); 173 pp = peer->procptr; 174 pp->unitptr = (caddr_t)up; 175 pp->io.clock_recv = wwvb_receive; 176 pp->io.srcclock = (caddr_t)peer; 177 pp->io.datalen = 0; 178 pp->io.fd = fd; 179 if (!io_addclock(&pp->io)) { 180 (void) close(fd); 181 free(up); 182 return (0); 183 } 184 185 /* 186 * Initialize miscellaneous variables 187 */ 188 peer->precision = PRECISION; 189 pp->clockdesc = DESCRIPTION; 190 memcpy((char *)&pp->refid, REFID, 4);
|
190 peer->burst = NSTAGE;
| 191 peer->burst = MAXSTAGE;
|
191 return (1); 192} 193 194 195/* 196 * wwvb_shutdown - shut down the clock 197 */ 198static void 199wwvb_shutdown( 200 int unit, 201 struct peer *peer 202 ) 203{ 204 register struct wwvbunit *up; 205 struct refclockproc *pp; 206 207 pp = peer->procptr; 208 up = (struct wwvbunit *)pp->unitptr; 209 io_closeclock(&pp->io); 210 free(up); 211} 212 213 214/* 215 * wwvb_receive - receive data from the serial interface 216 */ 217static void 218wwvb_receive( 219 struct recvbuf *rbufp 220 ) 221{ 222 struct wwvbunit *up; 223 struct refclockproc *pp; 224 struct peer *peer; 225 226 l_fp trtmp; /* arrival timestamp */ 227 int tz; /* time zone */ 228 int day, month; /* ddd conversion */ 229 int temp; /* int temp */ 230 char syncchar; /* synchronization indicator */ 231 char qualchar; /* quality indicator */ 232 char leapchar; /* leap indicator */ 233 char dstchar; /* daylight/standard indicator */ 234 char tmpchar; /* trashbin */ 235 236 /* 237 * Initialize pointers and read the timecode and timestamp 238 */ 239 peer = (struct peer *)rbufp->recv_srcclock; 240 pp = peer->procptr; 241 up = (struct wwvbunit *)pp->unitptr; 242 temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); 243 244 /* 245 * Note we get a buffer and timestamp for both a <cr> and <lf>, 246 * but only the <cr> timestamp is retained. Note: in format 0 on 247 * a Netclock/2 or upgraded 8170 the start bit is delayed 100 248 * +-50 us relative to the pps; however, on an unmodified 8170 249 * the start bit can be delayed up to 10 ms. In format 2 the 250 * reading precision is only to the millisecond. Thus, unless 251 * you have a pps gadget and don't have to have the year, format 252 * 0 provides the lowest jitter. 253 */ 254 if (temp == 0) { 255 if (up->tcswitch == 0) { 256 up->tcswitch = 1; 257 up->laststamp = trtmp; 258 } else 259 up->tcswitch = 0; 260 return; 261 } 262 pp->lencode = temp; 263 pp->lastrec = up->laststamp; 264 up->laststamp = trtmp; 265 up->tcswitch = 1;
| 192 return (1); 193} 194 195 196/* 197 * wwvb_shutdown - shut down the clock 198 */ 199static void 200wwvb_shutdown( 201 int unit, 202 struct peer *peer 203 ) 204{ 205 register struct wwvbunit *up; 206 struct refclockproc *pp; 207 208 pp = peer->procptr; 209 up = (struct wwvbunit *)pp->unitptr; 210 io_closeclock(&pp->io); 211 free(up); 212} 213 214 215/* 216 * wwvb_receive - receive data from the serial interface 217 */ 218static void 219wwvb_receive( 220 struct recvbuf *rbufp 221 ) 222{ 223 struct wwvbunit *up; 224 struct refclockproc *pp; 225 struct peer *peer; 226 227 l_fp trtmp; /* arrival timestamp */ 228 int tz; /* time zone */ 229 int day, month; /* ddd conversion */ 230 int temp; /* int temp */ 231 char syncchar; /* synchronization indicator */ 232 char qualchar; /* quality indicator */ 233 char leapchar; /* leap indicator */ 234 char dstchar; /* daylight/standard indicator */ 235 char tmpchar; /* trashbin */ 236 237 /* 238 * Initialize pointers and read the timecode and timestamp 239 */ 240 peer = (struct peer *)rbufp->recv_srcclock; 241 pp = peer->procptr; 242 up = (struct wwvbunit *)pp->unitptr; 243 temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); 244 245 /* 246 * Note we get a buffer and timestamp for both a <cr> and <lf>, 247 * but only the <cr> timestamp is retained. Note: in format 0 on 248 * a Netclock/2 or upgraded 8170 the start bit is delayed 100 249 * +-50 us relative to the pps; however, on an unmodified 8170 250 * the start bit can be delayed up to 10 ms. In format 2 the 251 * reading precision is only to the millisecond. Thus, unless 252 * you have a pps gadget and don't have to have the year, format 253 * 0 provides the lowest jitter. 254 */ 255 if (temp == 0) { 256 if (up->tcswitch == 0) { 257 up->tcswitch = 1; 258 up->laststamp = trtmp; 259 } else 260 up->tcswitch = 0; 261 return; 262 } 263 pp->lencode = temp; 264 pp->lastrec = up->laststamp; 265 up->laststamp = trtmp; 266 up->tcswitch = 1;
|
266#ifdef DEBUG 267 if (debug) 268 printf("wwvb: timecode %d %s\n", pp->lencode, 269 pp->a_lastcode); 270#endif
| |
271 272 /* 273 * We get down to business, check the timecode format and decode 274 * its contents. This code uses the timecode length to determine 275 * format 0, 2 or 3. If the timecode has invalid length or is 276 * not in proper format, we declare bad format and exit. 277 */ 278 syncchar = qualchar = leapchar = dstchar = ' '; 279 tz = 0;
| 267 268 /* 269 * We get down to business, check the timecode format and decode 270 * its contents. This code uses the timecode length to determine 271 * format 0, 2 or 3. If the timecode has invalid length or is 272 * not in proper format, we declare bad format and exit. 273 */ 274 syncchar = qualchar = leapchar = dstchar = ' '; 275 tz = 0;
|
280 pp->msec = 0;
| |
281 switch (pp->lencode) { 282
| 276 switch (pp->lencode) { 277
|
283 case LENWWVB0:
| 278 case LENWWVB0:
|
284 285 /* 286 * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" 287 */ 288 if (sscanf(pp->a_lastcode, 289 "%c %3d %2d:%2d:%2d%c%cTZ=%2d", 290 &syncchar, &pp->day, &pp->hour, &pp->minute, 291 &pp->second, &tmpchar, &dstchar, &tz) == 8)
| 279 280 /* 281 * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" 282 */ 283 if (sscanf(pp->a_lastcode, 284 "%c %3d %2d:%2d:%2d%c%cTZ=%2d", 285 &syncchar, &pp->day, &pp->hour, &pp->minute, 286 &pp->second, &tmpchar, &dstchar, &tz) == 8)
|
| 287 pp->nsec = 0;
|
292 break; 293
| 288 break; 289
|
294 case LENWWVB2:
| 290 case LENWWVB2:
|
295 296 /* 297 * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */ 298 if (sscanf(pp->a_lastcode,
| 291 292 /* 293 * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */ 294 if (sscanf(pp->a_lastcode,
|
299 "%c%c %2d %3d %2d:%2d:%2d.%3d %c",
| 295 "%c%c %2d %3d %2d:%2d:%2d.%3ld %c",
|
300 &syncchar, &qualchar, &pp->year, &pp->day,
| 296 &syncchar, &qualchar, &pp->year, &pp->day,
|
301 &pp->hour, &pp->minute, &pp->second, &pp->msec,
| 297 &pp->hour, &pp->minute, &pp->second, &pp->nsec,
|
302 &leapchar) == 9)
| 298 &leapchar) == 9)
|
| 299 pp->nsec *= 1000000;
|
303 break; 304
| 300 break; 301
|
305 case LENWWVB3:
| 302 case LENWWVB3:
|
306 307 /* 308 * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#" 309 */ 310 if (sscanf(pp->a_lastcode, 311 "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c", 312 &syncchar, &pp->year, &month, &day, &pp->hour, 313 &pp->minute, &pp->second, &dstchar, &leapchar) == 8) 314 { 315 pp->day = ymd2yd(pp->year, month, day);
| 303 304 /* 305 * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#" 306 */ 307 if (sscanf(pp->a_lastcode, 308 "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c", 309 &syncchar, &pp->year, &month, &day, &pp->hour, 310 &pp->minute, &pp->second, &dstchar, &leapchar) == 8) 311 { 312 pp->day = ymd2yd(pp->year, month, day);
|
| 313 pp->nsec = 0;
|
316 break; 317 } 318
| 314 break; 315 } 316
|
319 default:
| 317 default:
|
320 321 /* 322 * Unknown format: If dumping internal table, record 323 * stats; otherwise, declare bad format. 324 */ 325 if (up->linect > 0) { 326 up->linect--; 327 record_clock_stats(&peer->srcadr, 328 pp->a_lastcode); 329 } else { 330 refclock_report(peer, CEVNT_BADREPLY); 331 } 332 return; 333 } 334 335 /* 336 * Decode synchronization, quality and leap characters. If 337 * unsynchronized, set the leap bits accordingly and exit. 338 * Otherwise, set the leap bits according to the leap character. 339 * Once synchronized, the dispersion depends only on the 340 * quality character. 341 */ 342 switch (qualchar) { 343 344 case ' ': 345 pp->disp = .001;
| 318 319 /* 320 * Unknown format: If dumping internal table, record 321 * stats; otherwise, declare bad format. 322 */ 323 if (up->linect > 0) { 324 up->linect--; 325 record_clock_stats(&peer->srcadr, 326 pp->a_lastcode); 327 } else { 328 refclock_report(peer, CEVNT_BADREPLY); 329 } 330 return; 331 } 332 333 /* 334 * Decode synchronization, quality and leap characters. If 335 * unsynchronized, set the leap bits accordingly and exit. 336 * Otherwise, set the leap bits according to the leap character. 337 * Once synchronized, the dispersion depends only on the 338 * quality character. 339 */ 340 switch (qualchar) { 341 342 case ' ': 343 pp->disp = .001;
|
| 344 pp->lastref = pp->lastrec;
|
346 break; 347 348 case 'A': 349 pp->disp = .01; 350 break; 351 352 case 'B': 353 pp->disp = .1; 354 break; 355 356 case 'C': 357 pp->disp = .5; 358 break; 359 360 case 'D': 361 pp->disp = MAXDISPERSE; 362 break; 363 364 default: 365 pp->disp = MAXDISPERSE; 366 refclock_report(peer, CEVNT_BADREPLY); 367 break; 368 } 369 if (syncchar != ' ') 370 pp->leap = LEAP_NOTINSYNC; 371 else if (leapchar == 'L') 372 pp->leap = LEAP_ADDSECOND; 373 else 374 pp->leap = LEAP_NOWARNING; 375 376 /* 377 * Process the new sample in the median filter and determine the 378 * timecode timestamp. 379 */ 380 if (!refclock_process(pp)) 381 refclock_report(peer, CEVNT_BADTIME); 382} 383 384 385/* 386 * wwvb_poll - called by the transmit procedure 387 */ 388static void 389wwvb_poll( 390 int unit, 391 struct peer *peer 392 ) 393{ 394 register struct wwvbunit *up; 395 struct refclockproc *pp; 396 char pollchar; /* character sent to clock */ 397 398 /* 399 * Time to poll the clock. The Spectracom clock responds to a 400 * 'T' by returning a timecode in the format(s) specified above. 401 * Note there is no checking on state, since this may not be the 402 * only customer reading the clock. Only one customer need poll 403 * the clock; all others just listen in. If the clock becomes 404 * unreachable, declare a timeout and keep going. 405 */ 406 pp = peer->procptr; 407 up = (struct wwvbunit *)pp->unitptr; 408 if (up->linect > 0) 409 pollchar = 'R'; 410 else 411 pollchar = 'T'; 412 if (write(pp->io.fd, &pollchar, 1) != 1) 413 refclock_report(peer, CEVNT_FAULT);
| 345 break; 346 347 case 'A': 348 pp->disp = .01; 349 break; 350 351 case 'B': 352 pp->disp = .1; 353 break; 354 355 case 'C': 356 pp->disp = .5; 357 break; 358 359 case 'D': 360 pp->disp = MAXDISPERSE; 361 break; 362 363 default: 364 pp->disp = MAXDISPERSE; 365 refclock_report(peer, CEVNT_BADREPLY); 366 break; 367 } 368 if (syncchar != ' ') 369 pp->leap = LEAP_NOTINSYNC; 370 else if (leapchar == 'L') 371 pp->leap = LEAP_ADDSECOND; 372 else 373 pp->leap = LEAP_NOWARNING; 374 375 /* 376 * Process the new sample in the median filter and determine the 377 * timecode timestamp. 378 */ 379 if (!refclock_process(pp)) 380 refclock_report(peer, CEVNT_BADTIME); 381} 382 383 384/* 385 * wwvb_poll - called by the transmit procedure 386 */ 387static void 388wwvb_poll( 389 int unit, 390 struct peer *peer 391 ) 392{ 393 register struct wwvbunit *up; 394 struct refclockproc *pp; 395 char pollchar; /* character sent to clock */ 396 397 /* 398 * Time to poll the clock. The Spectracom clock responds to a 399 * 'T' by returning a timecode in the format(s) specified above. 400 * Note there is no checking on state, since this may not be the 401 * only customer reading the clock. Only one customer need poll 402 * the clock; all others just listen in. If the clock becomes 403 * unreachable, declare a timeout and keep going. 404 */ 405 pp = peer->procptr; 406 up = (struct wwvbunit *)pp->unitptr; 407 if (up->linect > 0) 408 pollchar = 'R'; 409 else 410 pollchar = 'T'; 411 if (write(pp->io.fd, &pollchar, 1) != 1) 412 refclock_report(peer, CEVNT_FAULT);
|
414 else 415 pp->polls++;
| |
416 if (peer->burst > 0) 417 return; 418 if (pp->coderecv == pp->codeproc) { 419 refclock_report(peer, CEVNT_TIMEOUT); 420 return; 421 }
| 413 if (peer->burst > 0) 414 return; 415 if (pp->coderecv == pp->codeproc) { 416 refclock_report(peer, CEVNT_TIMEOUT); 417 return; 418 }
|
422 record_clock_stats(&peer->srcadr, pp->a_lastcode);
| |
423 refclock_receive(peer);
| 419 refclock_receive(peer);
|
424 peer->burst = NSTAGE;
| 420 record_clock_stats(&peer->srcadr, pp->a_lastcode); 421#ifdef DEBUG 422 if (debug) 423 printf("wwvb: timecode %d %s\n", pp->lencode, 424 pp->a_lastcode); 425#endif 426 peer->burst = MAXSTAGE; 427 pp->polls++;
|
425 426 /* 427 * If the monitor flag is set (flag4), we dump the internal 428 * quality table at the first timecode beginning the day. 429 */ 430 if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour < 431 (int)up->lasthour) 432 up->linect = MONLIN; 433 up->lasthour = pp->hour; 434} 435 436#else 437int refclock_wwvb_bs; 438#endif /* REFCLOCK */
| 428 429 /* 430 * If the monitor flag is set (flag4), we dump the internal 431 * quality table at the first timecode beginning the day. 432 */ 433 if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour < 434 (int)up->lasthour) 435 up->linect = MONLIN; 436 up->lasthour = pp->hour; 437} 438 439#else 440int refclock_wwvb_bs; 441#endif /* REFCLOCK */
|