1*eabc0478Schristos /* $NetBSD: clk_sel240x.c,v 1.7 2024/08/18 20:47:17 christos Exp $ */ 28585484eSchristos 38585484eSchristos ////////////////////////////////////////////////////////////////////////////// 48585484eSchristos // Copyright (c) 2009,2012 - 58585484eSchristos // Schweitzer Engineering Laboratories, Inc. <opensource@selinc.com> 68585484eSchristos ////////////////////////////////////////////////////////////////////////////// 78585484eSchristos 88585484eSchristos // Need to have _XOPEN_SOURCE defined for time.h to give the 98585484eSchristos // correct strptime signature. As per feature_test_macros(7), 108585484eSchristos // define this before including any header files. 118585484eSchristos 128585484eSchristos // #ifndef _XOPEN_SOURCE 138585484eSchristos // #define _XOPEN_SOURCE 148585484eSchristos // #endif 158585484eSchristos 168585484eSchristos #ifdef HAVE_CONFIG_H 178585484eSchristos # include <config.h> 188585484eSchristos #endif 198585484eSchristos 208585484eSchristos #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_SEL240X) 218585484eSchristos 228585484eSchristos #include "ntp_syslog.h" 238585484eSchristos #include "ntp_types.h" 248585484eSchristos #include "ntp_fp.h" 258585484eSchristos #include "ntp_unixtime.h" 268585484eSchristos #include "ntp_calendar.h" 278585484eSchristos #include "ntp_machine.h" 288585484eSchristos #include "ntp_stdlib.h" 298585484eSchristos 308585484eSchristos #include "parse.h" 318585484eSchristos 328585484eSchristos #ifndef PARSESTREAM 338585484eSchristos # include <stdio.h> 348585484eSchristos #else 358585484eSchristos # include "sys/parsestreams.h" 368585484eSchristos #endif 378585484eSchristos 388585484eSchristos #include <time.h> 398585484eSchristos 408585484eSchristos ////////////////////////////////////////////////////////////////////////////// 418585484eSchristos // The B8 output has the following format B8 = '\x01YYYY:ddd:hh:mm:ssq\r\n' 428585484eSchristos // where q = ' ' locked 438585484eSchristos // '.' <1 us 448585484eSchristos // '*' <10 us 458585484eSchristos // '#' <100 us 468585484eSchristos // '?' >100 us 478585484eSchristos // 488585484eSchristos // Based on this we need to recored the stime when we receive the <SOH> 498585484eSchristos // character and end it when we see the \n. 508585484eSchristos // 518585484eSchristos // The q or quality character indicates satellite lock and sync. For the 528585484eSchristos // purposes of NTP we are going to call it valid when we receive anything but 538585484eSchristos // a '?'. But we are only going to call it synced when we receive a ' ' 548585484eSchristos ////////////////////////////////////////////////////////////////////////////// 558585484eSchristos 567476e6e4Schristos static parse_inp_fnc_t inp_sel240x; 577476e6e4Schristos static parse_cvt_fnc_t cvt_sel240x; 588585484eSchristos 598585484eSchristos // Parse clock format structure describing the message above 608585484eSchristos static struct format sel240x_fmt = 618585484eSchristos { { { 6, 3 }, 628585484eSchristos { 0, 0 }, 638585484eSchristos { 1, 4 }, 648585484eSchristos { 10, 2 }, 658585484eSchristos { 13, 2 }, 668585484eSchristos { 16, 2 }, 678585484eSchristos { 0, 0 }, 688585484eSchristos { 0, 0 }, 698585484eSchristos { 0, 0 }, 708585484eSchristos { 0, 0 }, 718585484eSchristos { 0, 0 }, 728585484eSchristos { 0, 0 } 738585484eSchristos }, 748585484eSchristos (const unsigned char *)"\x01 : : : : \x0d\x0a", 758585484eSchristos 0 768585484eSchristos }; 778585484eSchristos 788585484eSchristos // Structure desctibing the parser 798585484eSchristos clockformat_t clock_sel240x = 808585484eSchristos { 818585484eSchristos inp_sel240x, 828585484eSchristos cvt_sel240x, 838585484eSchristos pps_one, 848585484eSchristos (void*)&sel240x_fmt, 858585484eSchristos "SEL B8", 868585484eSchristos 25, 878585484eSchristos 0 888585484eSchristos }; 898585484eSchristos 908585484eSchristos ////////////////////////////////////////////////////////////////////////////// 918585484eSchristos static unsigned long 928585484eSchristos inp_sel240x( parse_t *parseio, 937476e6e4Schristos char ch, 948585484eSchristos timestamp_t *tstamp 958585484eSchristos ) 968585484eSchristos { 978585484eSchristos unsigned long rc; 988585484eSchristos 998585484eSchristos parseprintf( DD_PARSE, 1008585484eSchristos ("inp_sel240x(0x%lx, 0x%x, ...)\n",(long)parseio, ch)); 1018585484eSchristos 1028585484eSchristos switch( ch ) 1038585484eSchristos { 1048585484eSchristos case '\x01': 1058585484eSchristos parseio->parse_index = 1; 1068585484eSchristos parseio->parse_data[0] = ch; 1078585484eSchristos parseio->parse_dtime.parse_stime = *tstamp; 1088585484eSchristos rc = PARSE_INP_SKIP; 1098585484eSchristos break; 1108585484eSchristos case '\n': 1118585484eSchristos if( (rc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP ) 1128585484eSchristos { 1138585484eSchristos rc = parse_end( parseio ); 1148585484eSchristos } 1158585484eSchristos break; 1168585484eSchristos default: 1178585484eSchristos rc = parse_addchar( parseio, ch ); 1188585484eSchristos } 1198585484eSchristos 1208585484eSchristos return rc; 1218585484eSchristos } 1228585484eSchristos 1238585484eSchristos ////////////////////////////////////////////////////////////////////////////// 1248585484eSchristos static unsigned long 1258585484eSchristos cvt_sel240x( unsigned char *buffer, 1268585484eSchristos int size, 1278585484eSchristos struct format *format, 1288585484eSchristos clocktime_t *clock_time, 1298585484eSchristos void *local 1308585484eSchristos ) 1318585484eSchristos { 1328585484eSchristos unsigned long rc = CVT_NONE; 1338585484eSchristos 1348585484eSchristos if( Strok(buffer, format->fixed_string) ) 1358585484eSchristos { 1368585484eSchristos struct tm ptime; 1378585484eSchristos buffer++; 1388585484eSchristos buffer = (unsigned char *) strptime( 1398585484eSchristos (const char *)buffer, "%Y:%j:%H:%M:%S", &ptime ); 1408585484eSchristos if( *(buffer+1) != '\x0d' ) 1418585484eSchristos { 1428585484eSchristos rc = CVT_FAIL | CVT_BADFMT; 1438585484eSchristos } 1448585484eSchristos else 1458585484eSchristos { 1468585484eSchristos clock_time->day = ptime.tm_mday; 1478585484eSchristos clock_time->month = ptime.tm_mon + 1; 1488585484eSchristos clock_time->year = ptime.tm_year + 1900; 1498585484eSchristos clock_time->hour = ptime.tm_hour; 1508585484eSchristos clock_time->minute = ptime.tm_min; 1518585484eSchristos clock_time->second = ptime.tm_sec; 1528585484eSchristos clock_time->usecond = 0; 1538585484eSchristos clock_time->utcoffset = 0; 1548585484eSchristos clock_time->flags = PARSEB_UTC; 1558585484eSchristos 1568585484eSchristos if( *buffer == '?' ) 1578585484eSchristos { 1588585484eSchristos clock_time->flags |= PARSEB_POWERUP; 1598585484eSchristos } 1608585484eSchristos else if( *buffer != ' ' ) 1618585484eSchristos { 1628585484eSchristos clock_time->flags |= PARSEB_NOSYNC; 1638585484eSchristos } 1648585484eSchristos 1658585484eSchristos rc = CVT_OK; 1668585484eSchristos } 1678585484eSchristos } 1688585484eSchristos 1698585484eSchristos return rc; 1708585484eSchristos } 1718585484eSchristos 1728585484eSchristos #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */ 173*eabc0478Schristos NONEMPTY_TRANSLATION_UNIT 1748585484eSchristos #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SEL240X) */ 175