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