dcfd.c revision 1.1 1 1.1 kardel /* $NetBSD: dcfd.c,v 1.1 2009/12/13 16:56:35 kardel Exp $ */
2 1.1 kardel
3 1.1 kardel /*
4 1.1 kardel * /src/NTP/REPOSITORY/ntp4-dev/parseutil/dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A
5 1.1 kardel *
6 1.1 kardel * dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A
7 1.1 kardel *
8 1.1 kardel * DCF77 100/200ms pulse synchronisation daemon program (via 50Baud serial line)
9 1.1 kardel *
10 1.1 kardel * Features:
11 1.1 kardel * DCF77 decoding
12 1.1 kardel * simple NTP loopfilter logic for local clock
13 1.1 kardel * interactive display for debugging
14 1.1 kardel *
15 1.1 kardel * Lacks:
16 1.1 kardel * Leap second handling (at that level you should switch to NTP Version 4 - really!)
17 1.1 kardel *
18 1.1 kardel * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
19 1.1 kardel * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitt Erlangen-Nrnberg, Germany
20 1.1 kardel *
21 1.1 kardel * Redistribution and use in source and binary forms, with or without
22 1.1 kardel * modification, are permitted provided that the following conditions
23 1.1 kardel * are met:
24 1.1 kardel * 1. Redistributions of source code must retain the above copyright
25 1.1 kardel * notice, this list of conditions and the following disclaimer.
26 1.1 kardel * 2. Redistributions in binary form must reproduce the above copyright
27 1.1 kardel * notice, this list of conditions and the following disclaimer in the
28 1.1 kardel * documentation and/or other materials provided with the distribution.
29 1.1 kardel * 3. Neither the name of the author nor the names of its contributors
30 1.1 kardel * may be used to endorse or promote products derived from this software
31 1.1 kardel * without specific prior written permission.
32 1.1 kardel *
33 1.1 kardel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34 1.1 kardel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 1.1 kardel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 1.1 kardel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37 1.1 kardel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 1.1 kardel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 1.1 kardel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 1.1 kardel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 1.1 kardel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 1.1 kardel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 1.1 kardel * SUCH DAMAGE.
44 1.1 kardel *
45 1.1 kardel */
46 1.1 kardel
47 1.1 kardel #ifdef HAVE_CONFIG_H
48 1.1 kardel # include <config.h>
49 1.1 kardel #endif
50 1.1 kardel
51 1.1 kardel #include <sys/ioctl.h>
52 1.1 kardel #include <unistd.h>
53 1.1 kardel #include <stdio.h>
54 1.1 kardel #include <fcntl.h>
55 1.1 kardel #include <sys/types.h>
56 1.1 kardel #include <sys/time.h>
57 1.1 kardel #include <signal.h>
58 1.1 kardel #include <syslog.h>
59 1.1 kardel #include <time.h>
60 1.1 kardel
61 1.1 kardel /*
62 1.1 kardel * NTP compilation environment
63 1.1 kardel */
64 1.1 kardel #include "ntp_stdlib.h"
65 1.1 kardel #include "ntpd.h" /* indirectly include ntp.h to get YEAR_PIVOT Y2KFixes */
66 1.1 kardel
67 1.1 kardel /*
68 1.1 kardel * select which terminal handling to use (currently only SysV variants)
69 1.1 kardel */
70 1.1 kardel #if defined(HAVE_TERMIOS_H) || defined(STREAM)
71 1.1 kardel #include <termios.h>
72 1.1 kardel #define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
73 1.1 kardel #define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
74 1.1 kardel #else /* not HAVE_TERMIOS_H || STREAM */
75 1.1 kardel # if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS)
76 1.1 kardel # include <termio.h>
77 1.1 kardel # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
78 1.1 kardel # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
79 1.1 kardel # endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */
80 1.1 kardel #endif /* not HAVE_TERMIOS_H || STREAM */
81 1.1 kardel
82 1.1 kardel
83 1.1 kardel #ifndef TTY_GETATTR
84 1.1 kardel #include "Bletch: MUST DEFINE ONE OF 'HAVE_TERMIOS_H' or 'HAVE_TERMIO_H'"
85 1.1 kardel #endif
86 1.1 kardel
87 1.1 kardel #ifndef days_per_year
88 1.1 kardel #define days_per_year(_x_) (((_x_) % 4) ? 365 : (((_x_) % 400) ? 365 : 366))
89 1.1 kardel #endif
90 1.1 kardel
91 1.1 kardel #define timernormalize(_a_) \
92 1.1 kardel if ((_a_)->tv_usec >= 1000000) \
93 1.1 kardel { \
94 1.1 kardel (_a_)->tv_sec += (_a_)->tv_usec / 1000000; \
95 1.1 kardel (_a_)->tv_usec = (_a_)->tv_usec % 1000000; \
96 1.1 kardel } \
97 1.1 kardel if ((_a_)->tv_usec < 0) \
98 1.1 kardel { \
99 1.1 kardel (_a_)->tv_sec -= 1 + (-(_a_)->tv_usec / 1000000); \
100 1.1 kardel (_a_)->tv_usec = 999999 - (-(_a_)->tv_usec - 1); \
101 1.1 kardel }
102 1.1 kardel
103 1.1 kardel #ifdef timeradd
104 1.1 kardel #undef timeradd
105 1.1 kardel #endif
106 1.1 kardel #define timeradd(_a_, _b_) \
107 1.1 kardel (_a_)->tv_sec += (_b_)->tv_sec; \
108 1.1 kardel (_a_)->tv_usec += (_b_)->tv_usec; \
109 1.1 kardel timernormalize((_a_))
110 1.1 kardel
111 1.1 kardel #ifdef timersub
112 1.1 kardel #undef timersub
113 1.1 kardel #endif
114 1.1 kardel #define timersub(_a_, _b_) \
115 1.1 kardel (_a_)->tv_sec -= (_b_)->tv_sec; \
116 1.1 kardel (_a_)->tv_usec -= (_b_)->tv_usec; \
117 1.1 kardel timernormalize((_a_))
118 1.1 kardel
119 1.1 kardel /*
120 1.1 kardel * debug macros
121 1.1 kardel */
122 1.1 kardel #define PRINTF if (interactive) printf
123 1.1 kardel #define LPRINTF if (interactive && loop_filter_debug) printf
124 1.1 kardel
125 1.1 kardel #ifdef DEBUG
126 1.1 kardel #define dprintf(_x_) LPRINTF _x_
127 1.1 kardel #else
128 1.1 kardel #define dprintf(_x_)
129 1.1 kardel #endif
130 1.1 kardel
131 1.1 kardel #ifdef DECL_ERRNO
132 1.1 kardel extern int errno;
133 1.1 kardel #endif
134 1.1 kardel
135 1.1 kardel static char *revision = "4.18";
136 1.1 kardel
137 1.1 kardel /*
138 1.1 kardel * display received data (avoids also detaching from tty)
139 1.1 kardel */
140 1.1 kardel static int interactive = 0;
141 1.1 kardel
142 1.1 kardel /*
143 1.1 kardel * display loopfilter (clock control) variables
144 1.1 kardel */
145 1.1 kardel static int loop_filter_debug = 0;
146 1.1 kardel
147 1.1 kardel /*
148 1.1 kardel * do not set/adjust system time
149 1.1 kardel */
150 1.1 kardel static int no_set = 0;
151 1.1 kardel
152 1.1 kardel /*
153 1.1 kardel * time that passes between start of DCF impulse and time stamping (fine
154 1.1 kardel * adjustment) in microseconds (receiver/OS dependent)
155 1.1 kardel */
156 1.1 kardel #define DEFAULT_DELAY 230000 /* rough estimate */
157 1.1 kardel
158 1.1 kardel /*
159 1.1 kardel * The two states we can be in - eithe we receive nothing
160 1.1 kardel * usable or we have the correct time
161 1.1 kardel */
162 1.1 kardel #define NO_SYNC 0x01
163 1.1 kardel #define SYNC 0x02
164 1.1 kardel
165 1.1 kardel static int sync_state = NO_SYNC;
166 1.1 kardel static time_t last_sync;
167 1.1 kardel
168 1.1 kardel static unsigned long ticks = 0;
169 1.1 kardel
170 1.1 kardel static char pat[] = "-\\|/";
171 1.1 kardel
172 1.1 kardel #define LINES (24-2) /* error lines after which the two headlines are repeated */
173 1.1 kardel
174 1.1 kardel #define MAX_UNSYNC (10*60) /* allow synchronisation loss for 10 minutes */
175 1.1 kardel #define NOTICE_INTERVAL (20*60) /* mention missing synchronisation every 20 minutes */
176 1.1 kardel
177 1.1 kardel /*
178 1.1 kardel * clock adjustment PLL - see NTP protocol spec (RFC1305) for details
179 1.1 kardel */
180 1.1 kardel
181 1.1 kardel #define USECSCALE 10
182 1.1 kardel #define TIMECONSTANT 2
183 1.1 kardel #define ADJINTERVAL 0
184 1.1 kardel #define FREQ_WEIGHT 18
185 1.1 kardel #define PHASE_WEIGHT 7
186 1.1 kardel #define MAX_DRIFT 0x3FFFFFFF
187 1.1 kardel
188 1.1 kardel #define R_SHIFT(_X_, _Y_) (((_X_) < 0) ? -(-(_X_) >> (_Y_)) : ((_X_) >> (_Y_)))
189 1.1 kardel
190 1.1 kardel static long max_adj_offset_usec = 128000;
191 1.1 kardel
192 1.1 kardel static long clock_adjust = 0; /* current adjustment value (usec * 2^USECSCALE) */
193 1.1 kardel static long accum_drift = 0; /* accumulated drift value (usec / ADJINTERVAL) */
194 1.1 kardel static long adjustments = 0;
195 1.1 kardel static char skip_adjust = 1; /* discard first adjustment (bad samples) */
196 1.1 kardel
197 1.1 kardel /*
198 1.1 kardel * DCF77 state flags
199 1.1 kardel */
200 1.1 kardel #define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */
201 1.1 kardel #define DCFB_DST 0x0002 /* DST in effect */
202 1.1 kardel #define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurrence) */
203 1.1 kardel #define DCFB_ALTERNATE 0x0008 /* alternate antenna used */
204 1.1 kardel
205 1.1 kardel struct clocktime /* clock time broken up from time code */
206 1.1 kardel {
207 1.1 kardel long wday; /* Day of week: 1: Monday - 7: Sunday */
208 1.1 kardel long day;
209 1.1 kardel long month;
210 1.1 kardel long year;
211 1.1 kardel long hour;
212 1.1 kardel long minute;
213 1.1 kardel long second;
214 1.1 kardel long usecond;
215 1.1 kardel long utcoffset; /* in minutes */
216 1.1 kardel long flags; /* current clock status (DCF77 state flags) */
217 1.1 kardel };
218 1.1 kardel
219 1.1 kardel typedef struct clocktime clocktime_t;
220 1.1 kardel
221 1.1 kardel /*
222 1.1 kardel * (usually) quick constant multiplications
223 1.1 kardel */
224 1.1 kardel #define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) /* *8 + *2 */
225 1.1 kardel #define TIMES24(_X_) (((_X_) << 4) + ((_X_) << 3)) /* *16 + *8 */
226 1.1 kardel #define TIMES60(_X_) ((((_X_) << 4) - (_X_)) << 2) /* *(16 - 1) *4 */
227 1.1 kardel /*
228 1.1 kardel * generic l_abs() function
229 1.1 kardel */
230 1.1 kardel #define l_abs(_x_) (((_x_) < 0) ? -(_x_) : (_x_))
231 1.1 kardel
232 1.1 kardel /*
233 1.1 kardel * conversion related return/error codes
234 1.1 kardel */
235 1.1 kardel #define CVT_MASK 0x0000000F /* conversion exit code */
236 1.1 kardel #define CVT_NONE 0x00000001 /* format not applicable */
237 1.1 kardel #define CVT_FAIL 0x00000002 /* conversion failed - error code returned */
238 1.1 kardel #define CVT_OK 0x00000004 /* conversion succeeded */
239 1.1 kardel #define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */
240 1.1 kardel #define CVT_BADDATE 0x00000020 /* invalid date */
241 1.1 kardel #define CVT_BADTIME 0x00000040 /* invalid time */
242 1.1 kardel
243 1.1 kardel /*
244 1.1 kardel * DCF77 raw time code
245 1.1 kardel *
246 1.1 kardel * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
247 1.1 kardel * und Berlin, Maerz 1989
248 1.1 kardel *
249 1.1 kardel * Timecode transmission:
250 1.1 kardel * AM:
251 1.1 kardel * time marks are send every second except for the second before the
252 1.1 kardel * next minute mark
253 1.1 kardel * time marks consist of a reduction of transmitter power to 25%
254 1.1 kardel * of the nominal level
255 1.1 kardel * the falling edge is the time indication (on time)
256 1.1 kardel * time marks of a 100ms duration constitute a logical 0
257 1.1 kardel * time marks of a 200ms duration constitute a logical 1
258 1.1 kardel * FM:
259 1.1 kardel * see the spec. (basically a (non-)inverted psuedo random phase shift)
260 1.1 kardel *
261 1.1 kardel * Encoding:
262 1.1 kardel * Second Contents
263 1.1 kardel * 0 - 10 AM: free, FM: 0
264 1.1 kardel * 11 - 14 free
265 1.1 kardel * 15 R - alternate antenna
266 1.1 kardel * 16 A1 - expect zone change (1 hour before)
267 1.1 kardel * 17 - 18 Z1,Z2 - time zone
268 1.1 kardel * 0 0 illegal
269 1.1 kardel * 0 1 MEZ (MET)
270 1.1 kardel * 1 0 MESZ (MED, MET DST)
271 1.1 kardel * 1 1 illegal
272 1.1 kardel * 19 A2 - expect leap insertion/deletion (1 hour before)
273 1.1 kardel * 20 S - start of time code (1)
274 1.1 kardel * 21 - 24 M1 - BCD (lsb first) Minutes
275 1.1 kardel * 25 - 27 M10 - BCD (lsb first) 10 Minutes
276 1.1 kardel * 28 P1 - Minute Parity (even)
277 1.1 kardel * 29 - 32 H1 - BCD (lsb first) Hours
278 1.1 kardel * 33 - 34 H10 - BCD (lsb first) 10 Hours
279 1.1 kardel * 35 P2 - Hour Parity (even)
280 1.1 kardel * 36 - 39 D1 - BCD (lsb first) Days
281 1.1 kardel * 40 - 41 D10 - BCD (lsb first) 10 Days
282 1.1 kardel * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday)
283 1.1 kardel * 45 - 49 MO - BCD (lsb first) Month
284 1.1 kardel * 50 MO0 - 10 Months
285 1.1 kardel * 51 - 53 Y1 - BCD (lsb first) Years
286 1.1 kardel * 54 - 57 Y10 - BCD (lsb first) 10 Years
287 1.1 kardel * 58 P3 - Date Parity (even)
288 1.1 kardel * 59 - usually missing (minute indication), except for leap insertion
289 1.1 kardel */
290 1.1 kardel
291 1.1 kardel /*-----------------------------------------------------------------------
292 1.1 kardel * conversion table to map DCF77 bit stream into data fields.
293 1.1 kardel * Encoding:
294 1.1 kardel * Each field of the DCF77 code is described with two adjacent entries in
295 1.1 kardel * this table. The first entry specifies the offset into the DCF77 data stream
296 1.1 kardel * while the length is given as the difference between the start index and
297 1.1 kardel * the start index of the following field.
298 1.1 kardel */
299 1.1 kardel static struct rawdcfcode
300 1.1 kardel {
301 1.1 kardel char offset; /* start bit */
302 1.1 kardel } rawdcfcode[] =
303 1.1 kardel {
304 1.1 kardel { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 },
305 1.1 kardel { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 }
306 1.1 kardel };
307 1.1 kardel
308 1.1 kardel /*-----------------------------------------------------------------------
309 1.1 kardel * symbolic names for the fields of DCF77 describes in "rawdcfcode".
310 1.1 kardel * see comment above for the structure of the DCF77 data
311 1.1 kardel */
312 1.1 kardel #define DCF_M 0
313 1.1 kardel #define DCF_R 1
314 1.1 kardel #define DCF_A1 2
315 1.1 kardel #define DCF_Z 3
316 1.1 kardel #define DCF_A2 4
317 1.1 kardel #define DCF_S 5
318 1.1 kardel #define DCF_M1 6
319 1.1 kardel #define DCF_M10 7
320 1.1 kardel #define DCF_P1 8
321 1.1 kardel #define DCF_H1 9
322 1.1 kardel #define DCF_H10 10
323 1.1 kardel #define DCF_P2 11
324 1.1 kardel #define DCF_D1 12
325 1.1 kardel #define DCF_D10 13
326 1.1 kardel #define DCF_DW 14
327 1.1 kardel #define DCF_MO 15
328 1.1 kardel #define DCF_MO0 16
329 1.1 kardel #define DCF_Y1 17
330 1.1 kardel #define DCF_Y10 18
331 1.1 kardel #define DCF_P3 19
332 1.1 kardel
333 1.1 kardel /*-----------------------------------------------------------------------
334 1.1 kardel * parity field table (same encoding as rawdcfcode)
335 1.1 kardel * This table describes the sections of the DCF77 code that are
336 1.1 kardel * parity protected
337 1.1 kardel */
338 1.1 kardel static struct partab
339 1.1 kardel {
340 1.1 kardel char offset; /* start bit of parity field */
341 1.1 kardel } partab[] =
342 1.1 kardel {
343 1.1 kardel { 21 }, { 29 }, { 36 }, { 59 }
344 1.1 kardel };
345 1.1 kardel
346 1.1 kardel /*-----------------------------------------------------------------------
347 1.1 kardel * offsets for parity field descriptions
348 1.1 kardel */
349 1.1 kardel #define DCF_P_P1 0
350 1.1 kardel #define DCF_P_P2 1
351 1.1 kardel #define DCF_P_P3 2
352 1.1 kardel
353 1.1 kardel /*-----------------------------------------------------------------------
354 1.1 kardel * legal values for time zone information
355 1.1 kardel */
356 1.1 kardel #define DCF_Z_MET 0x2
357 1.1 kardel #define DCF_Z_MED 0x1
358 1.1 kardel
359 1.1 kardel /*-----------------------------------------------------------------------
360 1.1 kardel * symbolic representation if the DCF77 data stream
361 1.1 kardel */
362 1.1 kardel static struct dcfparam
363 1.1 kardel {
364 1.1 kardel unsigned char onebits[60];
365 1.1 kardel unsigned char zerobits[60];
366 1.1 kardel } dcfparam =
367 1.1 kardel {
368 1.1 kardel "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */
369 1.1 kardel "--------------------s-------p------p----------------------p" /* 'ZERO' representation */
370 1.1 kardel };
371 1.1 kardel
372 1.1 kardel /*-----------------------------------------------------------------------
373 1.1 kardel * extract a bitfield from DCF77 datastream
374 1.1 kardel * All numeric fields are LSB first.
375 1.1 kardel * buf holds a pointer to a DCF77 data buffer in symbolic
376 1.1 kardel * representation
377 1.1 kardel * idx holds the index to the field description in rawdcfcode
378 1.1 kardel */
379 1.1 kardel static unsigned long
380 1.1 kardel ext_bf(
381 1.1 kardel register unsigned char *buf,
382 1.1 kardel register int idx
383 1.1 kardel )
384 1.1 kardel {
385 1.1 kardel register unsigned long sum = 0;
386 1.1 kardel register int i, first;
387 1.1 kardel
388 1.1 kardel first = rawdcfcode[idx].offset;
389 1.1 kardel
390 1.1 kardel for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--)
391 1.1 kardel {
392 1.1 kardel sum <<= 1;
393 1.1 kardel sum |= (buf[i] != dcfparam.zerobits[i]);
394 1.1 kardel }
395 1.1 kardel return sum;
396 1.1 kardel }
397 1.1 kardel
398 1.1 kardel /*-----------------------------------------------------------------------
399 1.1 kardel * check even parity integrity for a bitfield
400 1.1 kardel *
401 1.1 kardel * buf holds a pointer to a DCF77 data buffer in symbolic
402 1.1 kardel * representation
403 1.1 kardel * idx holds the index to the field description in partab
404 1.1 kardel */
405 1.1 kardel static unsigned
406 1.1 kardel pcheck(
407 1.1 kardel register unsigned char *buf,
408 1.1 kardel register int idx
409 1.1 kardel )
410 1.1 kardel {
411 1.1 kardel register int i,last;
412 1.1 kardel register unsigned psum = 1;
413 1.1 kardel
414 1.1 kardel last = partab[idx+1].offset;
415 1.1 kardel
416 1.1 kardel for (i = partab[idx].offset; i < last; i++)
417 1.1 kardel psum ^= (buf[i] != dcfparam.zerobits[i]);
418 1.1 kardel
419 1.1 kardel return psum;
420 1.1 kardel }
421 1.1 kardel
422 1.1 kardel /*-----------------------------------------------------------------------
423 1.1 kardel * convert a DCF77 data buffer into wall clock time + flags
424 1.1 kardel *
425 1.1 kardel * buffer holds a pointer to a DCF77 data buffer in symbolic
426 1.1 kardel * representation
427 1.1 kardel * size describes the length of DCF77 information in bits (represented
428 1.1 kardel * as chars in symbolic notation
429 1.1 kardel * clock points to a wall clock time description of the DCF77 data (result)
430 1.1 kardel */
431 1.1 kardel static unsigned long
432 1.1 kardel convert_rawdcf(
433 1.1 kardel unsigned char *buffer,
434 1.1 kardel int size,
435 1.1 kardel clocktime_t *clock_time
436 1.1 kardel )
437 1.1 kardel {
438 1.1 kardel if (size < 57)
439 1.1 kardel {
440 1.1 kardel PRINTF("%-30s", "*** INCOMPLETE");
441 1.1 kardel return CVT_NONE;
442 1.1 kardel }
443 1.1 kardel
444 1.1 kardel /*
445 1.1 kardel * check Start and Parity bits
446 1.1 kardel */
447 1.1 kardel if ((ext_bf(buffer, DCF_S) == 1) &&
448 1.1 kardel pcheck(buffer, DCF_P_P1) &&
449 1.1 kardel pcheck(buffer, DCF_P_P2) &&
450 1.1 kardel pcheck(buffer, DCF_P_P3))
451 1.1 kardel {
452 1.1 kardel /*
453 1.1 kardel * buffer OK - extract all fields and build wall clock time from them
454 1.1 kardel */
455 1.1 kardel
456 1.1 kardel clock_time->flags = 0;
457 1.1 kardel clock_time->usecond= 0;
458 1.1 kardel clock_time->second = 0;
459 1.1 kardel clock_time->minute = ext_bf(buffer, DCF_M10);
460 1.1 kardel clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1);
461 1.1 kardel clock_time->hour = ext_bf(buffer, DCF_H10);
462 1.1 kardel clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1);
463 1.1 kardel clock_time->day = ext_bf(buffer, DCF_D10);
464 1.1 kardel clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1);
465 1.1 kardel clock_time->month = ext_bf(buffer, DCF_MO0);
466 1.1 kardel clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO);
467 1.1 kardel clock_time->year = ext_bf(buffer, DCF_Y10);
468 1.1 kardel clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1);
469 1.1 kardel clock_time->wday = ext_bf(buffer, DCF_DW);
470 1.1 kardel
471 1.1 kardel /*
472 1.1 kardel * determine offset to UTC by examining the time zone
473 1.1 kardel */
474 1.1 kardel switch (ext_bf(buffer, DCF_Z))
475 1.1 kardel {
476 1.1 kardel case DCF_Z_MET:
477 1.1 kardel clock_time->utcoffset = -60;
478 1.1 kardel break;
479 1.1 kardel
480 1.1 kardel case DCF_Z_MED:
481 1.1 kardel clock_time->flags |= DCFB_DST;
482 1.1 kardel clock_time->utcoffset = -120;
483 1.1 kardel break;
484 1.1 kardel
485 1.1 kardel default:
486 1.1 kardel PRINTF("%-30s", "*** BAD TIME ZONE");
487 1.1 kardel return CVT_FAIL|CVT_BADFMT;
488 1.1 kardel }
489 1.1 kardel
490 1.1 kardel /*
491 1.1 kardel * extract various warnings from DCF77
492 1.1 kardel */
493 1.1 kardel if (ext_bf(buffer, DCF_A1))
494 1.1 kardel clock_time->flags |= DCFB_ANNOUNCE;
495 1.1 kardel
496 1.1 kardel if (ext_bf(buffer, DCF_A2))
497 1.1 kardel clock_time->flags |= DCFB_LEAP;
498 1.1 kardel
499 1.1 kardel if (ext_bf(buffer, DCF_R))
500 1.1 kardel clock_time->flags |= DCFB_ALTERNATE;
501 1.1 kardel
502 1.1 kardel return CVT_OK;
503 1.1 kardel }
504 1.1 kardel else
505 1.1 kardel {
506 1.1 kardel /*
507 1.1 kardel * bad format - not for us
508 1.1 kardel */
509 1.1 kardel PRINTF("%-30s", "*** BAD FORMAT (invalid/parity)");
510 1.1 kardel return CVT_FAIL|CVT_BADFMT;
511 1.1 kardel }
512 1.1 kardel }
513 1.1 kardel
514 1.1 kardel /*-----------------------------------------------------------------------
515 1.1 kardel * raw dcf input routine - fix up 50 baud
516 1.1 kardel * characters for 1/0 decision
517 1.1 kardel */
518 1.1 kardel static unsigned long
519 1.1 kardel cvt_rawdcf(
520 1.1 kardel unsigned char *buffer,
521 1.1 kardel int size,
522 1.1 kardel clocktime_t *clock_time
523 1.1 kardel )
524 1.1 kardel {
525 1.1 kardel register unsigned char *s = buffer;
526 1.1 kardel register unsigned char *e = buffer + size;
527 1.1 kardel register unsigned char *b = dcfparam.onebits;
528 1.1 kardel register unsigned char *c = dcfparam.zerobits;
529 1.1 kardel register unsigned rtc = CVT_NONE;
530 1.1 kardel register unsigned int i, lowmax, highmax, cutoff, span;
531 1.1 kardel #define BITS 9
532 1.1 kardel unsigned char histbuf[BITS];
533 1.1 kardel /*
534 1.1 kardel * the input buffer contains characters with runs of consecutive
535 1.1 kardel * bits set. These set bits are an indication of the DCF77 pulse
536 1.1 kardel * length. We assume that we receive the pulse at 50 Baud. Thus
537 1.1 kardel * a 100ms pulse would generate a 4 bit train (20ms per bit and
538 1.1 kardel * start bit)
539 1.1 kardel * a 200ms pulse would create all zeroes (and probably a frame error)
540 1.1 kardel *
541 1.1 kardel * The basic idea is that on corret reception we must have two
542 1.1 kardel * maxima in the pulse length distribution histogram. (one for
543 1.1 kardel * the zero representing pulses and one for the one representing
544 1.1 kardel * pulses)
545 1.1 kardel * There will always be ones in the datastream, thus we have to see
546 1.1 kardel * two maxima.
547 1.1 kardel * The best point to cut for a 1/0 decision is the minimum between those
548 1.1 kardel * between the maxima. The following code tries to find this cutoff point.
549 1.1 kardel */
550 1.1 kardel
551 1.1 kardel /*
552 1.1 kardel * clear histogram buffer
553 1.1 kardel */
554 1.1 kardel for (i = 0; i < BITS; i++)
555 1.1 kardel {
556 1.1 kardel histbuf[i] = 0;
557 1.1 kardel }
558 1.1 kardel
559 1.1 kardel cutoff = 0;
560 1.1 kardel lowmax = 0;
561 1.1 kardel
562 1.1 kardel /*
563 1.1 kardel * convert sequences of set bits into bits counts updating
564 1.1 kardel * the histogram alongway
565 1.1 kardel */
566 1.1 kardel while (s < e)
567 1.1 kardel {
568 1.1 kardel register unsigned int ch = *s ^ 0xFF;
569 1.1 kardel /*
570 1.1 kardel * check integrity and update histogramm
571 1.1 kardel */
572 1.1 kardel if (!((ch+1) & ch) || !*s)
573 1.1 kardel {
574 1.1 kardel /*
575 1.1 kardel * character ok
576 1.1 kardel */
577 1.1 kardel for (i = 0; ch; i++)
578 1.1 kardel {
579 1.1 kardel ch >>= 1;
580 1.1 kardel }
581 1.1 kardel
582 1.1 kardel *s = i;
583 1.1 kardel histbuf[i]++;
584 1.1 kardel cutoff += i;
585 1.1 kardel lowmax++;
586 1.1 kardel }
587 1.1 kardel else
588 1.1 kardel {
589 1.1 kardel /*
590 1.1 kardel * invalid character (no consecutive bit sequence)
591 1.1 kardel */
592 1.1 kardel dprintf(("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer));
593 1.1 kardel *s = (unsigned char)~0;
594 1.1 kardel rtc = CVT_FAIL|CVT_BADFMT;
595 1.1 kardel }
596 1.1 kardel s++;
597 1.1 kardel }
598 1.1 kardel
599 1.1 kardel /*
600 1.1 kardel * first cutoff estimate (average bit count - must be between both
601 1.1 kardel * maxima)
602 1.1 kardel */
603 1.1 kardel if (lowmax)
604 1.1 kardel {
605 1.1 kardel cutoff /= lowmax;
606 1.1 kardel }
607 1.1 kardel else
608 1.1 kardel {
609 1.1 kardel cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */
610 1.1 kardel }
611 1.1 kardel
612 1.1 kardel dprintf(("parse: cvt_rawdcf: average bit count: %d\n", cutoff));
613 1.1 kardel
614 1.1 kardel lowmax = 0; /* weighted sum */
615 1.1 kardel highmax = 0; /* bitcount */
616 1.1 kardel
617 1.1 kardel /*
618 1.1 kardel * collect weighted sum of lower bits (left of initial guess)
619 1.1 kardel */
620 1.1 kardel dprintf(("parse: cvt_rawdcf: histogram:"));
621 1.1 kardel for (i = 0; i <= cutoff; i++)
622 1.1 kardel {
623 1.1 kardel lowmax += histbuf[i] * i;
624 1.1 kardel highmax += histbuf[i];
625 1.1 kardel dprintf((" %d", histbuf[i]));
626 1.1 kardel }
627 1.1 kardel dprintf((" <M>"));
628 1.1 kardel
629 1.1 kardel /*
630 1.1 kardel * round up
631 1.1 kardel */
632 1.1 kardel lowmax += highmax / 2;
633 1.1 kardel
634 1.1 kardel /*
635 1.1 kardel * calculate lower bit maximum (weighted sum / bit count)
636 1.1 kardel *
637 1.1 kardel * avoid divide by zero
638 1.1 kardel */
639 1.1 kardel if (highmax)
640 1.1 kardel {
641 1.1 kardel lowmax /= highmax;
642 1.1 kardel }
643 1.1 kardel else
644 1.1 kardel {
645 1.1 kardel lowmax = 0;
646 1.1 kardel }
647 1.1 kardel
648 1.1 kardel highmax = 0; /* weighted sum of upper bits counts */
649 1.1 kardel cutoff = 0; /* bitcount */
650 1.1 kardel
651 1.1 kardel /*
652 1.1 kardel * collect weighted sum of lower bits (right of initial guess)
653 1.1 kardel */
654 1.1 kardel for (; i < BITS; i++)
655 1.1 kardel {
656 1.1 kardel highmax+=histbuf[i] * i;
657 1.1 kardel cutoff +=histbuf[i];
658 1.1 kardel dprintf((" %d", histbuf[i]));
659 1.1 kardel }
660 1.1 kardel dprintf(("\n"));
661 1.1 kardel
662 1.1 kardel /*
663 1.1 kardel * determine upper maximum (weighted sum / bit count)
664 1.1 kardel */
665 1.1 kardel if (cutoff)
666 1.1 kardel {
667 1.1 kardel highmax /= cutoff;
668 1.1 kardel }
669 1.1 kardel else
670 1.1 kardel {
671 1.1 kardel highmax = BITS-1;
672 1.1 kardel }
673 1.1 kardel
674 1.1 kardel /*
675 1.1 kardel * following now holds:
676 1.1 kardel * lowmax <= cutoff(initial guess) <= highmax
677 1.1 kardel * best cutoff is the minimum nearest to higher bits
678 1.1 kardel */
679 1.1 kardel
680 1.1 kardel /*
681 1.1 kardel * find the minimum between lowmax and highmax (detecting
682 1.1 kardel * possibly a minimum span)
683 1.1 kardel */
684 1.1 kardel span = cutoff = lowmax;
685 1.1 kardel for (i = lowmax; i <= highmax; i++)
686 1.1 kardel {
687 1.1 kardel if (histbuf[cutoff] > histbuf[i])
688 1.1 kardel {
689 1.1 kardel /*
690 1.1 kardel * got a new minimum move beginning of minimum (cutoff) and
691 1.1 kardel * end of minimum (span) there
692 1.1 kardel */
693 1.1 kardel cutoff = span = i;
694 1.1 kardel }
695 1.1 kardel else
696 1.1 kardel if (histbuf[cutoff] == histbuf[i])
697 1.1 kardel {
698 1.1 kardel /*
699 1.1 kardel * minimum not better yet - but it spans more than
700 1.1 kardel * one bit value - follow it
701 1.1 kardel */
702 1.1 kardel span = i;
703 1.1 kardel }
704 1.1 kardel }
705 1.1 kardel
706 1.1 kardel /*
707 1.1 kardel * cutoff point for 1/0 decision is the middle of the minimum section
708 1.1 kardel * in the histogram
709 1.1 kardel */
710 1.1 kardel cutoff = (cutoff + span) / 2;
711 1.1 kardel
712 1.1 kardel dprintf(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff));
713 1.1 kardel
714 1.1 kardel /*
715 1.1 kardel * convert the bit counts to symbolic 1/0 information for data conversion
716 1.1 kardel */
717 1.1 kardel s = buffer;
718 1.1 kardel while ((s < e) && *c && *b)
719 1.1 kardel {
720 1.1 kardel if (*s == (unsigned char)~0)
721 1.1 kardel {
722 1.1 kardel /*
723 1.1 kardel * invalid character
724 1.1 kardel */
725 1.1 kardel *s = '?';
726 1.1 kardel }
727 1.1 kardel else
728 1.1 kardel {
729 1.1 kardel /*
730 1.1 kardel * symbolic 1/0 representation
731 1.1 kardel */
732 1.1 kardel *s = (*s >= cutoff) ? *b : *c;
733 1.1 kardel }
734 1.1 kardel s++;
735 1.1 kardel b++;
736 1.1 kardel c++;
737 1.1 kardel }
738 1.1 kardel
739 1.1 kardel /*
740 1.1 kardel * if everything went well so far return the result of the symbolic
741 1.1 kardel * conversion routine else just the accumulated errors
742 1.1 kardel */
743 1.1 kardel if (rtc != CVT_NONE)
744 1.1 kardel {
745 1.1 kardel PRINTF("%-30s", "*** BAD DATA");
746 1.1 kardel }
747 1.1 kardel
748 1.1 kardel return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock_time) : rtc;
749 1.1 kardel }
750 1.1 kardel
751 1.1 kardel /*-----------------------------------------------------------------------
752 1.1 kardel * convert a wall clock time description of DCF77 to a Unix time (seconds
753 1.1 kardel * since 1.1. 1970 UTC)
754 1.1 kardel */
755 1.1 kardel static time_t
756 1.1 kardel dcf_to_unixtime(
757 1.1 kardel clocktime_t *clock_time,
758 1.1 kardel unsigned *cvtrtc
759 1.1 kardel )
760 1.1 kardel {
761 1.1 kardel #define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); }
762 1.1 kardel static int days_of_month[] =
763 1.1 kardel {
764 1.1 kardel 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
765 1.1 kardel };
766 1.1 kardel register int i;
767 1.1 kardel time_t t;
768 1.1 kardel
769 1.1 kardel /*
770 1.1 kardel * map 2 digit years to 19xx (DCF77 is a 20th century item)
771 1.1 kardel */
772 1.1 kardel if ( clock_time->year < YEAR_PIVOT ) /* in case of Y2KFixes [ */
773 1.1 kardel clock_time->year += 100; /* *year%100, make tm_year */
774 1.1 kardel /* *(do we need this?) */
775 1.1 kardel if ( clock_time->year < YEAR_BREAK ) /* (failsafe if) */
776 1.1 kardel clock_time->year += 1900; /* Y2KFixes ] */
777 1.1 kardel
778 1.1 kardel /*
779 1.1 kardel * must have been a really bad year code - drop it
780 1.1 kardel */
781 1.1 kardel if (clock_time->year < (YEAR_PIVOT + 1900) ) /* Y2KFixes */
782 1.1 kardel {
783 1.1 kardel SETRTC(CVT_FAIL|CVT_BADDATE);
784 1.1 kardel return -1;
785 1.1 kardel }
786 1.1 kardel /*
787 1.1 kardel * sorry, slow section here - but it's not time critical anyway
788 1.1 kardel */
789 1.1 kardel
790 1.1 kardel /*
791 1.1 kardel * calculate days since 1970 (watching leap years)
792 1.1 kardel */
793 1.1 kardel t = julian0( clock_time->year ) - julian0( 1970 );
794 1.1 kardel
795 1.1 kardel /* month */
796 1.1 kardel if (clock_time->month <= 0 || clock_time->month > 12)
797 1.1 kardel {
798 1.1 kardel SETRTC(CVT_FAIL|CVT_BADDATE);
799 1.1 kardel return -1; /* bad month */
800 1.1 kardel }
801 1.1 kardel /* adjust current leap year */
802 1.1 kardel #if 0
803 1.1 kardel if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
804 1.1 kardel t--;
805 1.1 kardel #endif
806 1.1 kardel
807 1.1 kardel /*
808 1.1 kardel * collect days from months excluding the current one
809 1.1 kardel */
810 1.1 kardel for (i = 1; i < clock_time->month; i++)
811 1.1 kardel {
812 1.1 kardel t += days_of_month[i];
813 1.1 kardel }
814 1.1 kardel /* day */
815 1.1 kardel if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
816 1.1 kardel clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
817 1.1 kardel {
818 1.1 kardel SETRTC(CVT_FAIL|CVT_BADDATE);
819 1.1 kardel return -1; /* bad day */
820 1.1 kardel }
821 1.1 kardel
822 1.1 kardel /*
823 1.1 kardel * collect days from date excluding the current one
824 1.1 kardel */
825 1.1 kardel t += clock_time->day - 1;
826 1.1 kardel
827 1.1 kardel /* hour */
828 1.1 kardel if (clock_time->hour < 0 || clock_time->hour >= 24)
829 1.1 kardel {
830 1.1 kardel SETRTC(CVT_FAIL|CVT_BADTIME);
831 1.1 kardel return -1; /* bad hour */
832 1.1 kardel }
833 1.1 kardel
834 1.1 kardel /*
835 1.1 kardel * calculate hours from 1. 1. 1970
836 1.1 kardel */
837 1.1 kardel t = TIMES24(t) + clock_time->hour;
838 1.1 kardel
839 1.1 kardel /* min */
840 1.1 kardel if (clock_time->minute < 0 || clock_time->minute > 59)
841 1.1 kardel {
842 1.1 kardel SETRTC(CVT_FAIL|CVT_BADTIME);
843 1.1 kardel return -1; /* bad min */
844 1.1 kardel }
845 1.1 kardel
846 1.1 kardel /*
847 1.1 kardel * calculate minutes from 1. 1. 1970
848 1.1 kardel */
849 1.1 kardel t = TIMES60(t) + clock_time->minute;
850 1.1 kardel /* sec */
851 1.1 kardel
852 1.1 kardel /*
853 1.1 kardel * calculate UTC in minutes
854 1.1 kardel */
855 1.1 kardel t += clock_time->utcoffset;
856 1.1 kardel
857 1.1 kardel if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */
858 1.1 kardel {
859 1.1 kardel SETRTC(CVT_FAIL|CVT_BADTIME);
860 1.1 kardel return -1; /* bad sec */
861 1.1 kardel }
862 1.1 kardel
863 1.1 kardel /*
864 1.1 kardel * calculate UTC in seconds - phew !
865 1.1 kardel */
866 1.1 kardel t = TIMES60(t) + clock_time->second;
867 1.1 kardel /* done */
868 1.1 kardel return t;
869 1.1 kardel }
870 1.1 kardel
871 1.1 kardel /*-----------------------------------------------------------------------
872 1.1 kardel * cheap half baked 1/0 decision - for interactive operation only
873 1.1 kardel */
874 1.1 kardel static char
875 1.1 kardel type(
876 1.1 kardel unsigned int c
877 1.1 kardel )
878 1.1 kardel {
879 1.1 kardel c ^= 0xFF;
880 1.1 kardel return (c > 0xF);
881 1.1 kardel }
882 1.1 kardel
883 1.1 kardel /*-----------------------------------------------------------------------
884 1.1 kardel * week day representation
885 1.1 kardel */
886 1.1 kardel static const char *wday[8] =
887 1.1 kardel {
888 1.1 kardel "??",
889 1.1 kardel "Mo",
890 1.1 kardel "Tu",
891 1.1 kardel "We",
892 1.1 kardel "Th",
893 1.1 kardel "Fr",
894 1.1 kardel "Sa",
895 1.1 kardel "Su"
896 1.1 kardel };
897 1.1 kardel
898 1.1 kardel /*-----------------------------------------------------------------------
899 1.1 kardel * generate a string representation for a timeval
900 1.1 kardel */
901 1.1 kardel static char *
902 1.1 kardel pr_timeval(
903 1.1 kardel struct timeval *val
904 1.1 kardel )
905 1.1 kardel {
906 1.1 kardel static char buf[20];
907 1.1 kardel
908 1.1 kardel if (val->tv_sec == 0)
909 1.1 kardel sprintf(buf, "%c0.%06ld", (val->tv_usec < 0) ? '-' : '+', (long int)l_abs(val->tv_usec));
910 1.1 kardel else
911 1.1 kardel sprintf(buf, "%ld.%06ld", (long int)val->tv_sec, (long int)l_abs(val->tv_usec));
912 1.1 kardel return buf;
913 1.1 kardel }
914 1.1 kardel
915 1.1 kardel /*-----------------------------------------------------------------------
916 1.1 kardel * correct the current time by an offset by setting the time rigorously
917 1.1 kardel */
918 1.1 kardel static void
919 1.1 kardel set_time(
920 1.1 kardel struct timeval *offset
921 1.1 kardel )
922 1.1 kardel {
923 1.1 kardel struct timeval the_time;
924 1.1 kardel
925 1.1 kardel if (no_set)
926 1.1 kardel return;
927 1.1 kardel
928 1.1 kardel LPRINTF("set_time: %s ", pr_timeval(offset));
929 1.1 kardel syslog(LOG_NOTICE, "setting time (offset %s)", pr_timeval(offset));
930 1.1 kardel
931 1.1 kardel if (gettimeofday(&the_time, 0L) == -1)
932 1.1 kardel {
933 1.1 kardel perror("gettimeofday()");
934 1.1 kardel }
935 1.1 kardel else
936 1.1 kardel {
937 1.1 kardel timeradd(&the_time, offset);
938 1.1 kardel if (settimeofday(&the_time, 0L) == -1)
939 1.1 kardel {
940 1.1 kardel perror("settimeofday()");
941 1.1 kardel }
942 1.1 kardel }
943 1.1 kardel }
944 1.1 kardel
945 1.1 kardel /*-----------------------------------------------------------------------
946 1.1 kardel * slew the time by a given offset
947 1.1 kardel */
948 1.1 kardel static void
949 1.1 kardel adj_time(
950 1.1 kardel long offset
951 1.1 kardel )
952 1.1 kardel {
953 1.1 kardel struct timeval time_offset;
954 1.1 kardel
955 1.1 kardel if (no_set)
956 1.1 kardel return;
957 1.1 kardel
958 1.1 kardel time_offset.tv_sec = offset / 1000000;
959 1.1 kardel time_offset.tv_usec = offset % 1000000;
960 1.1 kardel
961 1.1 kardel LPRINTF("adj_time: %ld us ", (long int)offset);
962 1.1 kardel if (adjtime(&time_offset, 0L) == -1)
963 1.1 kardel perror("adjtime()");
964 1.1 kardel }
965 1.1 kardel
966 1.1 kardel /*-----------------------------------------------------------------------
967 1.1 kardel * read in a possibly previously written drift value
968 1.1 kardel */
969 1.1 kardel static void
970 1.1 kardel read_drift(
971 1.1 kardel const char *drift_file
972 1.1 kardel )
973 1.1 kardel {
974 1.1 kardel FILE *df;
975 1.1 kardel
976 1.1 kardel df = fopen(drift_file, "r");
977 1.1 kardel if (df != NULL)
978 1.1 kardel {
979 1.1 kardel int idrift = 0, fdrift = 0;
980 1.1 kardel
981 1.1 kardel fscanf(df, "%4d.%03d", &idrift, &fdrift);
982 1.1 kardel fclose(df);
983 1.1 kardel LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift);
984 1.1 kardel
985 1.1 kardel accum_drift = idrift << USECSCALE;
986 1.1 kardel fdrift = (fdrift << USECSCALE) / 1000;
987 1.1 kardel accum_drift += fdrift & (1<<USECSCALE);
988 1.1 kardel LPRINTF("read_drift: drift_comp %ld ", (long int)accum_drift);
989 1.1 kardel }
990 1.1 kardel }
991 1.1 kardel
992 1.1 kardel /*-----------------------------------------------------------------------
993 1.1 kardel * write out the current drift value
994 1.1 kardel */
995 1.1 kardel static void
996 1.1 kardel update_drift(
997 1.1 kardel const char *drift_file,
998 1.1 kardel long offset,
999 1.1 kardel time_t reftime
1000 1.1 kardel )
1001 1.1 kardel {
1002 1.1 kardel FILE *df;
1003 1.1 kardel
1004 1.1 kardel df = fopen(drift_file, "w");
1005 1.1 kardel if (df != NULL)
1006 1.1 kardel {
1007 1.1 kardel int idrift = R_SHIFT(accum_drift, USECSCALE);
1008 1.1 kardel int fdrift = accum_drift & ((1<<USECSCALE)-1);
1009 1.1 kardel
1010 1.1 kardel LPRINTF("update_drift: drift_comp %ld ", (long int)accum_drift);
1011 1.1 kardel fdrift = (fdrift * 1000) / (1<<USECSCALE);
1012 1.1 kardel fprintf(df, "%4d.%03d %c%ld.%06ld %.24s\n", idrift, fdrift,
1013 1.1 kardel (offset < 0) ? '-' : '+', (long int)(l_abs(offset) / 1000000),
1014 1.1 kardel (long int)(l_abs(offset) % 1000000), asctime(localtime(&reftime)));
1015 1.1 kardel fclose(df);
1016 1.1 kardel LPRINTF("update_drift: %d.%03d ppm ", idrift, fdrift);
1017 1.1 kardel }
1018 1.1 kardel }
1019 1.1 kardel
1020 1.1 kardel /*-----------------------------------------------------------------------
1021 1.1 kardel * process adjustments derived from the DCF77 observation
1022 1.1 kardel * (controls clock PLL)
1023 1.1 kardel */
1024 1.1 kardel static void
1025 1.1 kardel adjust_clock(
1026 1.1 kardel struct timeval *offset,
1027 1.1 kardel const char *drift_file,
1028 1.1 kardel time_t reftime
1029 1.1 kardel )
1030 1.1 kardel {
1031 1.1 kardel struct timeval toffset;
1032 1.1 kardel register long usecoffset;
1033 1.1 kardel int tmp;
1034 1.1 kardel
1035 1.1 kardel if (no_set)
1036 1.1 kardel return;
1037 1.1 kardel
1038 1.1 kardel if (skip_adjust)
1039 1.1 kardel {
1040 1.1 kardel skip_adjust = 0;
1041 1.1 kardel return;
1042 1.1 kardel }
1043 1.1 kardel
1044 1.1 kardel toffset = *offset;
1045 1.1 kardel toffset.tv_sec = l_abs(toffset.tv_sec);
1046 1.1 kardel toffset.tv_usec = l_abs(toffset.tv_usec);
1047 1.1 kardel if (toffset.tv_sec ||
1048 1.1 kardel (!toffset.tv_sec && toffset.tv_usec > max_adj_offset_usec))
1049 1.1 kardel {
1050 1.1 kardel /*
1051 1.1 kardel * hopeless - set the clock - and clear the timing
1052 1.1 kardel */
1053 1.1 kardel set_time(offset);
1054 1.1 kardel clock_adjust = 0;
1055 1.1 kardel skip_adjust = 1;
1056 1.1 kardel return;
1057 1.1 kardel }
1058 1.1 kardel
1059 1.1 kardel usecoffset = offset->tv_sec * 1000000 + offset->tv_usec;
1060 1.1 kardel
1061 1.1 kardel clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT); /* adjustment to make for next period */
1062 1.1 kardel
1063 1.1 kardel tmp = 0;
1064 1.1 kardel while (adjustments > (1 << tmp))
1065 1.1 kardel tmp++;
1066 1.1 kardel adjustments = 0;
1067 1.1 kardel if (tmp > FREQ_WEIGHT)
1068 1.1 kardel tmp = FREQ_WEIGHT;
1069 1.1 kardel
1070 1.1 kardel accum_drift += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp);
1071 1.1 kardel
1072 1.1 kardel if (accum_drift > MAX_DRIFT) /* clamp into interval */
1073 1.1 kardel accum_drift = MAX_DRIFT;
1074 1.1 kardel else
1075 1.1 kardel if (accum_drift < -MAX_DRIFT)
1076 1.1 kardel accum_drift = -MAX_DRIFT;
1077 1.1 kardel
1078 1.1 kardel update_drift(drift_file, usecoffset, reftime);
1079 1.1 kardel LPRINTF("clock_adjust: %s, clock_adjust %ld, drift_comp %ld(%ld) ",
1080 1.1 kardel pr_timeval(offset),(long int) R_SHIFT(clock_adjust, USECSCALE),
1081 1.1 kardel (long int)R_SHIFT(accum_drift, USECSCALE), (long int)accum_drift);
1082 1.1 kardel }
1083 1.1 kardel
1084 1.1 kardel /*-----------------------------------------------------------------------
1085 1.1 kardel * adjust the clock by a small mount to simulate frequency correction
1086 1.1 kardel */
1087 1.1 kardel static void
1088 1.1 kardel periodic_adjust(
1089 1.1 kardel void
1090 1.1 kardel )
1091 1.1 kardel {
1092 1.1 kardel register long adjustment;
1093 1.1 kardel
1094 1.1 kardel adjustments++;
1095 1.1 kardel
1096 1.1 kardel adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT);
1097 1.1 kardel
1098 1.1 kardel clock_adjust -= adjustment;
1099 1.1 kardel
1100 1.1 kardel adjustment += R_SHIFT(accum_drift, USECSCALE+ADJINTERVAL);
1101 1.1 kardel
1102 1.1 kardel adj_time(adjustment);
1103 1.1 kardel }
1104 1.1 kardel
1105 1.1 kardel /*-----------------------------------------------------------------------
1106 1.1 kardel * control synchronisation status (warnings) and do periodic adjusts
1107 1.1 kardel * (frequency control simulation)
1108 1.1 kardel */
1109 1.1 kardel static void
1110 1.1 kardel tick(
1111 1.1 kardel int signum
1112 1.1 kardel )
1113 1.1 kardel {
1114 1.1 kardel static unsigned long last_notice = 0;
1115 1.1 kardel
1116 1.1 kardel #if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC)
1117 1.1 kardel (void)signal(SIGALRM, tick);
1118 1.1 kardel #endif
1119 1.1 kardel
1120 1.1 kardel periodic_adjust();
1121 1.1 kardel
1122 1.1 kardel ticks += 1<<ADJINTERVAL;
1123 1.1 kardel
1124 1.1 kardel if ((ticks - last_sync) > MAX_UNSYNC)
1125 1.1 kardel {
1126 1.1 kardel /*
1127 1.1 kardel * not getting time for a while
1128 1.1 kardel */
1129 1.1 kardel if (sync_state == SYNC)
1130 1.1 kardel {
1131 1.1 kardel /*
1132 1.1 kardel * completely lost information
1133 1.1 kardel */
1134 1.1 kardel sync_state = NO_SYNC;
1135 1.1 kardel syslog(LOG_INFO, "DCF77 reception lost (timeout)");
1136 1.1 kardel last_notice = ticks;
1137 1.1 kardel }
1138 1.1 kardel else
1139 1.1 kardel /*
1140 1.1 kardel * in NO_SYNC state - look whether its time to speak up again
1141 1.1 kardel */
1142 1.1 kardel if ((ticks - last_notice) > NOTICE_INTERVAL)
1143 1.1 kardel {
1144 1.1 kardel syslog(LOG_NOTICE, "still not synchronized to DCF77 - check receiver/signal");
1145 1.1 kardel last_notice = ticks;
1146 1.1 kardel }
1147 1.1 kardel }
1148 1.1 kardel
1149 1.1 kardel #ifndef ITIMER_REAL
1150 1.1 kardel (void) alarm(1<<ADJINTERVAL);
1151 1.1 kardel #endif
1152 1.1 kardel }
1153 1.1 kardel
1154 1.1 kardel /*-----------------------------------------------------------------------
1155 1.1 kardel * break association from terminal to avoid catching terminal
1156 1.1 kardel * or process group related signals (-> daemon operation)
1157 1.1 kardel */
1158 1.1 kardel static void
1159 1.1 kardel detach(
1160 1.1 kardel void
1161 1.1 kardel )
1162 1.1 kardel {
1163 1.1 kardel # ifdef HAVE_DAEMON
1164 1.1 kardel daemon(0, 0);
1165 1.1 kardel # else /* not HAVE_DAEMON */
1166 1.1 kardel if (fork())
1167 1.1 kardel exit(0);
1168 1.1 kardel
1169 1.1 kardel {
1170 1.1 kardel u_long s;
1171 1.1 kardel int max_fd;
1172 1.1 kardel
1173 1.1 kardel #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1174 1.1 kardel max_fd = sysconf(_SC_OPEN_MAX);
1175 1.1 kardel #else /* HAVE_SYSCONF && _SC_OPEN_MAX */
1176 1.1 kardel max_fd = getdtablesize();
1177 1.1 kardel #endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
1178 1.1 kardel for (s = 0; s < max_fd; s++)
1179 1.1 kardel (void) close((int)s);
1180 1.1 kardel (void) open("/", 0);
1181 1.1 kardel (void) dup2(0, 1);
1182 1.1 kardel (void) dup2(0, 2);
1183 1.1 kardel #ifdef SYS_DOMAINOS
1184 1.1 kardel {
1185 1.1 kardel uid_$t puid;
1186 1.1 kardel status_$t st;
1187 1.1 kardel
1188 1.1 kardel proc2_$who_am_i(&puid);
1189 1.1 kardel proc2_$make_server(&puid, &st);
1190 1.1 kardel }
1191 1.1 kardel #endif /* SYS_DOMAINOS */
1192 1.1 kardel #if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
1193 1.1 kardel # ifdef HAVE_SETSID
1194 1.1 kardel if (setsid() == (pid_t)-1)
1195 1.1 kardel syslog(LOG_ERR, "dcfd: setsid(): %m");
1196 1.1 kardel # else
1197 1.1 kardel if (setpgid(0, 0) == -1)
1198 1.1 kardel syslog(LOG_ERR, "dcfd: setpgid(): %m");
1199 1.1 kardel # endif
1200 1.1 kardel #else /* HAVE_SETPGID || HAVE_SETSID */
1201 1.1 kardel {
1202 1.1 kardel int fid;
1203 1.1 kardel
1204 1.1 kardel fid = open("/dev/tty", 2);
1205 1.1 kardel if (fid >= 0)
1206 1.1 kardel {
1207 1.1 kardel (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
1208 1.1 kardel (void) close(fid);
1209 1.1 kardel }
1210 1.1 kardel # ifdef HAVE_SETPGRP_0
1211 1.1 kardel (void) setpgrp();
1212 1.1 kardel # else /* HAVE_SETPGRP_0 */
1213 1.1 kardel (void) setpgrp(0, getpid());
1214 1.1 kardel # endif /* HAVE_SETPGRP_0 */
1215 1.1 kardel }
1216 1.1 kardel #endif /* HAVE_SETPGID || HAVE_SETSID */
1217 1.1 kardel }
1218 1.1 kardel #endif /* not HAVE_DAEMON */
1219 1.1 kardel }
1220 1.1 kardel
1221 1.1 kardel /*-----------------------------------------------------------------------
1222 1.1 kardel * list possible arguments and options
1223 1.1 kardel */
1224 1.1 kardel static void
1225 1.1 kardel usage(
1226 1.1 kardel char *program
1227 1.1 kardel )
1228 1.1 kardel {
1229 1.1 kardel fprintf(stderr, "usage: %s [-n] [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] [-D <input delay>] <device>\n", program);
1230 1.1 kardel fprintf(stderr, "\t-n do not change time\n");
1231 1.1 kardel fprintf(stderr, "\t-i interactive\n");
1232 1.1 kardel fprintf(stderr, "\t-t trace (print all datagrams)\n");
1233 1.1 kardel fprintf(stderr, "\t-f print all databits (includes PTB private data)\n");
1234 1.1 kardel fprintf(stderr, "\t-l print loop filter debug information\n");
1235 1.1 kardel fprintf(stderr, "\t-o print offet average for current minute\n");
1236 1.1 kardel fprintf(stderr, "\t-Y make internal Y2K checks then exit\n"); /* Y2KFixes */
1237 1.1 kardel fprintf(stderr, "\t-d <drift_file> specify alternate drift file\n");
1238 1.1 kardel fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n");
1239 1.1 kardel }
1240 1.1 kardel
1241 1.1 kardel /*-----------------------------------------------------------------------
1242 1.1 kardel * check_y2k() - internal check of Y2K logic
1243 1.1 kardel * (a lot of this logic lifted from ../ntpd/check_y2k.c)
1244 1.1 kardel */
1245 1.1 kardel static int
1246 1.1 kardel check_y2k( void )
1247 1.1 kardel {
1248 1.1 kardel int year; /* current working year */
1249 1.1 kardel int year0 = 1900; /* sarting year for NTP time */
1250 1.1 kardel int yearend; /* ending year we test for NTP time.
1251 1.1 kardel * 32-bit systems: through 2036, the
1252 1.1 kardel **year in which NTP time overflows.
1253 1.1 kardel * 64-bit systems: a reasonable upper
1254 1.1 kardel **limit (well, maybe somewhat beyond
1255 1.1 kardel **reasonable, but well before the
1256 1.1 kardel **max time, by which time the earth
1257 1.1 kardel **will be dead.) */
1258 1.1 kardel time_t Time;
1259 1.1 kardel struct tm LocalTime;
1260 1.1 kardel
1261 1.1 kardel int Fatals, Warnings;
1262 1.1 kardel #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
1263 1.1 kardel Warnings++; else Fatals++
1264 1.1 kardel
1265 1.1 kardel Fatals = Warnings = 0;
1266 1.1 kardel
1267 1.1 kardel Time = time( (time_t *)NULL );
1268 1.1 kardel LocalTime = *localtime( &Time );
1269 1.1 kardel
1270 1.1 kardel year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */
1271 1.1 kardel ? ( 400 * 3 ) /* three greater gregorian cycles */
1272 1.1 kardel : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
1273 1.1 kardel /* NOTE: will automacially expand test years on
1274 1.1 kardel * 64 bit machines.... this may cause some of the
1275 1.1 kardel * existing ntp logic to fail for years beyond
1276 1.1 kardel * 2036 (the current 32-bit limit). If all checks
1277 1.1 kardel * fail ONLY beyond year 2036 you may ignore such
1278 1.1 kardel * errors, at least for a decade or so. */
1279 1.1 kardel yearend = year0 + year;
1280 1.1 kardel
1281 1.1 kardel year = 1900+YEAR_PIVOT;
1282 1.1 kardel printf( " starting year %04d\n", (int) year );
1283 1.1 kardel printf( " ending year %04d\n", (int) yearend );
1284 1.1 kardel
1285 1.1 kardel for ( ; year < yearend; year++ )
1286 1.1 kardel {
1287 1.1 kardel clocktime_t ct;
1288 1.1 kardel time_t Observed;
1289 1.1 kardel time_t Expected;
1290 1.1 kardel unsigned Flag;
1291 1.1 kardel unsigned long t;
1292 1.1 kardel
1293 1.1 kardel ct.day = 1;
1294 1.1 kardel ct.month = 1;
1295 1.1 kardel ct.year = year;
1296 1.1 kardel ct.hour = ct.minute = ct.second = ct.usecond = 0;
1297 1.1 kardel ct.utcoffset = 0;
1298 1.1 kardel ct.flags = 0;
1299 1.1 kardel
1300 1.1 kardel Flag = 0;
1301 1.1 kardel Observed = dcf_to_unixtime( &ct, &Flag );
1302 1.1 kardel /* seems to be a clone of parse_to_unixtime() with
1303 1.1 kardel * *a minor difference to arg2 type */
1304 1.1 kardel if ( ct.year != year )
1305 1.1 kardel {
1306 1.1 kardel fprintf( stdout,
1307 1.1 kardel "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
1308 1.1 kardel (int)year, (int)Flag, (int)ct.year );
1309 1.1 kardel Error(year);
1310 1.1 kardel break;
1311 1.1 kardel }
1312 1.1 kardel t = julian0(year) - julian0(1970); /* Julian day from 1970 */
1313 1.1 kardel Expected = t * 24 * 60 * 60;
1314 1.1 kardel if ( Observed != Expected || Flag )
1315 1.1 kardel { /* time difference */
1316 1.1 kardel fprintf( stdout,
1317 1.1 kardel "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
1318 1.1 kardel year, (int)Flag,
1319 1.1 kardel (unsigned long)Observed, (unsigned long)Expected,
1320 1.1 kardel ((long)Observed - (long)Expected) );
1321 1.1 kardel Error(year);
1322 1.1 kardel break;
1323 1.1 kardel }
1324 1.1 kardel
1325 1.1 kardel if ( year >= YEAR_PIVOT+1900 )
1326 1.1 kardel {
1327 1.1 kardel /* check year % 100 code we put into dcf_to_unixtime() */
1328 1.1 kardel ct.year = year % 100;
1329 1.1 kardel Flag = 0;
1330 1.1 kardel
1331 1.1 kardel Observed = dcf_to_unixtime( &ct, &Flag );
1332 1.1 kardel
1333 1.1 kardel if ( Observed != Expected || Flag )
1334 1.1 kardel { /* time difference */
1335 1.1 kardel fprintf( stdout,
1336 1.1 kardel "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
1337 1.1 kardel year, (int)ct.year, (int)Flag,
1338 1.1 kardel (unsigned long)Observed, (unsigned long)Expected,
1339 1.1 kardel ((long)Observed - (long)Expected) );
1340 1.1 kardel Error(year);
1341 1.1 kardel break;
1342 1.1 kardel }
1343 1.1 kardel
1344 1.1 kardel /* check year - 1900 code we put into dcf_to_unixtime() */
1345 1.1 kardel ct.year = year - 1900;
1346 1.1 kardel Flag = 0;
1347 1.1 kardel
1348 1.1 kardel Observed = dcf_to_unixtime( &ct, &Flag );
1349 1.1 kardel
1350 1.1 kardel if ( Observed != Expected || Flag ) { /* time difference */
1351 1.1 kardel fprintf( stdout,
1352 1.1 kardel "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
1353 1.1 kardel year, (int)ct.year, (int)Flag,
1354 1.1 kardel (unsigned long)Observed, (unsigned long)Expected,
1355 1.1 kardel ((long)Observed - (long)Expected) );
1356 1.1 kardel Error(year);
1357 1.1 kardel break;
1358 1.1 kardel }
1359 1.1 kardel
1360 1.1 kardel
1361 1.1 kardel }
1362 1.1 kardel }
1363 1.1 kardel
1364 1.1 kardel return ( Fatals );
1365 1.1 kardel }
1366 1.1 kardel
1367 1.1 kardel /*--------------------------------------------------
1368 1.1 kardel * rawdcf_init - set up modem lines for RAWDCF receivers
1369 1.1 kardel */
1370 1.1 kardel #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
1371 1.1 kardel static void
1372 1.1 kardel rawdcf_init(
1373 1.1 kardel int fd
1374 1.1 kardel )
1375 1.1 kardel {
1376 1.1 kardel /*
1377 1.1 kardel * You can use the RS232 to supply the power for a DCF77 receiver.
1378 1.1 kardel * Here a voltage between the DTR and the RTS line is used. Unfortunately
1379 1.1 kardel * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
1380 1.1 kardel */
1381 1.1 kardel
1382 1.1 kardel #ifdef TIOCM_DTR
1383 1.1 kardel int sl232 = TIOCM_DTR; /* turn on DTR for power supply */
1384 1.1 kardel #else
1385 1.1 kardel int sl232 = CIOCM_DTR; /* turn on DTR for power supply */
1386 1.1 kardel #endif
1387 1.1 kardel
1388 1.1 kardel if (ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)
1389 1.1 kardel {
1390 1.1 kardel syslog(LOG_NOTICE, "rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m");
1391 1.1 kardel }
1392 1.1 kardel }
1393 1.1 kardel #else
1394 1.1 kardel static void
1395 1.1 kardel rawdcf_init(
1396 1.1 kardel int fd
1397 1.1 kardel )
1398 1.1 kardel {
1399 1.1 kardel syslog(LOG_NOTICE, "rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules");
1400 1.1 kardel }
1401 1.1 kardel #endif /* DTR initialisation type */
1402 1.1 kardel
1403 1.1 kardel /*-----------------------------------------------------------------------
1404 1.1 kardel * main loop - argument interpreter / setup / main loop
1405 1.1 kardel */
1406 1.1 kardel int
1407 1.1 kardel main(
1408 1.1 kardel int argc,
1409 1.1 kardel char **argv
1410 1.1 kardel )
1411 1.1 kardel {
1412 1.1 kardel unsigned char c;
1413 1.1 kardel char **a = argv;
1414 1.1 kardel int ac = argc;
1415 1.1 kardel char *file = NULL;
1416 1.1 kardel const char *drift_file = "/etc/dcfd.drift";
1417 1.1 kardel int fd;
1418 1.1 kardel int offset = 15;
1419 1.1 kardel int offsets = 0;
1420 1.1 kardel int delay = DEFAULT_DELAY; /* average delay from input edge to time stamping */
1421 1.1 kardel int trace = 0;
1422 1.1 kardel int errs = 0;
1423 1.1 kardel
1424 1.1 kardel /*
1425 1.1 kardel * process arguments
1426 1.1 kardel */
1427 1.1 kardel while (--ac)
1428 1.1 kardel {
1429 1.1 kardel char *arg = *++a;
1430 1.1 kardel if (*arg == '-')
1431 1.1 kardel while ((c = *++arg))
1432 1.1 kardel switch (c)
1433 1.1 kardel {
1434 1.1 kardel case 't':
1435 1.1 kardel trace = 1;
1436 1.1 kardel interactive = 1;
1437 1.1 kardel break;
1438 1.1 kardel
1439 1.1 kardel case 'f':
1440 1.1 kardel offset = 0;
1441 1.1 kardel interactive = 1;
1442 1.1 kardel break;
1443 1.1 kardel
1444 1.1 kardel case 'l':
1445 1.1 kardel loop_filter_debug = 1;
1446 1.1 kardel offsets = 1;
1447 1.1 kardel interactive = 1;
1448 1.1 kardel break;
1449 1.1 kardel
1450 1.1 kardel case 'n':
1451 1.1 kardel no_set = 1;
1452 1.1 kardel break;
1453 1.1 kardel
1454 1.1 kardel case 'o':
1455 1.1 kardel offsets = 1;
1456 1.1 kardel interactive = 1;
1457 1.1 kardel break;
1458 1.1 kardel
1459 1.1 kardel case 'i':
1460 1.1 kardel interactive = 1;
1461 1.1 kardel break;
1462 1.1 kardel
1463 1.1 kardel case 'D':
1464 1.1 kardel if (ac > 1)
1465 1.1 kardel {
1466 1.1 kardel delay = atoi(*++a);
1467 1.1 kardel ac--;
1468 1.1 kardel }
1469 1.1 kardel else
1470 1.1 kardel {
1471 1.1 kardel fprintf(stderr, "%s: -D requires integer argument\n", argv[0]);
1472 1.1 kardel errs=1;
1473 1.1 kardel }
1474 1.1 kardel break;
1475 1.1 kardel
1476 1.1 kardel case 'd':
1477 1.1 kardel if (ac > 1)
1478 1.1 kardel {
1479 1.1 kardel drift_file = *++a;
1480 1.1 kardel ac--;
1481 1.1 kardel }
1482 1.1 kardel else
1483 1.1 kardel {
1484 1.1 kardel fprintf(stderr, "%s: -d requires file name argument\n", argv[0]);
1485 1.1 kardel errs=1;
1486 1.1 kardel }
1487 1.1 kardel break;
1488 1.1 kardel
1489 1.1 kardel case 'Y':
1490 1.1 kardel errs=check_y2k();
1491 1.1 kardel exit( errs ? 1 : 0 );
1492 1.1 kardel
1493 1.1 kardel default:
1494 1.1 kardel fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
1495 1.1 kardel errs=1;
1496 1.1 kardel break;
1497 1.1 kardel }
1498 1.1 kardel else
1499 1.1 kardel if (file == NULL)
1500 1.1 kardel file = arg;
1501 1.1 kardel else
1502 1.1 kardel {
1503 1.1 kardel fprintf(stderr, "%s: device specified twice\n", argv[0]);
1504 1.1 kardel errs=1;
1505 1.1 kardel }
1506 1.1 kardel }
1507 1.1 kardel
1508 1.1 kardel if (errs)
1509 1.1 kardel {
1510 1.1 kardel usage(argv[0]);
1511 1.1 kardel exit(1);
1512 1.1 kardel }
1513 1.1 kardel else
1514 1.1 kardel if (file == NULL)
1515 1.1 kardel {
1516 1.1 kardel fprintf(stderr, "%s: device not specified\n", argv[0]);
1517 1.1 kardel usage(argv[0]);
1518 1.1 kardel exit(1);
1519 1.1 kardel }
1520 1.1 kardel
1521 1.1 kardel errs = LINES+1;
1522 1.1 kardel
1523 1.1 kardel /*
1524 1.1 kardel * get access to DCF77 tty port
1525 1.1 kardel */
1526 1.1 kardel fd = open(file, O_RDONLY);
1527 1.1 kardel if (fd == -1)
1528 1.1 kardel {
1529 1.1 kardel perror(file);
1530 1.1 kardel exit(1);
1531 1.1 kardel }
1532 1.1 kardel else
1533 1.1 kardel {
1534 1.1 kardel int i, rrc;
1535 1.1 kardel struct timeval t, tt, tlast;
1536 1.1 kardel struct timeval timeout;
1537 1.1 kardel struct timeval phase;
1538 1.1 kardel struct timeval time_offset;
1539 1.1 kardel char pbuf[61]; /* printable version */
1540 1.1 kardel char buf[61]; /* raw data */
1541 1.1 kardel clocktime_t clock_time; /* wall clock time */
1542 1.1 kardel time_t utc_time = 0;
1543 1.1 kardel time_t last_utc_time = 0;
1544 1.1 kardel long usecerror = 0;
1545 1.1 kardel long lasterror = 0;
1546 1.1 kardel #if defined(HAVE_TERMIOS_H) || defined(STREAM)
1547 1.1 kardel struct termios term;
1548 1.1 kardel #else /* not HAVE_TERMIOS_H || STREAM */
1549 1.1 kardel # if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS)
1550 1.1 kardel struct termio term;
1551 1.1 kardel # endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */
1552 1.1 kardel #endif /* not HAVE_TERMIOS_H || STREAM */
1553 1.1 kardel unsigned int rtc = CVT_NONE;
1554 1.1 kardel
1555 1.1 kardel rawdcf_init(fd);
1556 1.1 kardel
1557 1.1 kardel timeout.tv_sec = 1;
1558 1.1 kardel timeout.tv_usec = 500000;
1559 1.1 kardel
1560 1.1 kardel phase.tv_sec = 0;
1561 1.1 kardel phase.tv_usec = delay;
1562 1.1 kardel
1563 1.1 kardel /*
1564 1.1 kardel * setup TTY (50 Baud, Read, 8Bit, No Hangup, 1 character IO)
1565 1.1 kardel */
1566 1.1 kardel if (TTY_GETATTR(fd, &term) == -1)
1567 1.1 kardel {
1568 1.1 kardel perror("tcgetattr");
1569 1.1 kardel exit(1);
1570 1.1 kardel }
1571 1.1 kardel
1572 1.1 kardel memset(term.c_cc, 0, sizeof(term.c_cc));
1573 1.1 kardel term.c_cc[VMIN] = 1;
1574 1.1 kardel #ifdef NO_PARENB_IGNPAR
1575 1.1 kardel term.c_cflag = CS8|CREAD|CLOCAL;
1576 1.1 kardel #else
1577 1.1 kardel term.c_cflag = CS8|CREAD|CLOCAL|PARENB;
1578 1.1 kardel #endif
1579 1.1 kardel term.c_iflag = IGNPAR;
1580 1.1 kardel term.c_oflag = 0;
1581 1.1 kardel term.c_lflag = 0;
1582 1.1 kardel
1583 1.1 kardel cfsetispeed(&term, B50);
1584 1.1 kardel cfsetospeed(&term, B50);
1585 1.1 kardel
1586 1.1 kardel if (TTY_SETATTR(fd, &term) == -1)
1587 1.1 kardel {
1588 1.1 kardel perror("tcsetattr");
1589 1.1 kardel exit(1);
1590 1.1 kardel }
1591 1.1 kardel
1592 1.1 kardel /*
1593 1.1 kardel * lose terminal if in daemon operation
1594 1.1 kardel */
1595 1.1 kardel if (!interactive)
1596 1.1 kardel detach();
1597 1.1 kardel
1598 1.1 kardel /*
1599 1.1 kardel * get syslog() initialized
1600 1.1 kardel */
1601 1.1 kardel #ifdef LOG_DAEMON
1602 1.1 kardel openlog("dcfd", LOG_PID, LOG_DAEMON);
1603 1.1 kardel #else
1604 1.1 kardel openlog("dcfd", LOG_PID);
1605 1.1 kardel #endif
1606 1.1 kardel
1607 1.1 kardel /*
1608 1.1 kardel * setup periodic operations (state control / frequency control)
1609 1.1 kardel */
1610 1.1 kardel #ifdef HAVE_SIGACTION
1611 1.1 kardel {
1612 1.1 kardel struct sigaction act;
1613 1.1 kardel
1614 1.1 kardel # ifdef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION
1615 1.1 kardel act.sa_sigaction = (void (*) (int, siginfo_t *, void *))0;
1616 1.1 kardel # endif /* HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION */
1617 1.1 kardel act.sa_handler = tick;
1618 1.1 kardel sigemptyset(&act.sa_mask);
1619 1.1 kardel act.sa_flags = 0;
1620 1.1 kardel
1621 1.1 kardel if (sigaction(SIGALRM, &act, (struct sigaction *)0) == -1)
1622 1.1 kardel {
1623 1.1 kardel syslog(LOG_ERR, "sigaction(SIGALRM): %m");
1624 1.1 kardel exit(1);
1625 1.1 kardel }
1626 1.1 kardel }
1627 1.1 kardel #else
1628 1.1 kardel #ifdef HAVE_SIGVEC
1629 1.1 kardel {
1630 1.1 kardel struct sigvec vec;
1631 1.1 kardel
1632 1.1 kardel vec.sv_handler = tick;
1633 1.1 kardel vec.sv_mask = 0;
1634 1.1 kardel vec.sv_flags = 0;
1635 1.1 kardel
1636 1.1 kardel if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1)
1637 1.1 kardel {
1638 1.1 kardel syslog(LOG_ERR, "sigvec(SIGALRM): %m");
1639 1.1 kardel exit(1);
1640 1.1 kardel }
1641 1.1 kardel }
1642 1.1 kardel #else
1643 1.1 kardel (void) signal(SIGALRM, tick);
1644 1.1 kardel #endif
1645 1.1 kardel #endif
1646 1.1 kardel
1647 1.1 kardel #ifdef ITIMER_REAL
1648 1.1 kardel {
1649 1.1 kardel struct itimerval it;
1650 1.1 kardel
1651 1.1 kardel it.it_interval.tv_sec = 1<<ADJINTERVAL;
1652 1.1 kardel it.it_interval.tv_usec = 0;
1653 1.1 kardel it.it_value.tv_sec = 1<<ADJINTERVAL;
1654 1.1 kardel it.it_value.tv_usec = 0;
1655 1.1 kardel
1656 1.1 kardel if (setitimer(ITIMER_REAL, &it, (struct itimerval *)0) == -1)
1657 1.1 kardel {
1658 1.1 kardel syslog(LOG_ERR, "setitimer: %m");
1659 1.1 kardel exit(1);
1660 1.1 kardel }
1661 1.1 kardel }
1662 1.1 kardel #else
1663 1.1 kardel (void) alarm(1<<ADJINTERVAL);
1664 1.1 kardel #endif
1665 1.1 kardel
1666 1.1 kardel PRINTF(" DCF77 monitor %s - Copyright (C) 1993-2005 by Frank Kardel\n\n", revision);
1667 1.1 kardel
1668 1.1 kardel pbuf[60] = '\0';
1669 1.1 kardel for ( i = 0; i < 60; i++)
1670 1.1 kardel pbuf[i] = '.';
1671 1.1 kardel
1672 1.1 kardel read_drift(drift_file);
1673 1.1 kardel
1674 1.1 kardel /*
1675 1.1 kardel * what time is it now (for interval measurement)
1676 1.1 kardel */
1677 1.1 kardel gettimeofday(&tlast, 0L);
1678 1.1 kardel i = 0;
1679 1.1 kardel /*
1680 1.1 kardel * loop until input trouble ...
1681 1.1 kardel */
1682 1.1 kardel do
1683 1.1 kardel {
1684 1.1 kardel /*
1685 1.1 kardel * get an impulse
1686 1.1 kardel */
1687 1.1 kardel while ((rrc = read(fd, &c, 1)) == 1)
1688 1.1 kardel {
1689 1.1 kardel gettimeofday(&t, 0L);
1690 1.1 kardel tt = t;
1691 1.1 kardel timersub(&t, &tlast);
1692 1.1 kardel
1693 1.1 kardel if (errs > LINES)
1694 1.1 kardel {
1695 1.1 kardel PRINTF(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]);
1696 1.1 kardel PRINTF(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]);
1697 1.1 kardel errs = 0;
1698 1.1 kardel }
1699 1.1 kardel
1700 1.1 kardel /*
1701 1.1 kardel * timeout -> possible minute mark -> interpretation
1702 1.1 kardel */
1703 1.1 kardel if (timercmp(&t, &timeout, >))
1704 1.1 kardel {
1705 1.1 kardel PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]);
1706 1.1 kardel
1707 1.1 kardel if ((rtc = cvt_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK)
1708 1.1 kardel {
1709 1.1 kardel /*
1710 1.1 kardel * this data was bad - well - forget synchronisation for now
1711 1.1 kardel */
1712 1.1 kardel PRINTF("\n");
1713 1.1 kardel if (sync_state == SYNC)
1714 1.1 kardel {
1715 1.1 kardel sync_state = NO_SYNC;
1716 1.1 kardel syslog(LOG_INFO, "DCF77 reception lost (bad data)");
1717 1.1 kardel }
1718 1.1 kardel errs++;
1719 1.1 kardel }
1720 1.1 kardel else
1721 1.1 kardel if (trace)
1722 1.1 kardel {
1723 1.1 kardel PRINTF("\r %.*s ", 59 - offset, &buf[offset]);
1724 1.1 kardel }
1725 1.1 kardel
1726 1.1 kardel
1727 1.1 kardel buf[0] = c;
1728 1.1 kardel
1729 1.1 kardel /*
1730 1.1 kardel * collect first character
1731 1.1 kardel */
1732 1.1 kardel if (((c^0xFF)+1) & (c^0xFF))
1733 1.1 kardel pbuf[0] = '?';
1734 1.1 kardel else
1735 1.1 kardel pbuf[0] = type(c) ? '#' : '-';
1736 1.1 kardel
1737 1.1 kardel for ( i = 1; i < 60; i++)
1738 1.1 kardel pbuf[i] = '.';
1739 1.1 kardel
1740 1.1 kardel i = 0;
1741 1.1 kardel }
1742 1.1 kardel else
1743 1.1 kardel {
1744 1.1 kardel /*
1745 1.1 kardel * collect character
1746 1.1 kardel */
1747 1.1 kardel buf[i] = c;
1748 1.1 kardel
1749 1.1 kardel /*
1750 1.1 kardel * initial guess (usually correct)
1751 1.1 kardel */
1752 1.1 kardel if (((c^0xFF)+1) & (c^0xFF))
1753 1.1 kardel pbuf[i] = '?';
1754 1.1 kardel else
1755 1.1 kardel pbuf[i] = type(c) ? '#' : '-';
1756 1.1 kardel
1757 1.1 kardel PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]);
1758 1.1 kardel }
1759 1.1 kardel
1760 1.1 kardel if (i == 0 && rtc == CVT_OK)
1761 1.1 kardel {
1762 1.1 kardel /*
1763 1.1 kardel * we got a good time code here - try to convert it to
1764 1.1 kardel * UTC
1765 1.1 kardel */
1766 1.1 kardel if ((utc_time = dcf_to_unixtime(&clock_time, &rtc)) == -1)
1767 1.1 kardel {
1768 1.1 kardel PRINTF("*** BAD CONVERSION\n");
1769 1.1 kardel }
1770 1.1 kardel
1771 1.1 kardel if (utc_time != (last_utc_time + 60))
1772 1.1 kardel {
1773 1.1 kardel /*
1774 1.1 kardel * well, two successive sucessful telegrams are not 60 seconds
1775 1.1 kardel * apart
1776 1.1 kardel */
1777 1.1 kardel PRINTF("*** NO MINUTE INC\n");
1778 1.1 kardel if (sync_state == SYNC)
1779 1.1 kardel {
1780 1.1 kardel sync_state = NO_SYNC;
1781 1.1 kardel syslog(LOG_INFO, "DCF77 reception lost (data mismatch)");
1782 1.1 kardel }
1783 1.1 kardel errs++;
1784 1.1 kardel rtc = CVT_FAIL|CVT_BADTIME|CVT_BADDATE;
1785 1.1 kardel }
1786 1.1 kardel else
1787 1.1 kardel usecerror = 0;
1788 1.1 kardel
1789 1.1 kardel last_utc_time = utc_time;
1790 1.1 kardel }
1791 1.1 kardel
1792 1.1 kardel if (rtc == CVT_OK)
1793 1.1 kardel {
1794 1.1 kardel if (i == 0)
1795 1.1 kardel {
1796 1.1 kardel /*
1797 1.1 kardel * valid time code - determine offset and
1798 1.1 kardel * note regained reception
1799 1.1 kardel */
1800 1.1 kardel last_sync = ticks;
1801 1.1 kardel if (sync_state == NO_SYNC)
1802 1.1 kardel {
1803 1.1 kardel syslog(LOG_INFO, "receiving DCF77");
1804 1.1 kardel }
1805 1.1 kardel else
1806 1.1 kardel {
1807 1.1 kardel /*
1808 1.1 kardel * we had at least one minute SYNC - thus
1809 1.1 kardel * last error is valid
1810 1.1 kardel */
1811 1.1 kardel time_offset.tv_sec = lasterror / 1000000;
1812 1.1 kardel time_offset.tv_usec = lasterror % 1000000;
1813 1.1 kardel adjust_clock(&time_offset, drift_file, utc_time);
1814 1.1 kardel }
1815 1.1 kardel sync_state = SYNC;
1816 1.1 kardel }
1817 1.1 kardel
1818 1.1 kardel time_offset.tv_sec = utc_time + i;
1819 1.1 kardel time_offset.tv_usec = 0;
1820 1.1 kardel
1821 1.1 kardel timeradd(&time_offset, &phase);
1822 1.1 kardel
1823 1.1 kardel usecerror += (time_offset.tv_sec - tt.tv_sec) * 1000000 + time_offset.tv_usec
1824 1.1 kardel -tt.tv_usec;
1825 1.1 kardel
1826 1.1 kardel /*
1827 1.1 kardel * output interpreted DCF77 data
1828 1.1 kardel */
1829 1.1 kardel PRINTF(offsets ? "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s> (%c%ld.%06lds)" :
1830 1.1 kardel "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s>",
1831 1.1 kardel wday[clock_time.wday],
1832 1.1 kardel clock_time.hour, clock_time.minute, i, clock_time.day, clock_time.month,
1833 1.1 kardel clock_time.year,
1834 1.1 kardel (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_",
1835 1.1 kardel (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_",
1836 1.1 kardel (clock_time.flags & DCFB_DST) ? "D" : "_",
1837 1.1 kardel (clock_time.flags & DCFB_LEAP) ? "L" : "_",
1838 1.1 kardel (lasterror < 0) ? '-' : '+', l_abs(lasterror) / 1000000, l_abs(lasterror) % 1000000
1839 1.1 kardel );
1840 1.1 kardel
1841 1.1 kardel if (trace && (i == 0))
1842 1.1 kardel {
1843 1.1 kardel PRINTF("\n");
1844 1.1 kardel errs++;
1845 1.1 kardel }
1846 1.1 kardel lasterror = usecerror / (i+1);
1847 1.1 kardel }
1848 1.1 kardel else
1849 1.1 kardel {
1850 1.1 kardel lasterror = 0; /* we cannot calculate phase errors on bad reception */
1851 1.1 kardel }
1852 1.1 kardel
1853 1.1 kardel PRINTF("\r");
1854 1.1 kardel
1855 1.1 kardel if (i < 60)
1856 1.1 kardel {
1857 1.1 kardel i++;
1858 1.1 kardel }
1859 1.1 kardel
1860 1.1 kardel tlast = tt;
1861 1.1 kardel
1862 1.1 kardel if (interactive)
1863 1.1 kardel fflush(stdout);
1864 1.1 kardel }
1865 1.1 kardel } while ((rrc == -1) && (errno == EINTR));
1866 1.1 kardel
1867 1.1 kardel /*
1868 1.1 kardel * lost IO - sorry guys
1869 1.1 kardel */
1870 1.1 kardel syslog(LOG_ERR, "TERMINATING - cannot read from device %s (%m)", file);
1871 1.1 kardel
1872 1.1 kardel (void)close(fd);
1873 1.1 kardel }
1874 1.1 kardel
1875 1.1 kardel closelog();
1876 1.1 kardel
1877 1.1 kardel return 0;
1878 1.1 kardel }
1879 1.1 kardel
1880 1.1 kardel /*
1881 1.1 kardel * History:
1882 1.1 kardel *
1883 1.1 kardel * dcfd.c,v
1884 1.1 kardel * Revision 4.18 2005/10/07 22:08:18 kardel
1885 1.1 kardel * make dcfd.c compile on NetBSD 3.99.9 again (configure/sigvec compatibility fix)
1886 1.1 kardel *
1887 1.1 kardel * Revision 4.17.2.1 2005/10/03 19:15:16 kardel
1888 1.1 kardel * work around configure not detecting a missing sigvec compatibility
1889 1.1 kardel * interface on NetBSD 3.99.9 and above
1890 1.1 kardel *
1891 1.1 kardel * Revision 4.17 2005/08/10 10:09:44 kardel
1892 1.1 kardel * output revision information
1893 1.1 kardel *
1894 1.1 kardel * Revision 4.16 2005/08/10 06:33:25 kardel
1895 1.1 kardel * cleanup warnings
1896 1.1 kardel *
1897 1.1 kardel * Revision 4.15 2005/08/10 06:28:45 kardel
1898 1.1 kardel * fix setting of baud rate
1899 1.1 kardel *
1900 1.1 kardel * Revision 4.14 2005/04/16 17:32:10 kardel
1901 1.1 kardel * update copyright
1902 1.1 kardel *
1903 1.1 kardel * Revision 4.13 2004/11/14 15:29:41 kardel
1904 1.1 kardel * support PPSAPI, upgrade Copyright to Berkeley style
1905 1.1 kardel *
1906 1.1 kardel */
1907