xref: /freebsd/contrib/ntp/libparse/clk_meinberg.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
2ea906c41SOllivier Robert  * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
3c0b746e5SOllivier Robert  *
4ea906c41SOllivier Robert  * clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
5c0b746e5SOllivier Robert  *
6c0b746e5SOllivier Robert  * Meinberg clock support
7c0b746e5SOllivier Robert  *
8276da39aSCy Schubert  * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
9a25439b6SCy Schubert  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
10c0b746e5SOllivier Robert  *
11ea906c41SOllivier Robert  * Redistribution and use in source and binary forms, with or without
12ea906c41SOllivier Robert  * modification, are permitted provided that the following conditions
13ea906c41SOllivier Robert  * are met:
14ea906c41SOllivier Robert  * 1. Redistributions of source code must retain the above copyright
15ea906c41SOllivier Robert  *    notice, this list of conditions and the following disclaimer.
16ea906c41SOllivier Robert  * 2. Redistributions in binary form must reproduce the above copyright
17ea906c41SOllivier Robert  *    notice, this list of conditions and the following disclaimer in the
18ea906c41SOllivier Robert  *    documentation and/or other materials provided with the distribution.
19ea906c41SOllivier Robert  * 3. Neither the name of the author nor the names of its contributors
20ea906c41SOllivier Robert  *    may be used to endorse or promote products derived from this software
21ea906c41SOllivier Robert  *    without specific prior written permission.
22ea906c41SOllivier Robert  *
23ea906c41SOllivier Robert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24ea906c41SOllivier Robert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ea906c41SOllivier Robert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ea906c41SOllivier Robert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27ea906c41SOllivier Robert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ea906c41SOllivier Robert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ea906c41SOllivier Robert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ea906c41SOllivier Robert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ea906c41SOllivier Robert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ea906c41SOllivier Robert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ea906c41SOllivier Robert  * SUCH DAMAGE.
34c0b746e5SOllivier Robert  *
35c0b746e5SOllivier Robert  */
36c0b746e5SOllivier Robert 
37c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
38c0b746e5SOllivier Robert # include <config.h>
39c0b746e5SOllivier Robert #endif
40c0b746e5SOllivier Robert 
41c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_MEINBERG)
42c0b746e5SOllivier Robert 
43c0b746e5SOllivier Robert #include "ntp_fp.h"
44c0b746e5SOllivier Robert #include "ntp_unixtime.h"
45c0b746e5SOllivier Robert #include "ntp_calendar.h"
46c0b746e5SOllivier Robert 
47c0b746e5SOllivier Robert #include "ntp_machine.h"
48c0b746e5SOllivier Robert 
49c0b746e5SOllivier Robert #include "parse.h"
50c0b746e5SOllivier Robert 
51c0b746e5SOllivier Robert #ifndef PARSESTREAM
52c0b746e5SOllivier Robert #include <stdio.h>
53c0b746e5SOllivier Robert #else
54c0b746e5SOllivier Robert #include "sys/parsestreams.h"
55c0b746e5SOllivier Robert #endif
56c0b746e5SOllivier Robert 
57c0b746e5SOllivier Robert #include "ntp_stdlib.h"
58c0b746e5SOllivier Robert 
59c0b746e5SOllivier Robert #include "ntp_stdlib.h"
60c0b746e5SOllivier Robert 
61c0b746e5SOllivier Robert #include "mbg_gps166.h"
62c0b746e5SOllivier Robert #include "binio.h"
63c0b746e5SOllivier Robert #include "ascii.h"
64c0b746e5SOllivier Robert 
65c0b746e5SOllivier Robert /*
66c0b746e5SOllivier Robert  * The Meinberg receiver every second sends a datagram of the following form
67c0b746e5SOllivier Robert  * (Standard Format)
68c0b746e5SOllivier Robert  *
69c0b746e5SOllivier Robert  *     <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
70c0b746e5SOllivier Robert  * pos:  0  00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2  2  3  3   3
71c0b746e5SOllivier Robert  *       1  23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8  9  0  1   2
72c0b746e5SOllivier Robert  * <STX>           = '\002' ASCII start of text
73c0b746e5SOllivier Robert  * <ETX>           = '\003' ASCII end of text
74c0b746e5SOllivier Robert  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
75c0b746e5SOllivier Robert  * <w>             = day of week (sunday= 0)
76c0b746e5SOllivier Robert  * <hh>,<mm>,<ss>  = hour, minute, second
77c0b746e5SOllivier Robert  * <S>             = '#' if never synced since powerup for DCF C51
78c0b746e5SOllivier Robert  *                 = '#' if not PZF sychronisation available for PZF 535/509
79c0b746e5SOllivier Robert  *                 = ' ' if ok
80c0b746e5SOllivier Robert  * <F>             = '*' if time comes from internal quartz
81c0b746e5SOllivier Robert  *                 = ' ' if completely synched
82c0b746e5SOllivier Robert  * <D>             = 'S' if daylight saving time is active
83c0b746e5SOllivier Robert  *                 = 'U' if time is represented in UTC
84c0b746e5SOllivier Robert  *                 = ' ' if no special condition exists
85c0b746e5SOllivier Robert  * <A>             = '!' during the hour preceeding an daylight saving time
86c0b746e5SOllivier Robert  *                       start/end change
87c0b746e5SOllivier Robert  *                 = 'A' leap second insert warning
88c0b746e5SOllivier Robert  *                 = ' ' if no special condition exists
89c0b746e5SOllivier Robert  *
90c0b746e5SOllivier Robert  * Extended data format (PZFUERL for PZF type clocks)
91c0b746e5SOllivier Robert  *
92c0b746e5SOllivier Robert  *     <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
93c0b746e5SOllivier Robert  * pos:  0   00 0 00 0 00 11 1 11 11 1 11 2 22 22 2  2  2  2  2  3  3   3
94c0b746e5SOllivier Robert  *       1   23 4 56 7 89 01 2 34 56 7 89 0 12 34 5  6  7  8  9  0  1   2
95c0b746e5SOllivier Robert  * <STX>           = '\002' ASCII start of text
96c0b746e5SOllivier Robert  * <ETX>           = '\003' ASCII end of text
97c0b746e5SOllivier Robert  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
98c0b746e5SOllivier Robert  * <w>             = day of week (sunday= 0)
99c0b746e5SOllivier Robert  * <hh>,<mm>,<ss>  = hour, minute, second
100c0b746e5SOllivier Robert  * <U>             = 'U' UTC time display
101c0b746e5SOllivier Robert  * <S>             = '#' if never synced since powerup else ' ' for DCF C51
102c0b746e5SOllivier Robert  *                   '#' if not PZF sychronisation available else ' ' for PZF 535/509
103c0b746e5SOllivier Robert  * <F>             = '*' if time comes from internal quartz else ' '
104c0b746e5SOllivier Robert  * <D>             = 'S' if daylight saving time is active else ' '
105c0b746e5SOllivier Robert  * <A>             = '!' during the hour preceeding an daylight saving time
106c0b746e5SOllivier Robert  *                       start/end change
107c0b746e5SOllivier Robert  * <L>             = 'A' LEAP second announcement
108a25439b6SCy Schubert  * <R>             = 'R' "call bit" used to signalize irregularities in the control facilities,
109a25439b6SCy Schubert  *                   usually ' ', until 2003 indicated transmission via alternate antenna
110c0b746e5SOllivier Robert  *
111a25439b6SCy Schubert  * Meinberg GPS receivers
112c0b746e5SOllivier Robert  *
113a25439b6SCy Schubert  * For very old devices you must get the Uni-Erlangen firmware for the GPS receiver support
114c0b746e5SOllivier Robert  * to work to full satisfaction !
115a25439b6SCy Schubert  * With newer GPS receiver types the Uni Erlangen string format can be configured at the device.
116c0b746e5SOllivier Robert  *
117c0b746e5SOllivier Robert  *     <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
118c0b746e5SOllivier Robert  *
119c0b746e5SOllivier Robert  *        000000000111111111122222222223333333333444444444455555555556666666
120c0b746e5SOllivier Robert  *        123456789012345678901234567890123456789012345678901234567890123456
121c0b746e5SOllivier Robert  *     \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N  11.0280E  373m\x03
122c0b746e5SOllivier Robert  *
123c0b746e5SOllivier Robert  *
124c0b746e5SOllivier Robert  * <STX>           = '\002' ASCII start of text
125c0b746e5SOllivier Robert  * <ETX>           = '\003' ASCII end of text
126c0b746e5SOllivier Robert  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
127c0b746e5SOllivier Robert  * <w>             = day of week (sunday= 0)
128c0b746e5SOllivier Robert  * <hh>,<mm>,<ss>  = hour, minute, second
129c0b746e5SOllivier Robert  * <+/->,<00:00>   = offset to UTC
130c0b746e5SOllivier Robert  * <S>             = '#' if never synced since powerup else ' '
131c0b746e5SOllivier Robert  * <F>             = '*' if position is not confirmed else ' '
132c0b746e5SOllivier Robert  * <D>             = 'S' if daylight saving time is active else ' '
133c0b746e5SOllivier Robert  * <A>             = '!' during the hour preceeding an daylight saving time
134c0b746e5SOllivier Robert  *                       start/end change
135c0b746e5SOllivier Robert  * <L>             = 'A' LEAP second announcement
136a25439b6SCy Schubert  * <R>             = 'R' "call bit" used to signalize irregularities in the control facilities,
137a25439b6SCy Schubert  *                   usually ' ', until 2003 indicated transmission via alternate antenna
138a25439b6SCy Schubert  *                   (reminiscent of PZF receivers)
139c0b746e5SOllivier Robert  * <L>             = 'L' on 23:59:60
140c0b746e5SOllivier Robert  *
141c0b746e5SOllivier Robert  * Binary messages have a lead in for a fixed header of SOH
142c0b746e5SOllivier Robert  */
143c0b746e5SOllivier Robert 
144c0b746e5SOllivier Robert /*--------------------------------------------------------------*/
145c0b746e5SOllivier Robert /* Name:         csum()                                         */
146c0b746e5SOllivier Robert /*                                                              */
147c0b746e5SOllivier Robert /* Purpose:      Compute a checksum about a number of bytes     */
148c0b746e5SOllivier Robert /*                                                              */
149c0b746e5SOllivier Robert /* Input:        uchar *p    address of the first byte          */
150c0b746e5SOllivier Robert /*               short n     the number of bytes                */
151c0b746e5SOllivier Robert /*                                                              */
152c0b746e5SOllivier Robert /* Output:       --                                             */
153c0b746e5SOllivier Robert /*                                                              */
154c0b746e5SOllivier Robert /* Ret val:      the checksum                                   */
155c0b746e5SOllivier Robert /*+-------------------------------------------------------------*/
156c0b746e5SOllivier Robert 
157a25439b6SCy Schubert CSUM
158c0b746e5SOllivier Robert mbg_csum(
159c0b746e5SOllivier Robert 	 unsigned char *p,
160c0b746e5SOllivier Robert 	 unsigned int n
161c0b746e5SOllivier Robert 	 )
162c0b746e5SOllivier Robert {
163a25439b6SCy Schubert   unsigned int sum = 0;
1642b15cb3dSCy Schubert   unsigned int i;
165c0b746e5SOllivier Robert 
166c0b746e5SOllivier Robert   for ( i = 0; i < n; i++ )
167c0b746e5SOllivier Robert     sum += *p++;
168c0b746e5SOllivier Robert 
169a25439b6SCy Schubert   return (CSUM) sum;
170a25439b6SCy Schubert 
171c0b746e5SOllivier Robert }  /* csum */
172c0b746e5SOllivier Robert 
173c0b746e5SOllivier Robert void
174c0b746e5SOllivier Robert get_mbg_header(
175c0b746e5SOllivier Robert 	       unsigned char **bufpp,
176c0b746e5SOllivier Robert 	       GPS_MSG_HDR *headerp
177c0b746e5SOllivier Robert 	       )
178c0b746e5SOllivier Robert {
179a25439b6SCy Schubert   headerp->cmd = (GPS_CMD) get_lsb_short(bufpp);
180a25439b6SCy Schubert   headerp->len = get_lsb_uint16(bufpp);
181a25439b6SCy Schubert   headerp->data_csum = (CSUM) get_lsb_short(bufpp);
182a25439b6SCy Schubert   headerp->hdr_csum  = (CSUM) get_lsb_short(bufpp);
183c0b746e5SOllivier Robert }
184c0b746e5SOllivier Robert 
185c0b746e5SOllivier Robert static struct format meinberg_fmt[] =
186c0b746e5SOllivier Robert {
187c0b746e5SOllivier Robert 	{
188c0b746e5SOllivier Robert 		{
189c0b746e5SOllivier Robert 			{ 3, 2},  {  6, 2}, {  9, 2},
190c0b746e5SOllivier Robert 			{ 18, 2}, { 21, 2}, { 24, 2},
191c0b746e5SOllivier Robert 			{ 14, 1}, { 27, 4}, { 29, 1},
192c0b746e5SOllivier Robert 		},
193c0b746e5SOllivier Robert 		(const unsigned char *)"\2D:  .  .  ;T: ;U:  .  .  ;    \3",
194c0b746e5SOllivier Robert 		0
195c0b746e5SOllivier Robert 	},
196c0b746e5SOllivier Robert 	{			/* special extended FAU Erlangen extended format */
197c0b746e5SOllivier Robert 		{
198c0b746e5SOllivier Robert 			{ 1, 2},  { 4,  2}, {  7, 2},
199c0b746e5SOllivier Robert 			{ 14, 2}, { 17, 2}, { 20, 2},
200c0b746e5SOllivier Robert 			{ 11, 1}, { 25, 4}, { 27, 1},
201c0b746e5SOllivier Robert 		},
202c0b746e5SOllivier Robert 		(const unsigned char *)"\2  .  .  ;  ;   :  :  ;        \3",
203c0b746e5SOllivier Robert 		MBG_EXTENDED
204c0b746e5SOllivier Robert 	},
205c0b746e5SOllivier Robert 	{			/* special extended FAU Erlangen GPS format */
206c0b746e5SOllivier Robert 		{
207c0b746e5SOllivier Robert 			{ 1,  2}, {  4, 2}, {  7, 2},
208c0b746e5SOllivier Robert 			{ 14, 2}, { 17, 2}, { 20, 2},
209c0b746e5SOllivier Robert 			{ 11, 1}, { 32, 7}, { 35, 1},
210c0b746e5SOllivier Robert 			{ 25, 2}, { 28, 2}, { 24, 1}
211c0b746e5SOllivier Robert 		},
212c0b746e5SOllivier Robert 		(const unsigned char *)"\2  .  .  ;  ;   :  :  ;    :  ;        ;   .         .       ",
213c0b746e5SOllivier Robert 		0
214c0b746e5SOllivier Robert 	}
215c0b746e5SOllivier Robert };
216c0b746e5SOllivier Robert 
217a25439b6SCy Schubert static parse_cvt_fnc_t cvt_meinberg;
218a25439b6SCy Schubert static parse_cvt_fnc_t cvt_mgps;
219a25439b6SCy Schubert static parse_inp_fnc_t mbg_input;
220a25439b6SCy Schubert static parse_inp_fnc_t gps_input;
221c0b746e5SOllivier Robert 
222c0b746e5SOllivier Robert struct msg_buf
223c0b746e5SOllivier Robert {
224c0b746e5SOllivier Robert   unsigned short len;		/* len to fill */
225c0b746e5SOllivier Robert   unsigned short phase;		/* current input phase */
226c0b746e5SOllivier Robert };
227c0b746e5SOllivier Robert 
228c0b746e5SOllivier Robert #define MBG_NONE	0	/* no data input */
229c0b746e5SOllivier Robert #define MBG_HEADER	1	/* receiving header */
230c0b746e5SOllivier Robert #define MBG_DATA	2	/* receiving data */
231c0b746e5SOllivier Robert #define MBG_STRING      3	/* receiving standard data message */
232c0b746e5SOllivier Robert 
233c0b746e5SOllivier Robert clockformat_t clock_meinberg[] =
234c0b746e5SOllivier Robert {
235c0b746e5SOllivier Robert 	{
236c0b746e5SOllivier Robert 		mbg_input,	/* normal input handling */
237c0b746e5SOllivier Robert 		cvt_meinberg,	/* Meinberg conversion */
238c0b746e5SOllivier Robert 		pps_one,	/* easy PPS monitoring */
239c0b746e5SOllivier Robert 		0,		/* conversion configuration */
240c0b746e5SOllivier Robert 		"Meinberg Standard", /* Meinberg simple format - beware */
241c0b746e5SOllivier Robert 		32,				/* string buffer */
242a25439b6SCy Schubert 		0		/* no private data (complete packets) */
243c0b746e5SOllivier Robert 	},
244c0b746e5SOllivier Robert 	{
245c0b746e5SOllivier Robert 		mbg_input,	/* normal input handling */
246c0b746e5SOllivier Robert 		cvt_meinberg,	/* Meinberg conversion */
247c0b746e5SOllivier Robert 		pps_one,	/* easy PPS monitoring */
248c0b746e5SOllivier Robert 		0,		/* conversion configuration */
249c0b746e5SOllivier Robert 		"Meinberg Extended", /* Meinberg enhanced format */
250c0b746e5SOllivier Robert 		32,		/* string buffer */
251a25439b6SCy Schubert 		0		/* no private data (complete packets) */
252c0b746e5SOllivier Robert 	},
253c0b746e5SOllivier Robert 	{
254c0b746e5SOllivier Robert 		gps_input,	/* no input handling */
255a25439b6SCy Schubert 		cvt_mgps,	/* Meinberg GPS receiver conversion */
256c0b746e5SOllivier Robert 		pps_one,	/* easy PPS monitoring */
257c0b746e5SOllivier Robert 		(void *)&meinberg_fmt[2], /* conversion configuration */
258c0b746e5SOllivier Robert 		"Meinberg GPS Extended",  /* Meinberg FAU GPS format */
259c0b746e5SOllivier Robert 		512,		/* string buffer */
260a25439b6SCy Schubert 		sizeof(struct msg_buf)	/* no private data (complete packets) */
261c0b746e5SOllivier Robert 	}
262c0b746e5SOllivier Robert };
263c0b746e5SOllivier Robert 
264c0b746e5SOllivier Robert /*
265a25439b6SCy Schubert  * parse_cvt_fnc_t cvt_meinberg
266c0b746e5SOllivier Robert  *
267c0b746e5SOllivier Robert  * convert simple type format
268c0b746e5SOllivier Robert  */
269c0b746e5SOllivier Robert static u_long
270c0b746e5SOllivier Robert cvt_meinberg(
271c0b746e5SOllivier Robert 	     unsigned char *buffer,
272c0b746e5SOllivier Robert 	     int            size,
273c0b746e5SOllivier Robert 	     struct format *unused,
274c0b746e5SOllivier Robert 	     clocktime_t   *clock_time,
275c0b746e5SOllivier Robert 	     void          *local
276c0b746e5SOllivier Robert 	     )
277c0b746e5SOllivier Robert {
278c0b746e5SOllivier Robert 	struct format *format;
279c0b746e5SOllivier Robert 
280c0b746e5SOllivier Robert 	/*
281c0b746e5SOllivier Robert 	 * select automagically correct data format
282c0b746e5SOllivier Robert 	 */
283c0b746e5SOllivier Robert 	if (Strok(buffer, meinberg_fmt[0].fixed_string))
284c0b746e5SOllivier Robert 	{
285c0b746e5SOllivier Robert 		format = &meinberg_fmt[0];
286c0b746e5SOllivier Robert 	}
287c0b746e5SOllivier Robert 	else
288c0b746e5SOllivier Robert 	{
289c0b746e5SOllivier Robert 		if (Strok(buffer, meinberg_fmt[1].fixed_string))
290c0b746e5SOllivier Robert 		{
291c0b746e5SOllivier Robert 			format = &meinberg_fmt[1];
292c0b746e5SOllivier Robert 		}
293c0b746e5SOllivier Robert 		else
294c0b746e5SOllivier Robert 		{
295c0b746e5SOllivier Robert 			return CVT_FAIL|CVT_BADFMT;
296c0b746e5SOllivier Robert 		}
297c0b746e5SOllivier Robert 	}
298c0b746e5SOllivier Robert 
299c0b746e5SOllivier Robert 	/*
300c0b746e5SOllivier Robert 	 * collect data
301c0b746e5SOllivier Robert 	 */
302c0b746e5SOllivier Robert 	if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
303c0b746e5SOllivier Robert 		 format->field_offsets[O_DAY].length) ||
304c0b746e5SOllivier Robert 	    Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
305c0b746e5SOllivier Robert 		 format->field_offsets[O_MONTH].length) ||
306c0b746e5SOllivier Robert 	    Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
307c0b746e5SOllivier Robert 		 format->field_offsets[O_YEAR].length) ||
308c0b746e5SOllivier Robert 	    Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
309c0b746e5SOllivier Robert 		 format->field_offsets[O_HOUR].length) ||
310c0b746e5SOllivier Robert 	    Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
311c0b746e5SOllivier Robert 		 format->field_offsets[O_MIN].length) ||
312c0b746e5SOllivier Robert 	    Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
313c0b746e5SOllivier Robert 		 format->field_offsets[O_SEC].length))
314c0b746e5SOllivier Robert 	{
315c0b746e5SOllivier Robert 		return CVT_FAIL|CVT_BADFMT;
316c0b746e5SOllivier Robert 	}
317c0b746e5SOllivier Robert 	else
318c0b746e5SOllivier Robert 	{
319c0b746e5SOllivier Robert 		unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
320c0b746e5SOllivier Robert 
321c0b746e5SOllivier Robert 		clock_time->usecond = 0;
322c0b746e5SOllivier Robert 		clock_time->flags   = PARSEB_S_LEAP;
323c0b746e5SOllivier Robert 
324c0b746e5SOllivier Robert 		if (clock_time->second == 60)
325c0b746e5SOllivier Robert 			clock_time->flags |= PARSEB_LEAPSECOND;
326c0b746e5SOllivier Robert 
327c0b746e5SOllivier Robert 		/*
328c0b746e5SOllivier Robert 		 * in the extended timecode format we have also the
329c0b746e5SOllivier Robert 		 * indication that the timecode is in UTC
330c0b746e5SOllivier Robert 		 * for compatibilty reasons we start at the USUAL
331c0b746e5SOllivier Robert 		 * offset (POWERUP flag) and know that the UTC indication
332c0b746e5SOllivier Robert 		 * is the character before the powerup flag
333c0b746e5SOllivier Robert 		 */
334c0b746e5SOllivier Robert 		if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U'))
335c0b746e5SOllivier Robert 		{
336c0b746e5SOllivier Robert 			/*
337c0b746e5SOllivier Robert 			 * timecode is in UTC
338c0b746e5SOllivier Robert 			 */
339c0b746e5SOllivier Robert 			clock_time->utcoffset = 0; /* UTC */
340c0b746e5SOllivier Robert 			clock_time->flags    |= PARSEB_UTC;
341c0b746e5SOllivier Robert 		}
342c0b746e5SOllivier Robert 		else
343c0b746e5SOllivier Robert 		{
344c0b746e5SOllivier Robert 			/*
345c0b746e5SOllivier Robert 			 * only calculate UTC offset if MET/MED is in time code
346c0b746e5SOllivier Robert 			 * or we have the old time code format, where we do not
347c0b746e5SOllivier Robert 			 * know whether it is UTC time or MET/MED
348c0b746e5SOllivier Robert 			 * pray that nobody switches to UTC in the *old* standard time code
349c0b746e5SOllivier Robert 			 * ROMS !!!! The new ROMS have 'U' at the ZONE field - good.
350c0b746e5SOllivier Robert 			 */
351c0b746e5SOllivier Robert 			switch (buffer[format->field_offsets[O_ZONE].offset])
352c0b746e5SOllivier Robert 			{
353c0b746e5SOllivier Robert 			case ' ':
354c0b746e5SOllivier Robert 				clock_time->utcoffset = -1*60*60; /* MET */
355c0b746e5SOllivier Robert 				break;
356c0b746e5SOllivier Robert 
357c0b746e5SOllivier Robert 			case 'S':
358c0b746e5SOllivier Robert 				clock_time->utcoffset = -2*60*60; /* MED */
359c0b746e5SOllivier Robert 				break;
360c0b746e5SOllivier Robert 
361c0b746e5SOllivier Robert 			case 'U':
362c0b746e5SOllivier Robert 				/*
363c0b746e5SOllivier Robert 				 * timecode is in UTC
364c0b746e5SOllivier Robert 				 */
365c0b746e5SOllivier Robert 				clock_time->utcoffset = 0;        /* UTC */
366c0b746e5SOllivier Robert 				clock_time->flags    |= PARSEB_UTC;
367c0b746e5SOllivier Robert 				break;
368c0b746e5SOllivier Robert 
369c0b746e5SOllivier Robert 			default:
370c0b746e5SOllivier Robert 				return CVT_FAIL|CVT_BADFMT;
371c0b746e5SOllivier Robert 			}
372c0b746e5SOllivier Robert 		}
373c0b746e5SOllivier Robert 
374c0b746e5SOllivier Robert 		/*
375c0b746e5SOllivier Robert 		 * gather status flags
376c0b746e5SOllivier Robert 		 */
377c0b746e5SOllivier Robert 		if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
378c0b746e5SOllivier Robert 			clock_time->flags    |= PARSEB_DST;
379c0b746e5SOllivier Robert 
380c0b746e5SOllivier Robert 		if (f[0] == '#')
381c0b746e5SOllivier Robert 			clock_time->flags |= PARSEB_POWERUP;
382c0b746e5SOllivier Robert 
383c0b746e5SOllivier Robert 		if (f[1] == '*')
384c0b746e5SOllivier Robert 			clock_time->flags |= PARSEB_NOSYNC;
385c0b746e5SOllivier Robert 
386c0b746e5SOllivier Robert 		if (f[3] == '!')
387c0b746e5SOllivier Robert 			clock_time->flags |= PARSEB_ANNOUNCE;
388c0b746e5SOllivier Robert 
389c0b746e5SOllivier Robert 		/*
390c0b746e5SOllivier Robert 		 * oncoming leap second
391c0b746e5SOllivier Robert 		 * 'a' code not confirmed - earth is not
392c0b746e5SOllivier Robert 		 * expected to speed up
393c0b746e5SOllivier Robert 		 */
394c0b746e5SOllivier Robert 		if (f[3] == 'A')
395c0b746e5SOllivier Robert 			clock_time->flags |= PARSEB_LEAPADD;
396c0b746e5SOllivier Robert 
397c0b746e5SOllivier Robert 		if (f[3] == 'a')
398c0b746e5SOllivier Robert 			clock_time->flags |= PARSEB_LEAPDEL;
399c0b746e5SOllivier Robert 
400c0b746e5SOllivier Robert 
401c0b746e5SOllivier Robert 		if (format->flags & MBG_EXTENDED)
402c0b746e5SOllivier Robert 		{
403276da39aSCy Schubert 			clock_time->flags |= PARSEB_S_CALLBIT;
404c0b746e5SOllivier Robert 
405c0b746e5SOllivier Robert 			/*
406c0b746e5SOllivier Robert 			 * DCF77 does not encode the direction -
407c0b746e5SOllivier Robert 			 * so we take the current default -
408c0b746e5SOllivier Robert 			 * earth slowing down
409c0b746e5SOllivier Robert 			 */
410c0b746e5SOllivier Robert 			clock_time->flags &= ~PARSEB_LEAPDEL;
411c0b746e5SOllivier Robert 
412c0b746e5SOllivier Robert 			if (f[4] == 'A')
413c0b746e5SOllivier Robert 				clock_time->flags |= PARSEB_LEAPADD;
414c0b746e5SOllivier Robert 
415c0b746e5SOllivier Robert 			if (f[5] == 'R')
416a25439b6SCy Schubert 				clock_time->flags |= PARSEB_CALLBIT;
417c0b746e5SOllivier Robert 		}
418c0b746e5SOllivier Robert 		return CVT_OK;
419c0b746e5SOllivier Robert 	}
420c0b746e5SOllivier Robert }
421c0b746e5SOllivier Robert 
422c0b746e5SOllivier Robert 
423c0b746e5SOllivier Robert /*
424a25439b6SCy Schubert  * parse_inp_fnc_t mbg_input
425c0b746e5SOllivier Robert  *
426a25439b6SCy Schubert  * grab data from input stream
427c0b746e5SOllivier Robert  */
428c0b746e5SOllivier Robert static u_long
429c0b746e5SOllivier Robert mbg_input(
430c0b746e5SOllivier Robert 	  parse_t      *parseio,
431a25439b6SCy Schubert 	  char         ch,
432c0b746e5SOllivier Robert 	  timestamp_t  *tstamp
433c0b746e5SOllivier Robert 	  )
434c0b746e5SOllivier Robert {
435c0b746e5SOllivier Robert 	unsigned int rtc;
436c0b746e5SOllivier Robert 
4373311ff84SXin LI 	parseprintf(DD_PARSE, ("mbg_input(0x%p, 0x%x, ...)\n", (void*)parseio, ch));
438c0b746e5SOllivier Robert 
439c0b746e5SOllivier Robert 	switch (ch)
440c0b746e5SOllivier Robert 	{
441c0b746e5SOllivier Robert 	case STX:
442c0b746e5SOllivier Robert 		parseprintf(DD_PARSE, ("mbg_input: STX seen\n"));
443c0b746e5SOllivier Robert 
444c0b746e5SOllivier Robert 		parseio->parse_index = 1;
445c0b746e5SOllivier Robert 		parseio->parse_data[0] = ch;
446c0b746e5SOllivier Robert 		parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
447c0b746e5SOllivier Robert 		return PARSE_INP_SKIP;
448c0b746e5SOllivier Robert 
449c0b746e5SOllivier Robert 	case ETX:
450c0b746e5SOllivier Robert 		parseprintf(DD_PARSE, ("mbg_input: ETX seen\n"));
451c0b746e5SOllivier Robert 		if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
452c0b746e5SOllivier Robert 			return parse_end(parseio);
453c0b746e5SOllivier Robert 		else
454c0b746e5SOllivier Robert 			return rtc;
455c0b746e5SOllivier Robert 
456c0b746e5SOllivier Robert 	default:
457c0b746e5SOllivier Robert 		return parse_addchar(parseio, ch);
458c0b746e5SOllivier Robert 	}
459c0b746e5SOllivier Robert }
460c0b746e5SOllivier Robert 
461c0b746e5SOllivier Robert 
462c0b746e5SOllivier Robert /*
463a25439b6SCy Schubert  * parse_cvt_fnc_t cvt_mgps
464c0b746e5SOllivier Robert  *
465c0b746e5SOllivier Robert  * convert Meinberg GPS format
466c0b746e5SOllivier Robert  */
467c0b746e5SOllivier Robert static u_long
468c0b746e5SOllivier Robert cvt_mgps(
469c0b746e5SOllivier Robert 	 unsigned char *buffer,
470c0b746e5SOllivier Robert 	 int            size,
471c0b746e5SOllivier Robert 	 struct format *format,
472c0b746e5SOllivier Robert 	 clocktime_t   *clock_time,
473c0b746e5SOllivier Robert 	 void          *local
474c0b746e5SOllivier Robert 	)
475c0b746e5SOllivier Robert {
476c0b746e5SOllivier Robert 	if (!Strok(buffer, format->fixed_string))
477c0b746e5SOllivier Robert 	{
478c0b746e5SOllivier Robert 		return cvt_meinberg(buffer, size, format, clock_time, local);
479c0b746e5SOllivier Robert 	}
480c0b746e5SOllivier Robert 	else
481c0b746e5SOllivier Robert 	{
482c0b746e5SOllivier Robert 		if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
483c0b746e5SOllivier Robert 			 format->field_offsets[O_DAY].length) ||
484c0b746e5SOllivier Robert 		    Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
485c0b746e5SOllivier Robert 			 format->field_offsets[O_MONTH].length) ||
486c0b746e5SOllivier Robert 		    Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
487c0b746e5SOllivier Robert 			 format->field_offsets[O_YEAR].length) ||
488c0b746e5SOllivier Robert 		    Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
489c0b746e5SOllivier Robert 			 format->field_offsets[O_HOUR].length) ||
490c0b746e5SOllivier Robert 		    Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
491c0b746e5SOllivier Robert 			 format->field_offsets[O_MIN].length) ||
492c0b746e5SOllivier Robert 		    Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
493c0b746e5SOllivier Robert 			 format->field_offsets[O_SEC].length))
494c0b746e5SOllivier Robert 		{
495c0b746e5SOllivier Robert 			return CVT_FAIL|CVT_BADFMT;
496c0b746e5SOllivier Robert 		}
497c0b746e5SOllivier Robert 		else
498c0b746e5SOllivier Robert 		{
499c0b746e5SOllivier Robert 			long h;
500c0b746e5SOllivier Robert 			unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
501c0b746e5SOllivier Robert 
502c0b746e5SOllivier Robert 			clock_time->flags = PARSEB_S_LEAP|PARSEB_S_POSITION;
503c0b746e5SOllivier Robert 
504c0b746e5SOllivier Robert 			clock_time->usecond = 0;
505c0b746e5SOllivier Robert 
506c0b746e5SOllivier Robert 			/*
507c0b746e5SOllivier Robert 			 * calculate UTC offset
508c0b746e5SOllivier Robert 			 */
509c0b746e5SOllivier Robert 			if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h,
510c0b746e5SOllivier Robert 				 format->field_offsets[O_UTCHOFFSET].length))
511c0b746e5SOllivier Robert 			{
512c0b746e5SOllivier Robert 				return CVT_FAIL|CVT_BADFMT;
513c0b746e5SOllivier Robert 			}
514c0b746e5SOllivier Robert 			else
515c0b746e5SOllivier Robert 			{
516c0b746e5SOllivier Robert 				if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock_time->utcoffset,
517c0b746e5SOllivier Robert 					 format->field_offsets[O_UTCMOFFSET].length))
518c0b746e5SOllivier Robert 				{
519c0b746e5SOllivier Robert 					return CVT_FAIL|CVT_BADFMT;
520c0b746e5SOllivier Robert 				}
521c0b746e5SOllivier Robert 
522c0b746e5SOllivier Robert 				clock_time->utcoffset += TIMES60(h);
523c0b746e5SOllivier Robert 				clock_time->utcoffset  = TIMES60(clock_time->utcoffset);
524c0b746e5SOllivier Robert 
525c0b746e5SOllivier Robert 				if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-')
526c0b746e5SOllivier Robert 				{
527c0b746e5SOllivier Robert 					clock_time->utcoffset = -clock_time->utcoffset;
528c0b746e5SOllivier Robert 				}
529c0b746e5SOllivier Robert 			}
530c0b746e5SOllivier Robert 
531c0b746e5SOllivier Robert 			/*
532c0b746e5SOllivier Robert 			 * gather status flags
533c0b746e5SOllivier Robert 			 */
534c0b746e5SOllivier Robert 			if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
535c0b746e5SOllivier Robert 			    clock_time->flags    |= PARSEB_DST;
536c0b746e5SOllivier Robert 
537c0b746e5SOllivier Robert 			if (clock_time->utcoffset == 0)
538c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_UTC;
539c0b746e5SOllivier Robert 
540c0b746e5SOllivier Robert 			/*
541c0b746e5SOllivier Robert 			 * no sv's seen - no time & position
542c0b746e5SOllivier Robert 			 */
543c0b746e5SOllivier Robert 			if (f[0] == '#')
544c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_POWERUP;
545c0b746e5SOllivier Robert 
546c0b746e5SOllivier Robert 			/*
547c0b746e5SOllivier Robert 			 * at least one sv seen - time (for last position)
548c0b746e5SOllivier Robert 			 */
549c0b746e5SOllivier Robert 			if (f[1] == '*')
550c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_NOSYNC;
551c0b746e5SOllivier Robert 			else
552c0b746e5SOllivier Robert 			    if (!(clock_time->flags & PARSEB_POWERUP))
553c0b746e5SOllivier Robert 				clock_time->flags |= PARSEB_POSITION;
554c0b746e5SOllivier Robert 
555c0b746e5SOllivier Robert 			/*
556c0b746e5SOllivier Robert 			 * oncoming zone switch
557c0b746e5SOllivier Robert 			 */
558c0b746e5SOllivier Robert 			if (f[3] == '!')
559c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_ANNOUNCE;
560c0b746e5SOllivier Robert 
561c0b746e5SOllivier Robert 			/*
562c0b746e5SOllivier Robert 			 * oncoming leap second
563c0b746e5SOllivier Robert 			 * 'a' code not confirmed - earth is not
564c0b746e5SOllivier Robert 			 * expected to speed up
565c0b746e5SOllivier Robert 			 */
566c0b746e5SOllivier Robert 			if (f[4] == 'A')
567c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_LEAPADD;
568c0b746e5SOllivier Robert 
569c0b746e5SOllivier Robert 			if (f[4] == 'a')
570c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_LEAPDEL;
571c0b746e5SOllivier Robert 
572c0b746e5SOllivier Robert 			/*
573c0b746e5SOllivier Robert 			 * f[5] == ' '
574c0b746e5SOllivier Robert 			 */
575c0b746e5SOllivier Robert 
576c0b746e5SOllivier Robert 			/*
577c0b746e5SOllivier Robert 			 * this is the leap second
578c0b746e5SOllivier Robert 			 */
579c0b746e5SOllivier Robert 			if ((f[6] == 'L') || (clock_time->second == 60))
580c0b746e5SOllivier Robert 			    clock_time->flags |= PARSEB_LEAPSECOND;
581c0b746e5SOllivier Robert 
582c0b746e5SOllivier Robert 			return CVT_OK;
583c0b746e5SOllivier Robert 		}
584c0b746e5SOllivier Robert 	}
585c0b746e5SOllivier Robert }
586c0b746e5SOllivier Robert 
587c0b746e5SOllivier Robert /*
588a25439b6SCy Schubert  * parse_inp_fnc_t gps_input
589c0b746e5SOllivier Robert  *
590c0b746e5SOllivier Robert  * grep binary data from input stream
591c0b746e5SOllivier Robert  */
592c0b746e5SOllivier Robert static u_long
593c0b746e5SOllivier Robert gps_input(
594c0b746e5SOllivier Robert 	  parse_t      *parseio,
595a25439b6SCy Schubert 	  char ch,
596c0b746e5SOllivier Robert 	  timestamp_t  *tstamp
597c0b746e5SOllivier Robert 	  )
598c0b746e5SOllivier Robert {
599c0b746e5SOllivier Robert   CSUM calc_csum;                    /* used to compare the incoming csums */
600c0b746e5SOllivier Robert   GPS_MSG_HDR header;
601c0b746e5SOllivier Robert   struct msg_buf *msg_buf;
602c0b746e5SOllivier Robert 
603c0b746e5SOllivier Robert   msg_buf = (struct msg_buf *)parseio->parse_pdata;
604c0b746e5SOllivier Robert 
6053311ff84SXin LI   parseprintf(DD_PARSE, ("gps_input(0x%p, 0x%x, ...)\n", (void*)parseio, ch));
606c0b746e5SOllivier Robert 
607c0b746e5SOllivier Robert   if (!msg_buf)
608c0b746e5SOllivier Robert     return PARSE_INP_SKIP;
609c0b746e5SOllivier Robert 
610c0b746e5SOllivier Robert   if ( msg_buf->phase == MBG_NONE )
611c0b746e5SOllivier Robert     {                  /* not receiving yet */
612c0b746e5SOllivier Robert       switch (ch)
613c0b746e5SOllivier Robert 	{
614c0b746e5SOllivier Robert 	case SOH:
615c0b746e5SOllivier Robert 	  parseprintf(DD_PARSE, ("gps_input: SOH seen\n"));
616c0b746e5SOllivier Robert 
617c0b746e5SOllivier Robert 	  msg_buf->len = sizeof( header ); /* prepare to receive msg header */
618c0b746e5SOllivier Robert 	  msg_buf->phase = MBG_HEADER; /* receiving header */
619c0b746e5SOllivier Robert 	  break;
620c0b746e5SOllivier Robert 
621c0b746e5SOllivier Robert 	case STX:
622c0b746e5SOllivier Robert 	  parseprintf(DD_PARSE, ("gps_input: STX seen\n"));
623c0b746e5SOllivier Robert 
624c0b746e5SOllivier Robert 	  msg_buf->len = 0;
625c0b746e5SOllivier Robert 	  msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */
626c0b746e5SOllivier Robert 	  parseio->parse_index = 1;
627c0b746e5SOllivier Robert 	  parseio->parse_data[0] = ch;
628c0b746e5SOllivier Robert 	  break;
629c0b746e5SOllivier Robert 
630c0b746e5SOllivier Robert 	default:
631c0b746e5SOllivier Robert 	  return PARSE_INP_SKIP;	/* keep searching */
632c0b746e5SOllivier Robert 	}
633c0b746e5SOllivier Robert 
634c0b746e5SOllivier Robert       parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */
635c0b746e5SOllivier Robert       parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */
636c0b746e5SOllivier Robert       parseio->parse_dtime.parse_stime  = *tstamp; /* collect timestamp */
637c0b746e5SOllivier Robert       return PARSE_INP_SKIP;
638c0b746e5SOllivier Robert     }
639c0b746e5SOllivier Robert 
640c0b746e5SOllivier Robert   /* SOH/STX has already been received */
641c0b746e5SOllivier Robert 
642c0b746e5SOllivier Robert   /* save incoming character in both buffers if needbe */
643c0b746e5SOllivier Robert   if ((msg_buf->phase == MBG_STRING) &&
644c0b746e5SOllivier Robert       (parseio->parse_index < parseio->parse_dsize))
645c0b746e5SOllivier Robert     parseio->parse_data[parseio->parse_index++] = ch;
646c0b746e5SOllivier Robert 
647c0b746e5SOllivier Robert   parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
648c0b746e5SOllivier Robert 
649c0b746e5SOllivier Robert   if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg))
650c0b746e5SOllivier Robert     {
651c0b746e5SOllivier Robert       msg_buf->phase = MBG_NONE; /* buffer overflow - discard */
652c0b746e5SOllivier Robert       parseio->parse_data[parseio->parse_index] = '\0';
653c0b746e5SOllivier Robert       memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
654ea906c41SOllivier Robert       parseio->parse_ldsize = parseio->parse_index;
655c0b746e5SOllivier Robert       return PARSE_INP_DATA;
656c0b746e5SOllivier Robert     }
657c0b746e5SOllivier Robert 
658c0b746e5SOllivier Robert   switch (msg_buf->phase)
659c0b746e5SOllivier Robert     {
660c0b746e5SOllivier Robert     case MBG_HEADER:
661c0b746e5SOllivier Robert     case MBG_DATA:
662c0b746e5SOllivier Robert       msg_buf->len--;
663c0b746e5SOllivier Robert 
664c0b746e5SOllivier Robert       if ( msg_buf->len )               /* transfer not complete */
665c0b746e5SOllivier Robert 	return PARSE_INP_SKIP;
666c0b746e5SOllivier Robert 
667c0b746e5SOllivier Robert       parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header"));
668c0b746e5SOllivier Robert 
669c0b746e5SOllivier Robert       break;
670c0b746e5SOllivier Robert 
671c0b746e5SOllivier Robert     case MBG_STRING:
672c0b746e5SOllivier Robert       if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize))
673c0b746e5SOllivier Robert 	{
674c0b746e5SOllivier Robert 	  msg_buf->phase = MBG_NONE;
675c0b746e5SOllivier Robert 	  parseprintf(DD_PARSE, ("gps_input: string complete\n"));
676c0b746e5SOllivier Robert 	  parseio->parse_data[parseio->parse_index] = '\0';
677c0b746e5SOllivier Robert 	  memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
678ea906c41SOllivier Robert 	  parseio->parse_ldsize = parseio->parse_index;
679c0b746e5SOllivier Robert 	  parseio->parse_index = 0;
680c0b746e5SOllivier Robert 	  return PARSE_INP_TIME;
681c0b746e5SOllivier Robert 	}
682c0b746e5SOllivier Robert       else
683c0b746e5SOllivier Robert 	{
684c0b746e5SOllivier Robert 	  return PARSE_INP_SKIP;
685c0b746e5SOllivier Robert 	}
686c0b746e5SOllivier Robert     }
687c0b746e5SOllivier Robert 
688c0b746e5SOllivier Robert   /* cnt == 0, so the header or the whole message is complete */
689c0b746e5SOllivier Robert 
690c0b746e5SOllivier Robert   if ( msg_buf->phase == MBG_HEADER )
691c0b746e5SOllivier Robert     {         /* header complete now */
692c0b746e5SOllivier Robert       unsigned char *datap = parseio->parse_dtime.parse_msg + 1;
693c0b746e5SOllivier Robert 
694c0b746e5SOllivier Robert       get_mbg_header(&datap, &header);
695c0b746e5SOllivier Robert 
696c0b746e5SOllivier Robert       parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n",
697a25439b6SCy Schubert 			     (int)header.cmd, (int)header.len, (int)header.data_csum,
698a25439b6SCy Schubert 			     (int)header.hdr_csum));
699c0b746e5SOllivier Robert 
700c0b746e5SOllivier Robert 
701c0b746e5SOllivier Robert       calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 );
702c0b746e5SOllivier Robert 
703a25439b6SCy Schubert       if ( calc_csum != header.hdr_csum )
704c0b746e5SOllivier Robert 	{
705c0b746e5SOllivier Robert 	  parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n",
706c0b746e5SOllivier Robert 				 (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 )));
707c0b746e5SOllivier Robert 
708c0b746e5SOllivier Robert 	  msg_buf->phase = MBG_NONE;  /* back to hunting mode */
709c0b746e5SOllivier Robert 	  return PARSE_INP_DATA;      /* invalid header checksum received - pass up for detection */
710c0b746e5SOllivier Robert 	}
711c0b746e5SOllivier Robert 
712a25439b6SCy Schubert       if ((header.len == 0)  ||       /* no data to wait for */
713a25439b6SCy Schubert 	  (header.len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1)))	/* blows anything we have space for */
714c0b746e5SOllivier Robert 	{
715c0b746e5SOllivier Robert 	  msg_buf->phase = MBG_NONE;  /* back to hunting mode */
716a25439b6SCy Schubert 	  return (header.len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */
717c0b746e5SOllivier Robert 	}
718c0b746e5SOllivier Robert 
719a25439b6SCy Schubert       parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.len));
720c0b746e5SOllivier Robert 
721a25439b6SCy Schubert       msg_buf->len   = header.len;/* save number of bytes to wait for */
722c0b746e5SOllivier Robert       msg_buf->phase = MBG_DATA;      /* flag header already complete */
723c0b746e5SOllivier Robert       return PARSE_INP_SKIP;
724c0b746e5SOllivier Robert     }
725c0b746e5SOllivier Robert 
726c0b746e5SOllivier Robert   parseprintf(DD_PARSE, ("gps_input: message data complete\n"));
727c0b746e5SOllivier Robert 
728c0b746e5SOllivier Robert   /* Header and data have been received. The header checksum has been */
729c0b746e5SOllivier Robert   /* checked */
730c0b746e5SOllivier Robert 
731c0b746e5SOllivier Robert   msg_buf->phase = MBG_NONE;	      /* back to hunting mode */
732c0b746e5SOllivier Robert   return PARSE_INP_DATA;              /* message complete, must be evaluated */
733c0b746e5SOllivier Robert }
734c0b746e5SOllivier Robert 
735c0b746e5SOllivier Robert #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
736*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT
737c0b746e5SOllivier Robert #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
738c0b746e5SOllivier Robert 
739c0b746e5SOllivier Robert /*
740c0b746e5SOllivier Robert  * History:
741c0b746e5SOllivier Robert  *
742c0b746e5SOllivier Robert  * clk_meinberg.c,v
743ea906c41SOllivier Robert  * Revision 4.12.2.1  2005/09/25 10:22:35  kardel
744ea906c41SOllivier Robert  * cleanup buffer bounds
745ea906c41SOllivier Robert  *
746ea906c41SOllivier Robert  * Revision 4.12  2005/04/16 17:32:10  kardel
747ea906c41SOllivier Robert  * update copyright
748ea906c41SOllivier Robert  *
749ea906c41SOllivier Robert  * Revision 4.11  2004/11/14 15:29:41  kardel
750ea906c41SOllivier Robert  * support PPSAPI, upgrade Copyright to Berkeley style
751ea906c41SOllivier Robert  *
752a151a66cSOllivier Robert  * Revision 4.8  1999/11/28 09:13:50  kardel
753a151a66cSOllivier Robert  * RECON_4_0_98F
754a151a66cSOllivier Robert  *
755c0b746e5SOllivier Robert  * Revision 4.7  1999/02/21 11:09:14  kardel
756c0b746e5SOllivier Robert  * cleanup
757c0b746e5SOllivier Robert  *
758c0b746e5SOllivier Robert  * Revision 4.6  1998/06/14 21:09:36  kardel
759c0b746e5SOllivier Robert  * Sun acc cleanup
760c0b746e5SOllivier Robert  *
761c0b746e5SOllivier Robert  * Revision 4.5  1998/06/13 15:18:54  kardel
762c0b746e5SOllivier Robert  * fix mem*() to b*() function macro emulation
763c0b746e5SOllivier Robert  *
764c0b746e5SOllivier Robert  * Revision 4.4  1998/06/13 12:03:23  kardel
765c0b746e5SOllivier Robert  * fix SYSV clock name clash
766c0b746e5SOllivier Robert  *
767c0b746e5SOllivier Robert  * Revision 4.3  1998/06/12 15:22:28  kardel
768c0b746e5SOllivier Robert  * fix prototypes
769c0b746e5SOllivier Robert  *
770c0b746e5SOllivier Robert  * Revision 4.2  1998/05/24 16:14:42  kardel
771c0b746e5SOllivier Robert  * support current Meinberg standard data formats
772c0b746e5SOllivier Robert  *
773c0b746e5SOllivier Robert  * Revision 4.1  1998/05/24 09:39:52  kardel
774c0b746e5SOllivier Robert  * implementation of the new IO handling model
775c0b746e5SOllivier Robert  *
776c0b746e5SOllivier Robert  * Revision 4.0  1998/04/10 19:45:29  kardel
777c0b746e5SOllivier Robert  * Start 4.0 release version numbering
778c0b746e5SOllivier Robert  *
779c0b746e5SOllivier Robert  * from V3 3.23 - log info deleted 1998/04/11 kardel
780c0b746e5SOllivier Robert  *
781c0b746e5SOllivier Robert  */
782