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 54 static parse_inp_fnc_t inp_sel240x; 55 static parse_cvt_fnc_t cvt_sel240x; 56 57 // Parse clock format structure describing the message above 58 static 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 77 clockformat_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 ////////////////////////////////////////////////////////////////////////////// 89 static unsigned long 90 inp_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 ////////////////////////////////////////////////////////////////////////////// 122 static unsigned long 123 cvt_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) */ 171 NONEMPTY_TRANSLATION_UNIT 172 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */ 173