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