154359Sroberto/* 2182007Sroberto * /src/NTP/ntp4-dev/libparse/clk_wharton.c,v 4.2 2004/11/14 15:29:41 kardel RELEASE_20050508_A 354359Sroberto * 4182007Sroberto * clk_wharton.c,v 4.2 2004/11/14 15:29:41 kardel RELEASE_20050508_A 554359Sroberto * 654359Sroberto * From Philippe De Muyter <phdm@macqel.be>, 1999 754359Sroberto */ 854359Sroberto#ifdef HAVE_CONFIG_H 954359Sroberto#include <config.h> 1054359Sroberto#endif 1154359Sroberto 1254359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_WHARTON_400A) 1354359Sroberto/* 1454359Sroberto * Support for WHARTON 400A Series clock + 404.2 serial interface. 1554359Sroberto * 1682498Sroberto * Copyright (C) 1999, 2000 by Philippe De Muyter <phdm@macqel.be> 1754359Sroberto * 1854359Sroberto * This program is distributed in the hope that it will be useful, but WITHOUT 1954359Sroberto * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2054359Sroberto * FITNESS FOR A PARTICULAR PURPOSE. 2154359Sroberto * 2254359Sroberto */ 2354359Sroberto 2454359Sroberto#include "ntp_fp.h" 2554359Sroberto#include "ascii.h" 2654359Sroberto#include "parse.h" 2754359Sroberto 2854359Sroberto#ifndef PARSESTREAM 2954359Sroberto#include "ntp_stdlib.h" 3054359Sroberto#include <stdio.h> 3154359Sroberto#else 3254359Sroberto#include "sys/parsestreams.h" 3354359Srobertoextern void printf P((const char *, ...)); 3454359Sroberto#endif 3554359Sroberto 3654359Sroberto/* 3754359Sroberto * In private e-mail alastair@wharton.co.uk said : 3854359Sroberto * "If you are going to use the 400A and 404.2 system [for ntp] I recommend 3954359Sroberto * that you set the 400A to output the message every second. The start of 4054359Sroberto * transmission of the first byte of the message is synchronised to the 4154359Sroberto * second edge." 4254359Sroberto * The WHARTON 400A Series is able to send date/time serial messages 4354359Sroberto * in 7 output formats. We use format 1 here because it is the shortest. 4454359Sroberto * For use with this driver, the WHARTON 400A Series clock must be set-up 4554359Sroberto * as follows : 4654359Sroberto * Programmable Selected 4754359Sroberto * Option No Option 4854359Sroberto * BST or CET display 3 9 or 11 4954359Sroberto * No external controller 7 0 5054359Sroberto * Serial Output Format 1 9 1 5154359Sroberto * Baud rate 9600 bps 10 96 5254359Sroberto * Bit length 8 bits 11 8 5354359Sroberto * Parity even 12 E 5454359Sroberto * 5554359Sroberto * WHARTON 400A Series output format 1 is as follows : 5654359Sroberto * 5754359Sroberto * Timestamp STXssmmhhDDMMYYSETX 5854359Sroberto * Pos 0 12345678901234 5954359Sroberto * 0 00000000011111 6054359Sroberto * 6154359Sroberto * STX start transmission (ASCII 0x02) 6254359Sroberto * ETX end transmission (ASCII 0x03) 6354359Sroberto * ss Second expressed in reversed decimal (units then tens) 6454359Sroberto * mm Minute expressed in reversed decimal 6554359Sroberto * hh Hour expressed in reversed decimal 6654359Sroberto * DD Day of month expressed in reversed decimal 6754359Sroberto * MM Month expressed in reversed decimal (January is 1) 6854359Sroberto * YY Year (without century) expressed in reversed decimal 6954359Sroberto * S Status byte : 0x30 + 7054359Sroberto * bit 0 0 = MSF source 1 = DCF source 7154359Sroberto * bit 1 0 = Winter time 1 = Summer time 7254359Sroberto * bit 2 0 = not synchronised 1 = synchronised 7354359Sroberto * bit 3 0 = no early warning 1 = early warning 7454359Sroberto * 7554359Sroberto */ 7654359Sroberto 7754359Sroberto/* 7854359Sroberto * cvt_wharton_400a 7954359Sroberto * 8054359Sroberto * convert simple type format 8154359Sroberto */ 8254359Srobertostatic u_long 8354359Srobertocvt_wharton_400a( 8454359Sroberto unsigned char *buffer, 8554359Sroberto int size, 8654359Sroberto struct format *format, 8754359Sroberto clocktime_t *clock_time, 8854359Sroberto void *local 8954359Sroberto ) 9054359Sroberto{ 9154359Sroberto int i; 9254359Sroberto 9354359Sroberto /* The given `size' includes a terminating null-character. */ 9482498Sroberto if (size != 16 || buffer[0] != STX || buffer[14] != ETX 9582498Sroberto || buffer[13] < '0' || buffer[13] > ('0' + 0xf)) 9654359Sroberto return CVT_NONE; 9782498Sroberto for (i = 1; i < 13; i += 1) 9854359Sroberto if (buffer[i] < '0' || buffer[i] > '9') 9954359Sroberto return CVT_NONE; 10054359Sroberto clock_time->second = (buffer[2] - '0') * 10 + buffer[1] - '0'; 10154359Sroberto clock_time->minute = (buffer[4] - '0') * 10 + buffer[3] - '0'; 10254359Sroberto clock_time->hour = (buffer[6] - '0') * 10 + buffer[5] - '0'; 10354359Sroberto clock_time->day = (buffer[8] - '0') * 10 + buffer[7] - '0'; 10454359Sroberto clock_time->month = (buffer[10] - '0') * 10 + buffer[9] - '0'; 10554359Sroberto clock_time->year = (buffer[12] - '0') * 10 + buffer[11] - '0'; 10654359Sroberto clock_time->usecond = 0; 10754359Sroberto if (buffer[13] & 0x1) /* We have CET time */ 10854359Sroberto clock_time->utcoffset = -1*60*60; 10954359Sroberto else /* We have BST time */ 11054359Sroberto clock_time->utcoffset = 0; 11154359Sroberto if (buffer[13] & 0x2) { 11254359Sroberto clock_time->flags |= PARSEB_DST; 11354359Sroberto clock_time->utcoffset += -1*60*60; 11454359Sroberto } 11554359Sroberto if (!(buffer[13] & 0x4)) 11654359Sroberto clock_time->flags |= PARSEB_NOSYNC; 11754359Sroberto if (buffer[13] & 0x8) 11854359Sroberto clock_time->flags |= PARSEB_ANNOUNCE; 11954359Sroberto 12054359Sroberto return CVT_OK; 12154359Sroberto} 12254359Sroberto 12354359Sroberto/* 12454359Sroberto * inp_wharton_400a 12554359Sroberto * 12654359Sroberto * grep data from input stream 12754359Sroberto */ 12854359Srobertostatic u_long 12954359Srobertoinp_wharton_400a( 13054359Sroberto parse_t *parseio, 13154359Sroberto unsigned int ch, 13254359Sroberto timestamp_t *tstamp 13354359Sroberto ) 13454359Sroberto{ 13554359Sroberto unsigned int rtc; 13654359Sroberto 13782498Sroberto parseprintf(DD_PARSE, ("inp_wharton_400a(0x%lx, 0x%x, ...)\n", (long)parseio, ch)); 13854359Sroberto 13954359Sroberto switch (ch) 14054359Sroberto { 14154359Sroberto case STX: 14254359Sroberto parseprintf(DD_PARSE, ("inp_wharton_400a: STX seen\n")); 14354359Sroberto 14454359Sroberto parseio->parse_index = 1; 14554359Sroberto parseio->parse_data[0] = ch; 14654359Sroberto parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ 14754359Sroberto return PARSE_INP_SKIP; 14854359Sroberto 14954359Sroberto case ETX: 15054359Sroberto parseprintf(DD_PARSE, ("inp_wharton_400a: ETX seen\n")); 15154359Sroberto if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) 15254359Sroberto return parse_end(parseio); 15354359Sroberto else 15454359Sroberto return rtc; 15554359Sroberto 15654359Sroberto default: 15754359Sroberto return parse_addchar(parseio, ch); 15854359Sroberto } 15954359Sroberto} 16054359Sroberto 16154359Srobertoclockformat_t clock_wharton_400a = 16254359Sroberto{ 16354359Sroberto inp_wharton_400a, /* input handling function */ 16454359Sroberto cvt_wharton_400a, /* conversion function */ 16554359Sroberto 0, /* no PPS monitoring */ 16654359Sroberto 0, /* conversion configuration */ 16754359Sroberto "WHARTON 400A Series clock Output Format 1", /* String format name */ 16854359Sroberto 15, /* string buffer */ 16954359Sroberto 0 /* no private data (complete pakets) */ 17054359Sroberto}; 17154359Sroberto 17254359Sroberto#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_WHARTON_400A) */ 17354359Srobertoint clk_wharton_400a_bs; 17454359Sroberto#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_WHARTON_400A) */ 17554359Sroberto 17654359Sroberto/* 17754359Sroberto * clk_wharton.c,v 17854359Sroberto * Revision 4.1 1999/02/28 15:27:24 kardel 17954359Sroberto * wharton clock integration 18054359Sroberto * 18154359Sroberto */ 182