1//////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2009,2012 -
3//        Schweitzer Engineering Laboratories, Inc. <opensource@selinc.com>
4//////////////////////////////////////////////////////////////////////////////
5
6// Need to have _XOPEN_SOURCE defined for time.h to give the
7// correct strptime signature.  As per feature_test_macros(7),
8// define this before including any header files.
9
10// #ifndef _XOPEN_SOURCE
11// #define _XOPEN_SOURCE
12// #endif
13
14#ifdef HAVE_CONFIG_H
15# include <config.h>
16#endif
17
18#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_SEL240X)
19
20#include "ntp_syslog.h"
21#include "ntp_types.h"
22#include "ntp_fp.h"
23#include "ntp_unixtime.h"
24#include "ntp_calendar.h"
25#include "ntp_machine.h"
26#include "ntp_stdlib.h"
27
28#include "parse.h"
29
30#ifndef PARSESTREAM
31# include <stdio.h>
32#else
33# include "sys/parsestreams.h"
34#endif
35
36#include <time.h>
37
38//////////////////////////////////////////////////////////////////////////////
39// The B8 output has the following format B8 = '\x01YYYY:ddd:hh:mm:ssq\r\n'
40//    where q = ' ' locked
41//              '.' <1 us
42//              '*' <10 us
43//              '#' <100 us
44//              '?' >100 us
45//
46// Based on this we need to recored the stime when we receive the <SOH>
47// character and end it when we see the \n.
48//
49// The q or quality character indicates satellite lock and sync.   For the
50// purposes of NTP we are going to call it valid when we receive anything but
51// a '?'.  But we are only going to call it synced when we receive a ' '
52//////////////////////////////////////////////////////////////////////////////
53
54static parse_inp_fnc_t inp_sel240x;
55static parse_cvt_fnc_t cvt_sel240x;
56
57// Parse clock format structure describing the message above
58static struct format sel240x_fmt =
59{ { {  6, 3 },
60    {  0, 0 },
61    {  1, 4 },
62    { 10, 2 },
63    { 13, 2 },
64    { 16, 2 },
65    {  0, 0 },
66    {  0, 0 },
67    {  0, 0 },
68    {  0, 0 },
69    {  0, 0 },
70    {  0, 0 }
71  },
72  (const unsigned char *)"\x01    :   :  :  :   \x0d\x0a",
73  0
74};
75
76// Structure desctibing the parser
77clockformat_t clock_sel240x =
78{
79	inp_sel240x,
80	cvt_sel240x,
81	pps_one,
82	(void*)&sel240x_fmt,
83	"SEL B8",
84	25,
85	0
86};
87
88//////////////////////////////////////////////////////////////////////////////
89static unsigned long
90inp_sel240x( parse_t      *parseio,
91	     char         ch,
92	     timestamp_t  *tstamp
93	   )
94{
95	unsigned long rc;
96
97	parseprintf( DD_PARSE,
98	             ("inp_sel240x(0x%lx, 0x%x, ...)\n",(long)parseio, ch));
99
100	switch( ch )
101	{
102	case '\x01':
103		parseio->parse_index = 1;
104		parseio->parse_data[0] = ch;
105		parseio->parse_dtime.parse_stime = *tstamp;
106		rc = PARSE_INP_SKIP;
107		break;
108	case '\n':
109		if( (rc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP )
110		{
111			rc = parse_end( parseio );
112		}
113		break;
114	default:
115		rc = parse_addchar( parseio, ch );
116	}
117
118	return rc;
119}
120
121//////////////////////////////////////////////////////////////////////////////
122static unsigned long
123cvt_sel240x( unsigned char *buffer,
124	     int            size,
125	     struct format *format,
126	     clocktime_t   *clock_time,
127	     void          *local
128	   )
129{
130	unsigned long rc = CVT_NONE;
131
132	if( Strok(buffer, format->fixed_string) )
133	{
134		struct tm ptime;
135		buffer++;
136		buffer = (unsigned char *) strptime(
137			(const char *)buffer, "%Y:%j:%H:%M:%S", &ptime );
138		if( *(buffer+1) != '\x0d' )
139		{
140			rc = CVT_FAIL | CVT_BADFMT;
141		}
142		else
143		{
144			clock_time->day = ptime.tm_mday;
145			clock_time->month = ptime.tm_mon + 1;
146			clock_time->year = ptime.tm_year + 1900;
147			clock_time->hour = ptime.tm_hour;
148			clock_time->minute = ptime.tm_min;
149			clock_time->second = ptime.tm_sec;
150			clock_time->usecond = 0;
151			clock_time->utcoffset = 0;
152			clock_time->flags = PARSEB_UTC;
153
154			if( *buffer == '?' )
155			{
156				clock_time->flags |= PARSEB_POWERUP;
157			}
158			else if( *buffer != ' ' )
159			{
160				clock_time->flags |= PARSEB_NOSYNC;
161			}
162
163			rc = CVT_OK;
164		}
165	}
166
167	return rc;
168}
169
170#else  /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */
171int clk_sel240x_bs;
172#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */
173