154359Sroberto/*
2182007Sroberto * /src/NTP/ntp4-dev/libparse/clk_hopf6021.c,v 4.10 2004/11/14 15:29:41 kardel RELEASE_20050508_A
354359Sroberto *
4182007Sroberto * clk_hopf6021.c,v 4.10 2004/11/14 15:29:41 kardel RELEASE_20050508_A
554359Sroberto *
654359Sroberto * Radiocode Clocks HOPF Funkuhr 6021 mit serieller Schnittstelle
754359Sroberto * base code version from 24th Nov 1995 - history at end
854359Sroberto *
954359Sroberto * Created by F.Schnekenbuehl <frank@comsys.dofn.de> from clk_rcc8000.c
1054359Sroberto * Nortel DASA Network Systems GmbH, Department: ND250
1154359Sroberto * A Joint venture of Daimler-Benz Aerospace and Nortel
1254359Sroberto *
1354359Sroberto * This program is distributed in the hope that it will be useful,
1454359Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of
1554359Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1654359Sroberto *
1754359Sroberto */
1854359Sroberto
1954359Sroberto#ifdef HAVE_CONFIG_H
2054359Sroberto# include <config.h>
2154359Sroberto#endif
2254359Sroberto
2354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_HOPF6021)
2454359Sroberto
2554359Sroberto#include "ntp_fp.h"
2654359Sroberto#include "ntp_unixtime.h"
2754359Sroberto#include "ntp_calendar.h"
2854359Sroberto#include "ascii.h"
2954359Sroberto
3054359Sroberto#include "parse.h"
3154359Sroberto
3254359Sroberto#ifndef PARSESTREAM
3354359Sroberto#include "ntp_stdlib.h"
3454359Sroberto#include <stdio.h>
3554359Sroberto#else
3654359Sroberto#include "sys/parsestreams.h"
37280849Scyextern int printf (const char *, ...);
3854359Sroberto#endif
3954359Sroberto
40282408Scy/*
41282408Scy * hopf Funkuhr 6021
4254359Sroberto *      used with 9600,8N1,
43282408Scy *      UTC ueber serielle Schnittstelle
4454359Sroberto *      Sekundenvorlauf ON
4554359Sroberto *      ETX zum Sekundenvorlauf ON
4654359Sroberto *      Datenstring 6021
4754359Sroberto *      Ausgabe Uhrzeit und Datum
4854359Sroberto *      Senden mit Steuerzeichen
4954359Sroberto *      Senden sekuendlich
5054359Sroberto */
5154359Sroberto
5254359Sroberto/*
5354359Sroberto *  Type 6021 Serial Output format
5454359Sroberto *
5554359Sroberto *      000000000011111111 / char
5654359Sroberto *      012345678901234567 \ position
5754359Sroberto *      sABHHMMSSDDMMYYnre  Actual
5854359Sroberto *       C4110046231195     Parse
5954359Sroberto *      s              enr  Check
6054359Sroberto *
6154359Sroberto *  s = STX (0x02), e = ETX (0x03)
6254359Sroberto *  n = NL  (0x0A), r = CR  (0x0D)
6354359Sroberto *
6454359Sroberto *  A B - Status and weekday
6554359Sroberto *
6654359Sroberto *  A - Status
6754359Sroberto *
6854359Sroberto *      8 4 2 1
6954359Sroberto *      x x x 0  - no announcement
7054359Sroberto *      x x x 1  - Summertime - wintertime - summertime announcement
7154359Sroberto *      x x 0 x  - Wintertime
7254359Sroberto *      x x 1 x  - Summertime
7354359Sroberto *      0 0 x x  - Time/Date invalid
74282408Scy *      0 1 x x  - Internal clock used
7554359Sroberto *      1 0 x x  - Radio clock
7654359Sroberto *      1 1 x x  - Radio clock highprecision
7754359Sroberto *
7854359Sroberto *  B - 8 4 2 1
7954359Sroberto *      0 x x x  - MESZ/MEZ
8054359Sroberto *      1 x x x  - UTC
8154359Sroberto *      x 0 0 1  - Monday
8254359Sroberto *      x 0 1 0  - Tuesday
8354359Sroberto *      x 0 1 1  - Wednesday
8454359Sroberto *      x 1 0 0  - Thursday
8554359Sroberto *      x 1 0 1  - Friday
8654359Sroberto *      x 1 1 0  - Saturday
8754359Sroberto *      x 1 1 1  - Sunday
8854359Sroberto */
8954359Sroberto
9054359Sroberto#define HOPF_DSTWARN	0x01	/* DST switch warning */
9154359Sroberto#define HOPF_DST	0x02	/* DST in effect */
9254359Sroberto
93282408Scy#define HOPF_MODE	0x0C	/* operation mode mask */
9454359Sroberto#define  HOPF_INVALID	0x00	/* no time code available */
9554359Sroberto#define  HOPF_INTERNAL	0x04	/* internal clock */
96282408Scy#define  HOPF_RADIO	0x08	/* radio clock */
9754359Sroberto#define  HOPF_RADIOHP	0x0C	/* high precision radio clock */
9854359Sroberto
9954359Sroberto#define HOPF_UTC	0x08	/* time code in UTC */
10054359Sroberto#define HOPF_WMASK	0x07	/* mask for weekday code */
10154359Sroberto
10254359Srobertostatic struct format hopf6021_fmt =
10354359Sroberto{
10454359Sroberto	{
105282408Scy		{  9, 2 }, {11, 2}, { 13, 2}, /* Day, Month, Year */
106282408Scy		{  3, 2 }, { 5, 2}, {  7, 2}, /* Hour, Minute, Second */
10754359Sroberto		{  2, 1 }, { 1, 1}, {  0, 0}, /* Weekday, Flags, Zone */
10854359Sroberto		/* ... */
10954359Sroberto	},
11054359Sroberto	(const unsigned char *)"\002              \n\r\003",
111282408Scy	0
11254359Sroberto};
11354359Sroberto
11454359Sroberto#define OFFS(x) format->field_offsets[(x)].offset
11554359Sroberto#define STOI(x, y) Stoi(&buffer[OFFS(x)], y, format->field_offsets[(x)].length)
11654359Sroberto
117282408Scystatic parse_cvt_fnc_t cvt_hopf6021;
118282408Scystatic parse_inp_fnc_t inp_hopf6021;
119309007Sdelphijstatic unsigned char   hexval(unsigned char);
12054359Sroberto
12154359Srobertoclockformat_t clock_hopf6021 =
12254359Sroberto{
12354359Sroberto  inp_hopf6021,			/* HOPF 6021 input handling */
12454359Sroberto  cvt_hopf6021,                 /* Radiocode clock conversion */
12554359Sroberto  0,				/* no direct PPS monitoring */
12654359Sroberto  (void *)&hopf6021_fmt,        /* conversion configuration */
12754359Sroberto  "hopf Funkuhr 6021",          /* clock format name */
12854359Sroberto  19,                           /* string buffer */
12954359Sroberto  0                            /* private data length, no private data */
13054359Sroberto};
13154359Sroberto
132282408Scy/* parse_cvt_fnc_t cvt_hopf6021 */
133282408Scystatic u_long
13454359Srobertocvt_hopf6021(
13554359Sroberto	     unsigned char *buffer,
13654359Sroberto	     int            size,
13754359Sroberto	     struct format *format,
13854359Sroberto	     clocktime_t   *clock_time,
13954359Sroberto	     void          *local
14054359Sroberto	     )
14154359Sroberto{
14254359Sroberto	unsigned char status,weekday;
14354359Sroberto
14454359Sroberto	if (!Strok(buffer, format->fixed_string))
14554359Sroberto	{
14654359Sroberto		return CVT_NONE;
14754359Sroberto	}
14854359Sroberto
14954359Sroberto	if (  STOI(O_DAY,   &clock_time->day)    ||
15054359Sroberto	      STOI(O_MONTH, &clock_time->month)  ||
15154359Sroberto	      STOI(O_YEAR,  &clock_time->year)   ||
15254359Sroberto	      STOI(O_HOUR,  &clock_time->hour)   ||
15354359Sroberto	      STOI(O_MIN,   &clock_time->minute) ||
15454359Sroberto	      STOI(O_SEC,   &clock_time->second)
15554359Sroberto	      )
15654359Sroberto	{
15754359Sroberto		return CVT_FAIL|CVT_BADFMT;
15854359Sroberto	}
15954359Sroberto
160309007Sdelphij	clock_time->usecond = 0;
161309007Sdelphij	clock_time->flags   = 0;
16254359Sroberto
163309007Sdelphij	status  = hexval(buffer[OFFS(O_FLAGS)]);
164309007Sdelphij	weekday = hexval(buffer[OFFS(O_WDAY)]);
16554359Sroberto
16654359Sroberto	if ((status == 0xFF) || (weekday == 0xFF))
16754359Sroberto	{
16854359Sroberto		return CVT_FAIL|CVT_BADFMT;
16954359Sroberto	}
17054359Sroberto
17154359Sroberto	if (weekday & HOPF_UTC)
17254359Sroberto	{
173309007Sdelphij		clock_time->flags     |= PARSEB_UTC;
174309007Sdelphij		clock_time->utcoffset  = 0;
17554359Sroberto	}
176309007Sdelphij	else if (status & HOPF_DST)
177309007Sdelphij	{
178309007Sdelphij		clock_time->flags     |= PARSEB_DST;
179309007Sdelphij		clock_time->utcoffset  = -2*60*60; /* MET DST */
180309007Sdelphij	}
18154359Sroberto	else
18254359Sroberto	{
183309007Sdelphij		clock_time->utcoffset  = -1*60*60; /* MET */
18454359Sroberto	}
18554359Sroberto
186309007Sdelphij	if (status & HOPF_DSTWARN)
187309007Sdelphij	{
188309007Sdelphij		clock_time->flags |= PARSEB_ANNOUNCE;
189309007Sdelphij	}
190309007Sdelphij
19154359Sroberto	switch (status & HOPF_MODE)
19254359Sroberto	{
193309007Sdelphij	    default:	/* dummy: we cover all 4 cases. */
19454359Sroberto	    case HOPF_INVALID:  /* Time/Date invalid */
19554359Sroberto		clock_time->flags |= PARSEB_POWERUP;
19654359Sroberto		break;
19754359Sroberto
19854359Sroberto	    case HOPF_INTERNAL: /* internal clock */
19954359Sroberto		clock_time->flags |= PARSEB_NOSYNC;
20054359Sroberto		break;
20154359Sroberto
20254359Sroberto	    case HOPF_RADIO:    /* Radio clock */
20354359Sroberto	    case HOPF_RADIOHP:  /* Radio clock high precision */
20454359Sroberto		break;
20554359Sroberto	}
20654359Sroberto
20754359Sroberto	return CVT_OK;
20854359Sroberto}
20954359Sroberto
21054359Sroberto/*
211282408Scy * parse_inp_fnc_t inp_hopf6021
21254359Sroberto *
213282408Scy * grab data from input stream
21454359Sroberto */
21554359Srobertostatic u_long
21654359Srobertoinp_hopf6021(
21754359Sroberto	     parse_t      *parseio,
218282408Scy	     char         ch,
21954359Sroberto	     timestamp_t  *tstamp
22054359Sroberto	  )
22154359Sroberto{
22254359Sroberto	unsigned int rtc;
223282408Scy
224293423Sdelphij	parseprintf(DD_PARSE, ("inp_hopf6021(0x%p, 0x%x, ...)\n", (void*)parseio, ch));
225282408Scy
22654359Sroberto	switch (ch)
22754359Sroberto	{
22854359Sroberto	case ETX:
22954359Sroberto		parseprintf(DD_PARSE, ("inp_hopf6021: EOL seen\n"));
23054359Sroberto		parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
23154359Sroberto		if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
23254359Sroberto			return parse_end(parseio);
23354359Sroberto		else
23454359Sroberto			return rtc;
23554359Sroberto
23654359Sroberto	default:
23754359Sroberto		return parse_addchar(parseio, ch);
23854359Sroberto	}
23954359Sroberto}
24054359Sroberto
241309007Sdelphij/*
242309007Sdelphij * convert a hex-digit to numeric value
243309007Sdelphij */
244309007Sdelphijstatic unsigned char
245309007Sdelphijhexval(
246309007Sdelphij	unsigned char ch
247309007Sdelphij	)
248309007Sdelphij{
249309007Sdelphij	unsigned int dv;
250309007Sdelphij
251309007Sdelphij	if ((dv = ch - '0') >= 10u)
252309007Sdelphij	{
253309007Sdelphij		if ((dv -= 'A'-'0') < 6u || (dv -= 'a'-'A') < 6u)
254309007Sdelphij		{
255309007Sdelphij			dv += 10;
256309007Sdelphij		}
257309007Sdelphij		else
258309007Sdelphij		{
259309007Sdelphij			dv = 0xFF;
260309007Sdelphij		}
261309007Sdelphij	}
262309007Sdelphij	return (unsigned char)dv;
263309007Sdelphij}
264309007Sdelphij
26554359Sroberto#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */
26654359Srobertoint clk_hopf6021_bs;
26754359Sroberto#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */
26854359Sroberto
26954359Sroberto/*
27054359Sroberto * History:
27154359Sroberto *
27254359Sroberto * clk_hopf6021.c,v
273182007Sroberto * Revision 4.10  2004/11/14 15:29:41  kardel
274182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
275182007Sroberto *
27656746Sroberto * Revision 4.7  1999/11/28 09:13:49  kardel
27756746Sroberto * RECON_4_0_98F
27856746Sroberto *
27954359Sroberto * Revision 4.6  1998/11/15 20:27:57  kardel
28054359Sroberto * Release 4.0.73e13 reconcilation
28154359Sroberto *
28254359Sroberto * Revision 4.5  1998/06/14 21:09:35  kardel
28354359Sroberto * Sun acc cleanup
28454359Sroberto *
28554359Sroberto * Revision 4.4  1998/06/13 12:02:38  kardel
28654359Sroberto * fix SYSV clock name clash
28754359Sroberto *
28854359Sroberto * Revision 4.3  1998/06/12 15:22:27  kardel
28954359Sroberto * fix prototypes
29054359Sroberto *
29154359Sroberto * Revision 4.2  1998/06/12 09:13:25  kardel
29254359Sroberto * conditional compile macros fixed
29354359Sroberto * printf prototype
29454359Sroberto *
29554359Sroberto * Revision 4.1  1998/05/24 09:39:52  kardel
29654359Sroberto * implementation of the new IO handling model
29754359Sroberto *
29854359Sroberto * Revision 4.0  1998/04/10 19:45:29  kardel
29954359Sroberto * Start 4.0 release version numbering
30054359Sroberto *
30154359Sroberto * from V3 3.6 log info deleted 1998/04/11 kardel
30254359Sroberto */
303