xref: /freebsd/contrib/ntp/libparse/clk_varitext.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_VARITEXT)
6 /*
7  * clk_varitext.c,v 1.0 1997/01/19 A.McConnell
8  *
9  * Supports Varitext's Radio Clock
10  *
11  * Used the Meinberg/Computime clock as a template for Varitext Radio Clock
12  *
13  * Copyright (C) 1992-1996 by Frank Kardel
14  * Friedrich-Alexander Universitt Erlangen-Nrnberg, Germany
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  */
21 
22 #include <sys/types.h>
23 #include <sys/time.h>
24 
25 #include "ntp_fp.h"
26 #include "ntp_unixtime.h"
27 #include "ntp_calendar.h"
28 
29 #include "parse.h"
30 
31 #ifndef PARSESTREAM
32 #include "ntp_stdlib.h"
33 #include <stdio.h>
34 #else
35 #include "sys/parsestreams.h"
36 extern void printf P((const char *, ...));
37 #endif
38 
39 static const u_char VT_INITIALISED      = 0x01;
40 static const u_char VT_SYNCHRONISED     = 0x02;
41 static const u_char VT_ALARM_STATE      = 0x04;
42 static const u_char VT_BST              = 0x08;
43 static const u_char VT_SEASON_CHANGE    = 0x10;
44 static const u_char VT_LAST_TELEGRAM_OK = 0x20;
45 
46 /*
47  * The Varitext receiver sends a datagram in the following format every minute
48  *
49  * Timestamp	T:YY:MM:MD:WD:HH:MM:SSCRLFSTXXX
50  * Pos          0123456789012345678901 2 3 4567
51  *              0000000000111111111122 2 2 2222
52  * Parse        T:  :  :  :  :  :  :  \r\n
53  *
54  * T	Startcharacter "T" specifies start of the timestamp
55  * YY	Year MM	Month 1-12
56  * MD	Day of the month
57  * WD	Day of week
58  * HH	Hour
59  * MM   Minute
60  * SS   Second
61  * CR   Carriage return
62  * LF   Linefeed
63  * ST	Status character
64  *	Bit 0 - Set= Initialised; Reset=Time Invalid (DO NOT USE)
65  *	Bit 1 - Set= Synchronised; Reset= Unsynchronised
66  * 	Bit 2 - Set= Alarm state; Reset= No alarm
67  * 	Bit 3 - Set= BST; Reset= GMT
68  * 	Bit 4 - Set= Seasonal change in approx hour; Reset= No seasonal change expected
69  *	Bit 5 - Set= Last MSF telegram was OK; Reset= Last telegram was in error;
70  * 	Bit 6 - Always set
71  *	Bit 7 - Unused
72  * XXX	Checksum calculated using Fletcher's method (ignored for now).
73  */
74 
75 static struct format varitext_fmt =
76 {
77   {
78     {8, 2},  {5,  2}, {2,  2},	/* day, month, year */
79     {14, 2}, {17, 2}, {20, 2},	/* hour, minute, second */
80     {11, 2}, {24, 1}		/* dayofweek, status */
81   },
82   (const unsigned char*)"T:  :  :  :  :  :  :  \r\n    ",
83   0
84 };
85 
86 static u_long   cvt_varitext P((unsigned char *, int, struct format *, clocktime_t *, void *));
87 static u_long   inp_varitext P((parse_t *, unsigned int, timestamp_t *));
88 
89 struct varitext {
90   unsigned char start_found;
91   unsigned char end_found;
92   unsigned char end_count;
93   unsigned char previous_ch;
94   timestamp_t   tstamp;
95 };
96 
97 clockformat_t   clock_varitext =
98 {
99   inp_varitext,			/* Because of the strange format we need to parse it ourselves */
100   cvt_varitext,			/* Varitext conversion */
101   0,				/* no PPS monitoring */
102   (void *)&varitext_fmt,	/* conversion configuration */
103   "Varitext Radio Clock",	/* Varitext Radio Clock */
104   30,				/* string buffer */
105   sizeof(struct varitext),	/* Private data size required to hold current parse state */
106 };
107 
108 /*
109  * cvt_varitext
110  *
111  * convert simple type format
112  */
113 static          u_long
114 cvt_varitext(
115 	     unsigned char	*buffer,
116 	     int    		size,
117 	     struct format	*format,
118 	     clocktime_t	*clock_time,
119 	     void		*local
120 	     )
121 {
122 
123   if (!Strok(buffer, format->fixed_string)) {
124     return CVT_NONE;
125   } else {
126     if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
127 	     format->field_offsets[O_DAY].length) ||
128 	Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
129 	     format->field_offsets[O_MONTH].length) ||
130 	Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
131 	     format->field_offsets[O_YEAR].length) ||
132 	Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
133 	     format->field_offsets[O_HOUR].length) ||
134 	Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
135 	     format->field_offsets[O_MIN].length) ||
136 	Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
137 	     format->field_offsets[O_SEC].length)) {
138       return CVT_FAIL | CVT_BADFMT;
139     } else {
140       u_char *f = (u_char*) &buffer[format->field_offsets[O_FLAGS].offset];
141 
142       clock_time->flags = 0;
143       clock_time->utcoffset = 0;
144 
145       if (((*f) & VT_BST))	/* BST flag is set so set to indicate daylight saving time is active and utc offset */
146 	{
147 	  clock_time->utcoffset = -1*60*60;
148 	  clock_time->flags |= PARSEB_DST;
149 	}
150       /*
151 	 if (!((*f) & VT_INITIALISED))  Clock not initialised
152 	 clock_time->flags |= PARSEB_POWERUP;
153 
154 	 if (!((*f) & VT_SYNCHRONISED))   Clock not synchronised
155 	 clock_time->flags |= PARSEB_NOSYNC;
156 
157 	 if (((*f) & VT_SEASON_CHANGE))  Seasonal change expected in the next hour
158 	 clock_time->flags |= PARSEB_ANNOUNCE;
159 	 */
160       return CVT_OK;
161     }
162   }
163 }
164 
165 static u_long
166 inp_varitext(
167 	     parse_t	 *parseio,
168 	     unsigned int ch,
169 	     timestamp_t *tstamp
170 	     )
171 {
172   struct varitext *t = (struct varitext *)parseio->parse_pdata;
173   int    rtc;
174 
175   parseprintf(DD_PARSE, ("inp_varitext(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch));
176 
177   if (!t)
178     return PARSE_INP_SKIP;	/* local data not allocated - sigh! */
179 
180   if (ch == 'T')
181     t->tstamp = *tstamp;
182 
183   if ((t->previous_ch == 'T') && (ch == ':'))
184     {
185       parseprintf(DD_PARSE, ("inp_varitext: START seen\n"));
186 
187       parseio->parse_data[0] = 'T';
188       parseio->parse_index=1;
189       parseio->parse_dtime.parse_stime = t->tstamp; /* Time stamp at packet start */
190       t->start_found = 1;
191       t->end_found = 0;
192       t->end_count = 0;
193     }
194 
195   if (t->start_found)
196     {
197       if ((rtc = parse_addchar(parseio, ch)) != PARSE_INP_SKIP)
198 	{
199 	  parseprintf(DD_PARSE, ("inp_varitext: ABORTED due to too many characters\n"));
200 
201 	  memset(t, 0, sizeof(struct varitext));
202 	  return rtc;
203 	}
204 
205       if (t->end_found)
206 	{
207 	  if (++(t->end_count) == 4) /* Finally found the end of the message */
208 	    {
209 	      parseprintf(DD_PARSE, ("inp_varitext: END seen\n"));
210 
211 	      memset(t, 0, sizeof(struct varitext));
212 	      if ((rtc = parse_addchar(parseio, 0)) == PARSE_INP_SKIP)
213 		return parse_end(parseio);
214 	      else
215 		return rtc;
216 	    }
217 	}
218 
219       if ((t->previous_ch == '\r') && (ch == '\n'))
220 	{
221 	  t->end_found = 1;
222 	}
223 
224     }
225 
226   t->previous_ch = ch;
227 
228   return PARSE_INP_SKIP;
229 }
230 
231 #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_VARITEXT) */
232 int clk_varitext_bs;
233 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_VARITEXT) */
234 
235 /*
236  * Revision 1.0  1997/06/02 13:16:30  McConnell
237  * File created
238  *
239  */
240