clk_sel240x.c revision 280849
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 unsigned long inp_sel240x( parse_t *parseio,
55		                  unsigned int ch,
56				  timestamp_t *tstamp);
57static unsigned long cvt_sel240x( unsigned char *buffer,
58		                  int size,
59				  struct format *format,
60				  clocktime_t *clock_time,
61				  void *local );
62
63// Parse clock format structure describing the message above
64static struct format sel240x_fmt =
65{ { {  6, 3 },
66    {  0, 0 },
67    {  1, 4 },
68    { 10, 2 },
69    { 13, 2 },
70    { 16, 2 },
71    {  0, 0 },
72    {  0, 0 },
73    {  0, 0 },
74    {  0, 0 },
75    {  0, 0 },
76    {  0, 0 }
77  },
78  (const unsigned char *)"\x01    :   :  :  :   \x0d\x0a",
79  0
80};
81
82// Structure desctibing the parser
83clockformat_t clock_sel240x =
84{
85	inp_sel240x,
86	cvt_sel240x,
87	pps_one,
88	(void*)&sel240x_fmt,
89	"SEL B8",
90	25,
91	0
92};
93
94//////////////////////////////////////////////////////////////////////////////
95static unsigned long
96inp_sel240x( parse_t      *parseio,
97	     unsigned int ch,
98	     timestamp_t  *tstamp
99	   )
100{
101	unsigned long rc;
102
103	parseprintf( DD_PARSE,
104	             ("inp_sel240x(0x%lx, 0x%x, ...)\n",(long)parseio, ch));
105
106	switch( ch )
107	{
108	case '\x01':
109		parseio->parse_index = 1;
110		parseio->parse_data[0] = ch;
111		parseio->parse_dtime.parse_stime = *tstamp;
112		rc = PARSE_INP_SKIP;
113		break;
114	case '\n':
115		if( (rc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP )
116		{
117			rc = parse_end( parseio );
118		}
119		break;
120	default:
121		rc = parse_addchar( parseio, ch );
122	}
123
124	return rc;
125}
126
127//////////////////////////////////////////////////////////////////////////////
128static unsigned long
129cvt_sel240x( unsigned char *buffer,
130	     int            size,
131	     struct format *format,
132	     clocktime_t   *clock_time,
133	     void          *local
134	   )
135{
136	unsigned long rc = CVT_NONE;
137
138	if( Strok(buffer, format->fixed_string) )
139	{
140		struct tm ptime;
141		buffer++;
142		buffer = (unsigned char *) strptime(
143			(const char *)buffer, "%Y:%j:%H:%M:%S", &ptime );
144		if( *(buffer+1) != '\x0d' )
145		{
146			rc = CVT_FAIL | CVT_BADFMT;
147		}
148		else
149		{
150			clock_time->day = ptime.tm_mday;
151			clock_time->month = ptime.tm_mon + 1;
152			clock_time->year = ptime.tm_year + 1900;
153			clock_time->hour = ptime.tm_hour;
154			clock_time->minute = ptime.tm_min;
155			clock_time->second = ptime.tm_sec;
156			clock_time->usecond = 0;
157			clock_time->utcoffset = 0;
158			clock_time->flags = PARSEB_UTC;
159
160			if( *buffer == '?' )
161			{
162				clock_time->flags |= PARSEB_POWERUP;
163			}
164			else if( *buffer != ' ' )
165			{
166				clock_time->flags |= PARSEB_NOSYNC;
167			}
168
169			rc = CVT_OK;
170		}
171	}
172
173	return rc;
174}
175
176#else  /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */
177int clk_sel240x_bs;
178#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */
179