1290001Sglebius//////////////////////////////////////////////////////////////////////////////
2290001Sglebius// Copyright (c) 2009,2012 -
3290001Sglebius//        Schweitzer Engineering Laboratories, Inc. <opensource@selinc.com>
4290001Sglebius//////////////////////////////////////////////////////////////////////////////
5290001Sglebius
6290001Sglebius// Need to have _XOPEN_SOURCE defined for time.h to give the
7290001Sglebius// correct strptime signature.  As per feature_test_macros(7),
8290001Sglebius// define this before including any header files.
9290001Sglebius
10290001Sglebius// #ifndef _XOPEN_SOURCE
11290001Sglebius// #define _XOPEN_SOURCE
12290001Sglebius// #endif
13290001Sglebius
14290001Sglebius#ifdef HAVE_CONFIG_H
15290001Sglebius# include <config.h>
16290001Sglebius#endif
17290001Sglebius
18290001Sglebius#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_SEL240X)
19290001Sglebius
20290001Sglebius#include "ntp_syslog.h"
21290001Sglebius#include "ntp_types.h"
22290001Sglebius#include "ntp_fp.h"
23290001Sglebius#include "ntp_unixtime.h"
24290001Sglebius#include "ntp_calendar.h"
25290001Sglebius#include "ntp_machine.h"
26290001Sglebius#include "ntp_stdlib.h"
27290001Sglebius
28290001Sglebius#include "parse.h"
29290001Sglebius
30290001Sglebius#ifndef PARSESTREAM
31290001Sglebius# include <stdio.h>
32290001Sglebius#else
33290001Sglebius# include "sys/parsestreams.h"
34290001Sglebius#endif
35290001Sglebius
36290001Sglebius#include <time.h>
37290001Sglebius
38290001Sglebius//////////////////////////////////////////////////////////////////////////////
39290001Sglebius// The B8 output has the following format B8 = '\x01YYYY:ddd:hh:mm:ssq\r\n'
40290001Sglebius//    where q = ' ' locked
41290001Sglebius//              '.' <1 us
42290001Sglebius//              '*' <10 us
43290001Sglebius//              '#' <100 us
44290001Sglebius//              '?' >100 us
45290001Sglebius//
46290001Sglebius// Based on this we need to recored the stime when we receive the <SOH>
47290001Sglebius// character and end it when we see the \n.
48290001Sglebius//
49290001Sglebius// The q or quality character indicates satellite lock and sync.   For the
50290001Sglebius// purposes of NTP we are going to call it valid when we receive anything but
51290001Sglebius// a '?'.  But we are only going to call it synced when we receive a ' '
52290001Sglebius//////////////////////////////////////////////////////////////////////////////
53290001Sglebius
54290001Sglebiusstatic parse_inp_fnc_t inp_sel240x;
55290001Sglebiusstatic parse_cvt_fnc_t cvt_sel240x;
56290001Sglebius
57290001Sglebius// Parse clock format structure describing the message above
58290001Sglebiusstatic struct format sel240x_fmt =
59290001Sglebius{ { {  6, 3 },
60290001Sglebius    {  0, 0 },
61290001Sglebius    {  1, 4 },
62290001Sglebius    { 10, 2 },
63290001Sglebius    { 13, 2 },
64290001Sglebius    { 16, 2 },
65290001Sglebius    {  0, 0 },
66290001Sglebius    {  0, 0 },
67290001Sglebius    {  0, 0 },
68290001Sglebius    {  0, 0 },
69290001Sglebius    {  0, 0 },
70290001Sglebius    {  0, 0 }
71290001Sglebius  },
72290001Sglebius  (const unsigned char *)"\x01    :   :  :  :   \x0d\x0a",
73290001Sglebius  0
74290001Sglebius};
75290001Sglebius
76290001Sglebius// Structure desctibing the parser
77290001Sglebiusclockformat_t clock_sel240x =
78290001Sglebius{
79290001Sglebius	inp_sel240x,
80290001Sglebius	cvt_sel240x,
81290001Sglebius	pps_one,
82290001Sglebius	(void*)&sel240x_fmt,
83290001Sglebius	"SEL B8",
84290001Sglebius	25,
85290001Sglebius	0
86290001Sglebius};
87290001Sglebius
88290001Sglebius//////////////////////////////////////////////////////////////////////////////
89290001Sglebiusstatic unsigned long
90290001Sglebiusinp_sel240x( parse_t      *parseio,
91290001Sglebius	     char         ch,
92290001Sglebius	     timestamp_t  *tstamp
93290001Sglebius	   )
94290001Sglebius{
95290001Sglebius	unsigned long rc;
96290001Sglebius
97290001Sglebius	parseprintf( DD_PARSE,
98290001Sglebius	             ("inp_sel240x(0x%lx, 0x%x, ...)\n",(long)parseio, ch));
99290001Sglebius
100290001Sglebius	switch( ch )
101290001Sglebius	{
102290001Sglebius	case '\x01':
103290001Sglebius		parseio->parse_index = 1;
104290001Sglebius		parseio->parse_data[0] = ch;
105290001Sglebius		parseio->parse_dtime.parse_stime = *tstamp;
106290001Sglebius		rc = PARSE_INP_SKIP;
107290001Sglebius		break;
108290001Sglebius	case '\n':
109290001Sglebius		if( (rc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP )
110290001Sglebius		{
111290001Sglebius			rc = parse_end( parseio );
112290001Sglebius		}
113290001Sglebius		break;
114290001Sglebius	default:
115290001Sglebius		rc = parse_addchar( parseio, ch );
116290001Sglebius	}
117290001Sglebius
118290001Sglebius	return rc;
119290001Sglebius}
120290001Sglebius
121290001Sglebius//////////////////////////////////////////////////////////////////////////////
122290001Sglebiusstatic unsigned long
123290001Sglebiuscvt_sel240x( unsigned char *buffer,
124290001Sglebius	     int            size,
125290001Sglebius	     struct format *format,
126290001Sglebius	     clocktime_t   *clock_time,
127290001Sglebius	     void          *local
128290001Sglebius	   )
129290001Sglebius{
130290001Sglebius	unsigned long rc = CVT_NONE;
131290001Sglebius
132290001Sglebius	if( Strok(buffer, format->fixed_string) )
133290001Sglebius	{
134290001Sglebius		struct tm ptime;
135290001Sglebius		buffer++;
136290001Sglebius		buffer = (unsigned char *) strptime(
137290001Sglebius			(const char *)buffer, "%Y:%j:%H:%M:%S", &ptime );
138290001Sglebius		if( *(buffer+1) != '\x0d' )
139290001Sglebius		{
140290001Sglebius			rc = CVT_FAIL | CVT_BADFMT;
141290001Sglebius		}
142290001Sglebius		else
143290001Sglebius		{
144290001Sglebius			clock_time->day = ptime.tm_mday;
145290001Sglebius			clock_time->month = ptime.tm_mon + 1;
146290001Sglebius			clock_time->year = ptime.tm_year + 1900;
147290001Sglebius			clock_time->hour = ptime.tm_hour;
148290001Sglebius			clock_time->minute = ptime.tm_min;
149290001Sglebius			clock_time->second = ptime.tm_sec;
150290001Sglebius			clock_time->usecond = 0;
151290001Sglebius			clock_time->utcoffset = 0;
152290001Sglebius			clock_time->flags = PARSEB_UTC;
153290001Sglebius
154290001Sglebius			if( *buffer == '?' )
155290001Sglebius			{
156290001Sglebius				clock_time->flags |= PARSEB_POWERUP;
157290001Sglebius			}
158290001Sglebius			else if( *buffer != ' ' )
159290001Sglebius			{
160290001Sglebius				clock_time->flags |= PARSEB_NOSYNC;
161290001Sglebius			}
162290001Sglebius
163290001Sglebius			rc = CVT_OK;
164290001Sglebius		}
165290001Sglebius	}
166290001Sglebius
167290001Sglebius	return rc;
168290001Sglebius}
169290001Sglebius
170290001Sglebius#else  /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */
171290001Sglebiusint clk_sel240x_bs;
172290001Sglebius#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */
173