1 1.6 christos /* $NetBSD: clk_varitext.c,v 1.7 2024/08/18 20:47:17 christos Exp $ */ 2 1.1 kardel 3 1.1 kardel #ifdef HAVE_CONFIG_H 4 1.1 kardel # include <config.h> 5 1.1 kardel #endif 6 1.1 kardel 7 1.1 kardel #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_VARITEXT) 8 1.1 kardel /* 9 1.1 kardel * /src/NTP/ntp4-dev/libparse/clk_varitext.c,v 1.5 2005/04/16 17:32:10 kardel RELEASE_20050508_A 10 1.1 kardel * 11 1.1 kardel * clk_varitext.c,v 1.5 2005/04/16 17:32:10 kardel RELEASE_20050508_A 12 1.1 kardel * 13 1.1 kardel * Varitext code variant by A.McConnell 1997/01/19 14 1.3 christos * 15 1.1 kardel * Supports Varitext's Radio Clock 16 1.3 christos * 17 1.1 kardel * Used the Meinberg/Computime clock as a template for Varitext Radio Clock 18 1.1 kardel * 19 1.1 kardel * Codebase: 20 1.1 kardel * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org> 21 1.3 christos * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany 22 1.1 kardel * 23 1.1 kardel * Redistribution and use in source and binary forms, with or without 24 1.1 kardel * modification, are permitted provided that the following conditions 25 1.1 kardel * are met: 26 1.1 kardel * 1. Redistributions of source code must retain the above copyright 27 1.1 kardel * notice, this list of conditions and the following disclaimer. 28 1.1 kardel * 2. Redistributions in binary form must reproduce the above copyright 29 1.1 kardel * notice, this list of conditions and the following disclaimer in the 30 1.1 kardel * documentation and/or other materials provided with the distribution. 31 1.1 kardel * 3. Neither the name of the author nor the names of its contributors 32 1.1 kardel * may be used to endorse or promote products derived from this software 33 1.1 kardel * without specific prior written permission. 34 1.1 kardel * 35 1.1 kardel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 36 1.1 kardel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 1.1 kardel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 1.1 kardel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 39 1.1 kardel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 40 1.1 kardel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 41 1.1 kardel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 42 1.1 kardel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 43 1.1 kardel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 44 1.1 kardel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 45 1.1 kardel * SUCH DAMAGE. 46 1.1 kardel * 47 1.1 kardel */ 48 1.1 kardel 49 1.1 kardel #include "ntp_fp.h" 50 1.1 kardel #include "ntp_unixtime.h" 51 1.1 kardel #include "ntp_calendar.h" 52 1.1 kardel 53 1.1 kardel #include "parse.h" 54 1.1 kardel 55 1.1 kardel #ifndef PARSESTREAM 56 1.1 kardel # include "ntp_stdlib.h" 57 1.1 kardel # include <stdio.h> 58 1.1 kardel #else 59 1.1 kardel # include "sys/parsestreams.h" 60 1.1 kardel extern int printf (const char *, ...); 61 1.1 kardel #endif 62 1.1 kardel 63 1.5 christos /* static const u_char VT_INITIALISED = 0x01; */ 64 1.5 christos /* static const u_char VT_SYNCHRONISED = 0x02; */ 65 1.5 christos /* static const u_char VT_ALARM_STATE = 0x04; */ 66 1.1 kardel static const u_char VT_BST = 0x08; 67 1.5 christos /* static const u_char VT_SEASON_CHANGE = 0x10; */ 68 1.5 christos /* static const u_char VT_LAST_TELEGRAM_OK = 0x20; */ 69 1.1 kardel 70 1.1 kardel /* 71 1.1 kardel * The Varitext receiver sends a datagram in the following format every minute 72 1.3 christos * 73 1.3 christos * Timestamp T:YY:MM:MD:WD:HH:MM:SSCRLFSTXXX 74 1.1 kardel * Pos 0123456789012345678901 2 3 4567 75 1.1 kardel * 0000000000111111111122 2 2 2222 76 1.3 christos * Parse T: : : : : : : \r\n 77 1.3 christos * 78 1.3 christos * T Startcharacter "T" specifies start of the timestamp 79 1.3 christos * YY Year MM Month 1-12 80 1.3 christos * MD Day of the month 81 1.3 christos * WD Day of week 82 1.3 christos * HH Hour 83 1.3 christos * MM Minute 84 1.3 christos * SS Second 85 1.3 christos * CR Carriage return 86 1.3 christos * LF Linefeed 87 1.1 kardel * ST Status character 88 1.1 kardel * Bit 0 - Set= Initialised; Reset=Time Invalid (DO NOT USE) 89 1.3 christos * Bit 1 - Set= Synchronised; Reset= Unsynchronised 90 1.3 christos * Bit 2 - Set= Alarm state; Reset= No alarm 91 1.3 christos * Bit 3 - Set= BST; Reset= GMT 92 1.3 christos * Bit 4 - Set= Seasonal change in approx hour; Reset= No seasonal change expected 93 1.1 kardel * Bit 5 - Set= Last MSF telegram was OK; Reset= Last telegram was in error; 94 1.3 christos * Bit 6 - Always set 95 1.1 kardel * Bit 7 - Unused 96 1.3 christos * XXX Checksum calculated using Fletcher's method (ignored for now). 97 1.1 kardel */ 98 1.1 kardel 99 1.1 kardel static struct format varitext_fmt = 100 1.1 kardel { 101 1.1 kardel { 102 1.1 kardel {8, 2}, {5, 2}, {2, 2}, /* day, month, year */ 103 1.1 kardel {14, 2}, {17, 2}, {20, 2}, /* hour, minute, second */ 104 1.1 kardel {11, 2}, {24, 1} /* dayofweek, status */ 105 1.1 kardel }, 106 1.1 kardel (const unsigned char*)"T: : : : : : : \r\n ", 107 1.1 kardel 0 108 1.1 kardel }; 109 1.1 kardel 110 1.3 christos static parse_cvt_fnc_t cvt_varitext; 111 1.3 christos static parse_inp_fnc_t inp_varitext; 112 1.1 kardel 113 1.1 kardel struct varitext { 114 1.1 kardel unsigned char start_found; 115 1.1 kardel unsigned char end_found; 116 1.1 kardel unsigned char end_count; 117 1.1 kardel unsigned char previous_ch; 118 1.1 kardel timestamp_t tstamp; 119 1.1 kardel }; 120 1.1 kardel 121 1.1 kardel clockformat_t clock_varitext = 122 1.1 kardel { 123 1.1 kardel inp_varitext, /* Because of the strange format we need to parse it ourselves */ 124 1.1 kardel cvt_varitext, /* Varitext conversion */ 125 1.1 kardel 0, /* no PPS monitoring */ 126 1.1 kardel (void *)&varitext_fmt, /* conversion configuration */ 127 1.1 kardel "Varitext Radio Clock", /* Varitext Radio Clock */ 128 1.1 kardel 30, /* string buffer */ 129 1.1 kardel sizeof(struct varitext), /* Private data size required to hold current parse state */ 130 1.1 kardel }; 131 1.1 kardel 132 1.1 kardel /* 133 1.3 christos * parse_cvt_fnc_t cvt_varitext 134 1.3 christos * 135 1.1 kardel * convert simple type format 136 1.1 kardel */ 137 1.3 christos static u_long 138 1.1 kardel cvt_varitext( 139 1.1 kardel unsigned char *buffer, 140 1.1 kardel int size, 141 1.1 kardel struct format *format, 142 1.1 kardel clocktime_t *clock_time, 143 1.1 kardel void *local 144 1.1 kardel ) 145 1.1 kardel { 146 1.1 kardel 147 1.3 christos if (!Strok(buffer, format->fixed_string)) { 148 1.1 kardel return CVT_NONE; 149 1.1 kardel } else { 150 1.1 kardel if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day, 151 1.1 kardel format->field_offsets[O_DAY].length) || 152 1.1 kardel Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month, 153 1.1 kardel format->field_offsets[O_MONTH].length) || 154 1.1 kardel Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year, 155 1.1 kardel format->field_offsets[O_YEAR].length) || 156 1.1 kardel Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour, 157 1.1 kardel format->field_offsets[O_HOUR].length) || 158 1.1 kardel Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute, 159 1.1 kardel format->field_offsets[O_MIN].length) || 160 1.1 kardel Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second, 161 1.3 christos format->field_offsets[O_SEC].length)) { 162 1.1 kardel return CVT_FAIL | CVT_BADFMT; 163 1.1 kardel } else { 164 1.1 kardel u_char *f = (u_char*) &buffer[format->field_offsets[O_FLAGS].offset]; 165 1.1 kardel 166 1.1 kardel clock_time->flags = 0; 167 1.1 kardel clock_time->utcoffset = 0; 168 1.1 kardel 169 1.1 kardel if (((*f) & VT_BST)) /* BST flag is set so set to indicate daylight saving time is active and utc offset */ 170 1.1 kardel { 171 1.1 kardel clock_time->utcoffset = -1*60*60; 172 1.1 kardel clock_time->flags |= PARSEB_DST; 173 1.1 kardel } 174 1.1 kardel /* 175 1.3 christos if (!((*f) & VT_INITIALISED)) Clock not initialised 176 1.1 kardel clock_time->flags |= PARSEB_POWERUP; 177 1.3 christos 178 1.3 christos if (!((*f) & VT_SYNCHRONISED)) Clock not synchronised 179 1.1 kardel clock_time->flags |= PARSEB_NOSYNC; 180 1.3 christos 181 1.3 christos if (((*f) & VT_SEASON_CHANGE)) Seasonal change expected in the next hour 182 1.1 kardel clock_time->flags |= PARSEB_ANNOUNCE; 183 1.1 kardel */ 184 1.3 christos return CVT_OK; 185 1.1 kardel } 186 1.1 kardel } 187 1.1 kardel } 188 1.1 kardel 189 1.3 christos /* parse_inp_fnc_t inp_varitext */ 190 1.3 christos static u_long 191 1.1 kardel inp_varitext( 192 1.1 kardel parse_t *parseio, 193 1.3 christos char ch, 194 1.1 kardel timestamp_t *tstamp 195 1.1 kardel ) 196 1.1 kardel { 197 1.1 kardel struct varitext *t = (struct varitext *)parseio->parse_pdata; 198 1.1 kardel int rtc; 199 1.1 kardel 200 1.5 christos parseprintf(DD_PARSE, ("inp_varitext(0x%p, 0x%x, ...)\n", (void*)parseio, ch)); 201 1.1 kardel 202 1.3 christos if (!t) 203 1.1 kardel return PARSE_INP_SKIP; /* local data not allocated - sigh! */ 204 1.1 kardel 205 1.3 christos if (ch == 'T') 206 1.1 kardel t->tstamp = *tstamp; 207 1.1 kardel 208 1.1 kardel if ((t->previous_ch == 'T') && (ch == ':')) 209 1.1 kardel { 210 1.1 kardel parseprintf(DD_PARSE, ("inp_varitext: START seen\n")); 211 1.1 kardel 212 1.1 kardel parseio->parse_data[0] = 'T'; 213 1.1 kardel parseio->parse_index=1; 214 1.1 kardel parseio->parse_dtime.parse_stime = t->tstamp; /* Time stamp at packet start */ 215 1.1 kardel t->start_found = 1; 216 1.1 kardel t->end_found = 0; 217 1.1 kardel t->end_count = 0; 218 1.1 kardel } 219 1.1 kardel 220 1.1 kardel if (t->start_found) 221 1.1 kardel { 222 1.1 kardel if ((rtc = parse_addchar(parseio, ch)) != PARSE_INP_SKIP) 223 1.1 kardel { 224 1.1 kardel parseprintf(DD_PARSE, ("inp_varitext: ABORTED due to too many characters\n")); 225 1.1 kardel 226 1.1 kardel memset(t, 0, sizeof(struct varitext)); 227 1.1 kardel return rtc; 228 1.1 kardel } 229 1.1 kardel 230 1.3 christos if (t->end_found) 231 1.1 kardel { 232 1.1 kardel if (++(t->end_count) == 4) /* Finally found the end of the message */ 233 1.1 kardel { 234 1.1 kardel parseprintf(DD_PARSE, ("inp_varitext: END seen\n")); 235 1.1 kardel 236 1.1 kardel memset(t, 0, sizeof(struct varitext)); 237 1.1 kardel if ((rtc = parse_addchar(parseio, 0)) == PARSE_INP_SKIP) 238 1.1 kardel return parse_end(parseio); 239 1.1 kardel else 240 1.1 kardel return rtc; 241 1.3 christos } 242 1.1 kardel } 243 1.1 kardel 244 1.3 christos if ((t->previous_ch == '\r') && (ch == '\n')) 245 1.1 kardel { 246 1.1 kardel t->end_found = 1; 247 1.1 kardel } 248 1.1 kardel 249 1.1 kardel } 250 1.3 christos 251 1.1 kardel t->previous_ch = ch; 252 1.1 kardel 253 1.1 kardel return PARSE_INP_SKIP; 254 1.1 kardel } 255 1.1 kardel 256 1.1 kardel #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_VARITEXT) */ 257 1.7 christos NONEMPTY_TRANSLATION_UNIT 258 1.1 kardel #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_VARITEXT) */ 259 1.1 kardel 260 1.1 kardel /* 261 1.1 kardel * History: 262 1.1 kardel * 263 1.1 kardel * clk_varitext.c,v 264 1.1 kardel * Revision 1.5 2005/04/16 17:32:10 kardel 265 1.1 kardel * update copyright 266 1.1 kardel * 267 1.1 kardel * Revision 1.4 2004/11/14 15:29:41 kardel 268 1.1 kardel * support PPSAPI, upgrade Copyright to Berkeley style 269 1.1 kardel * 270 1.1 kardel * 271 1.1 kardel * Revision 1.0 1997/06/02 13:16:30 McConnell 272 1.1 kardel * File created 273 1.1 kardel * 274 1.1 kardel */ 275