1/*
2 * /src/NTP/ntp4-dev/libparse/clk_hopf6021.c,v 4.10 2004/11/14 15:29:41 kardel RELEASE_20050508_A
3 *
4 * clk_hopf6021.c,v 4.10 2004/11/14 15:29:41 kardel RELEASE_20050508_A
5 *
6 * Radiocode Clocks HOPF Funkuhr 6021 mit serieller Schnittstelle
7 * base code version from 24th Nov 1995 - history at end
8 *
9 * Created by F.Schnekenbuehl <frank@comsys.dofn.de> from clk_rcc8000.c
10 * Nortel DASA Network Systems GmbH, Department: ND250
11 * A Joint venture of Daimler-Benz Aerospace and Nortel
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 */
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_HOPF6021)
24
25#include "ntp_fp.h"
26#include "ntp_unixtime.h"
27#include "ntp_calendar.h"
28#include "ascii.h"
29
30#include "parse.h"
31
32#ifndef PARSESTREAM
33#include "ntp_stdlib.h"
34#include <stdio.h>
35#else
36#include "sys/parsestreams.h"
37extern int printf (const char *, ...);
38#endif
39
40/*
41 * hopf Funkuhr 6021
42 *      used with 9600,8N1,
43 *      UTC ueber serielle Schnittstelle
44 *      Sekundenvorlauf ON
45 *      ETX zum Sekundenvorlauf ON
46 *      Datenstring 6021
47 *      Ausgabe Uhrzeit und Datum
48 *      Senden mit Steuerzeichen
49 *      Senden sekuendlich
50 */
51
52/*
53 *  Type 6021 Serial Output format
54 *
55 *      000000000011111111 / char
56 *      012345678901234567 \ position
57 *      sABHHMMSSDDMMYYnre  Actual
58 *       C4110046231195     Parse
59 *      s              enr  Check
60 *
61 *  s = STX (0x02), e = ETX (0x03)
62 *  n = NL  (0x0A), r = CR  (0x0D)
63 *
64 *  A B - Status and weekday
65 *
66 *  A - Status
67 *
68 *      8 4 2 1
69 *      x x x 0  - no announcement
70 *      x x x 1  - Summertime - wintertime - summertime announcement
71 *      x x 0 x  - Wintertime
72 *      x x 1 x  - Summertime
73 *      0 0 x x  - Time/Date invalid
74 *      0 1 x x  - Internal clock used
75 *      1 0 x x  - Radio clock
76 *      1 1 x x  - Radio clock highprecision
77 *
78 *  B - 8 4 2 1
79 *      0 x x x  - MESZ/MEZ
80 *      1 x x x  - UTC
81 *      x 0 0 1  - Monday
82 *      x 0 1 0  - Tuesday
83 *      x 0 1 1  - Wednesday
84 *      x 1 0 0  - Thursday
85 *      x 1 0 1  - Friday
86 *      x 1 1 0  - Saturday
87 *      x 1 1 1  - Sunday
88 */
89
90#define HOPF_DSTWARN	0x01	/* DST switch warning */
91#define HOPF_DST	0x02	/* DST in effect */
92
93#define HOPF_MODE	0x0C	/* operation mode mask */
94#define  HOPF_INVALID	0x00	/* no time code available */
95#define  HOPF_INTERNAL	0x04	/* internal clock */
96#define  HOPF_RADIO	0x08	/* radio clock */
97#define  HOPF_RADIOHP	0x0C	/* high precision radio clock */
98
99#define HOPF_UTC	0x08	/* time code in UTC */
100#define HOPF_WMASK	0x07	/* mask for weekday code */
101
102static struct format hopf6021_fmt =
103{
104	{
105		{  9, 2 }, {11, 2}, { 13, 2}, /* Day, Month, Year */
106		{  3, 2 }, { 5, 2}, {  7, 2}, /* Hour, Minute, Second */
107		{  2, 1 }, { 1, 1}, {  0, 0}, /* Weekday, Flags, Zone */
108		/* ... */
109	},
110	(const unsigned char *)"\002              \n\r\003",
111	0
112};
113
114#define OFFS(x) format->field_offsets[(x)].offset
115#define STOI(x, y) Stoi(&buffer[OFFS(x)], y, format->field_offsets[(x)].length)
116
117static parse_cvt_fnc_t cvt_hopf6021;
118static parse_inp_fnc_t inp_hopf6021;
119static unsigned char   hexval(unsigned char);
120
121clockformat_t clock_hopf6021 =
122{
123  inp_hopf6021,			/* HOPF 6021 input handling */
124  cvt_hopf6021,                 /* Radiocode clock conversion */
125  0,				/* no direct PPS monitoring */
126  (void *)&hopf6021_fmt,        /* conversion configuration */
127  "hopf Funkuhr 6021",          /* clock format name */
128  19,                           /* string buffer */
129  0                            /* private data length, no private data */
130};
131
132/* parse_cvt_fnc_t cvt_hopf6021 */
133static u_long
134cvt_hopf6021(
135	     unsigned char *buffer,
136	     int            size,
137	     struct format *format,
138	     clocktime_t   *clock_time,
139	     void          *local
140	     )
141{
142	unsigned char status,weekday;
143
144	if (!Strok(buffer, format->fixed_string))
145	{
146		return CVT_NONE;
147	}
148
149	if (  STOI(O_DAY,   &clock_time->day)    ||
150	      STOI(O_MONTH, &clock_time->month)  ||
151	      STOI(O_YEAR,  &clock_time->year)   ||
152	      STOI(O_HOUR,  &clock_time->hour)   ||
153	      STOI(O_MIN,   &clock_time->minute) ||
154	      STOI(O_SEC,   &clock_time->second)
155	      )
156	{
157		return CVT_FAIL|CVT_BADFMT;
158	}
159
160	clock_time->usecond = 0;
161	clock_time->flags   = 0;
162
163	status  = hexval(buffer[OFFS(O_FLAGS)]);
164	weekday = hexval(buffer[OFFS(O_WDAY)]);
165
166	if ((status == 0xFF) || (weekday == 0xFF))
167	{
168		return CVT_FAIL|CVT_BADFMT;
169	}
170
171	if (weekday & HOPF_UTC)
172	{
173		clock_time->flags     |= PARSEB_UTC;
174		clock_time->utcoffset  = 0;
175	}
176	else if (status & HOPF_DST)
177	{
178		clock_time->flags     |= PARSEB_DST;
179		clock_time->utcoffset  = -2*60*60; /* MET DST */
180	}
181	else
182	{
183		clock_time->utcoffset  = -1*60*60; /* MET */
184	}
185
186	if (status & HOPF_DSTWARN)
187	{
188		clock_time->flags |= PARSEB_ANNOUNCE;
189	}
190
191	switch (status & HOPF_MODE)
192	{
193	    default:	/* dummy: we cover all 4 cases. */
194	    case HOPF_INVALID:  /* Time/Date invalid */
195		clock_time->flags |= PARSEB_POWERUP;
196		break;
197
198	    case HOPF_INTERNAL: /* internal clock */
199		clock_time->flags |= PARSEB_NOSYNC;
200		break;
201
202	    case HOPF_RADIO:    /* Radio clock */
203	    case HOPF_RADIOHP:  /* Radio clock high precision */
204		break;
205	}
206
207	return CVT_OK;
208}
209
210/*
211 * parse_inp_fnc_t inp_hopf6021
212 *
213 * grab data from input stream
214 */
215static u_long
216inp_hopf6021(
217	     parse_t      *parseio,
218	     char         ch,
219	     timestamp_t  *tstamp
220	  )
221{
222	unsigned int rtc;
223
224	parseprintf(DD_PARSE, ("inp_hopf6021(0x%p, 0x%x, ...)\n", (void*)parseio, ch));
225
226	switch (ch)
227	{
228	case ETX:
229		parseprintf(DD_PARSE, ("inp_hopf6021: EOL seen\n"));
230		parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
231		if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
232			return parse_end(parseio);
233		else
234			return rtc;
235
236	default:
237		return parse_addchar(parseio, ch);
238	}
239}
240
241/*
242 * convert a hex-digit to numeric value
243 */
244static unsigned char
245hexval(
246	unsigned char ch
247	)
248{
249	unsigned int dv;
250
251	if ((dv = ch - '0') >= 10u)
252	{
253		if ((dv -= 'A'-'0') < 6u || (dv -= 'a'-'A') < 6u)
254		{
255			dv += 10;
256		}
257		else
258		{
259			dv = 0xFF;
260		}
261	}
262	return (unsigned char)dv;
263}
264
265#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */
266int clk_hopf6021_bs;
267#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */
268
269/*
270 * History:
271 *
272 * clk_hopf6021.c,v
273 * Revision 4.10  2004/11/14 15:29:41  kardel
274 * support PPSAPI, upgrade Copyright to Berkeley style
275 *
276 * Revision 4.7  1999/11/28 09:13:49  kardel
277 * RECON_4_0_98F
278 *
279 * Revision 4.6  1998/11/15 20:27:57  kardel
280 * Release 4.0.73e13 reconcilation
281 *
282 * Revision 4.5  1998/06/14 21:09:35  kardel
283 * Sun acc cleanup
284 *
285 * Revision 4.4  1998/06/13 12:02:38  kardel
286 * fix SYSV clock name clash
287 *
288 * Revision 4.3  1998/06/12 15:22:27  kardel
289 * fix prototypes
290 *
291 * Revision 4.2  1998/06/12 09:13:25  kardel
292 * conditional compile macros fixed
293 * printf prototype
294 *
295 * Revision 4.1  1998/05/24 09:39:52  kardel
296 * implementation of the new IO handling model
297 *
298 * Revision 4.0  1998/04/10 19:45:29  kardel
299 * Start 4.0 release version numbering
300 *
301 * from V3 3.6 log info deleted 1998/04/11 kardel
302 */
303