#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_MEINBERG) /* * /src/NTP/REPOSITORY/v3/parse/clk_meinberg.c,v 3.15 1994/05/30 10:19:59 kardel Exp * * clk_meinberg.c,v 3.15 1994/05/30 10:19:59 kardel Exp * * Meinberg clock support * * Copyright (c) 1992,1993,1994 * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include "sys/types.h" #include "sys/time.h" #include "sys/errno.h" #include "ntp_fp.h" #include "ntp_unixtime.h" #include "ntp_calendar.h" #include "parse.h" /* * The Meinberg receiver every second sends a datagram of the following form * (Standard Format) * * D:
..;T:;U:::; * pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3 * 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2 * = '\002' ASCII start of text * = '\003' ASCII end of text *
,, = day, month, year(2 digits!!) * = day of week (sunday= 0) * ,, = hour, minute, second * = '#' if never synced since powerup else ' ' for DCF U/A 31 * '#' if not PZF sychronisation available else ' ' for PZF 535 * = '*' if time comes from internal quartz else ' ' * = 'S' if daylight saving time is active else ' ' * = '!' during the hour preceeding an daylight saving time * start/end change * * For the university of Erlangen a special format was implemented to support * LEAP announcement and anouncement of alternate antenna. * * Version for UNI-ERLANGEN Software is: PZFUERL V4.6 (Meinberg) * * The use of this software release (or higher) is *ABSOLUTELY* * recommended (ask for PZFUERL version as some minor HW fixes have * been introduced) due to the LEAP second support and UTC indication. * The standard timecode does not indicate when the timecode is in * UTC (by front panel configuration) thus we have no chance to find * the correct utc offset. For the standard format do not ever use * UTC display as this is not detectable in the time code !!! * *
..; ; ::; * pos: 0 00 0 00 0 00 11 1 11 11 1 11 2 22 22 2 2 2 2 2 3 3 3 * 1 23 4 56 7 89 01 2 34 56 7 89 0 12 34 5 6 7 8 9 0 1 2 * = '\002' ASCII start of text * = '\003' ASCII end of text *
,, = day, month, year(2 digits!!) * = day of week (sunday= 0) * ,, = hour, minute, second * = 'U' UTC time display * = '#' if never synced since powerup else ' ' for DCF U/A 31 * '#' if not PZF sychronisation available else ' ' for PZF 535 * = '*' if time comes from internal quartz else ' ' * = 'S' if daylight saving time is active else ' ' * = '!' during the hour preceeding an daylight saving time * start/end change * = 'A' LEAP second announcement * = 'R' alternate antenna * * Meinberg GPS166 receiver * * You must get the Uni-Erlangen firmware for the GPS receiver support * to work to full satisfaction ! * *
..; ; ::; <+/-><00:00>; ; * * 000000000111111111122222222223333333333444444444455555555556666666 * 123456789012345678901234567890123456789012345678901234567890123456 * \x0209.07.93; 5; 08:48:26; +00:00; ; 49.5736N 11.0280E 373m\x03 * * * = '\002' ASCII start of text * = '\003' ASCII end of text *
,, = day, month, year(2 digits!!) * = day of week (sunday= 0) * ,, = hour, minute, second * <+/->,<00:00> = offset to UTC * = '#' if never synced since powerup else ' ' for DCF U/A 31 * '#' if not PZF sychronisation available else ' ' for PZF 535 * = 'U' UTC time display * = '*' if time comes from internal quartz else ' ' * = 'S' if daylight saving time is active else ' ' * = '!' during the hour preceeding an daylight saving time * start/end change * = 'A' LEAP second announcement * = 'R' alternate antenna (reminiscent of PZF535) usually ' ' * = 'L' on 23:59:60 */ static struct format meinberg_fmt[] = { { { { 3, 2}, { 6, 2}, { 9, 2}, { 18, 2}, { 21, 2}, { 24, 2}, { 14, 1}, { 27, 4}, { 29, 1}, }, "\2D: . . ;T: ;U: . . ; \3", 0 }, { /* special extended FAU Erlangen extended format */ { { 1, 2}, { 4, 2}, { 7, 2}, { 14, 2}, { 17, 2}, { 20, 2}, { 11, 1}, { 25, 4}, { 27, 1}, }, "\2 . . ; ; : : ; \3", MBG_EXTENDED }, { /* special extended FAU Erlangen GPS format */ { { 1, 2}, { 4, 2}, { 7, 2}, { 14, 2}, { 17, 2}, { 20, 2}, { 11, 1}, { 32, 8}, { 35, 1}, { 25, 2}, { 28, 2}, { 24, 1} }, "\2 . . ; ; : : ; : ; ; . . ", 0 } }; static u_long cvt_meinberg(); static u_long cvt_mgps(); clockformat_t clock_meinberg[] = { { (unsigned LONG (*)())0, /* no input handling */ cvt_meinberg, /* Meinberg conversion */ syn_simple, /* easy time stamps for RS232 (fallback) */ pps_simple, /* easy PPS monitoring */ (u_long (*)())0, /* no time code synthesizer monitoring */ (void *)&meinberg_fmt[0], /* conversion configuration */ "Meinberg Standard", /* Meinberg simple format - beware */ 32, /* string buffer */ F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ 0, /* no private data (complete pakets) */ { 0, 0}, '\2', '\3', '\0' }, { (unsigned LONG (*)())0, /* no input handling */ cvt_meinberg, /* Meinberg conversion */ syn_simple, /* easy time stamps for RS232 (fallback) */ pps_simple, /* easy PPS monitoring */ (u_long (*)())0, /* no time code synthesizer monitoring */ (void *)&meinberg_fmt[1], /* conversion configuration */ "Meinberg Extended", /* Meinberg enhanced format */ 32, /* string buffer */ F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ 0, /* no private data (complete pakets) */ { 0, 0}, '\2', '\3', '\0' }, { (unsigned LONG (*)())0, /* no input handling */ cvt_mgps, /* Meinberg GPS166 conversion */ syn_simple, /* easy time stamps for RS232 (fallback) */ pps_simple, /* easy PPS monitoring */ (u_long (*)())0, /* no time code synthesizer monitoring */ (void *)&meinberg_fmt[2], /* conversion configuration */ "Meinberg GPS Extended", /* Meinberg FAU GPS format */ 70, /* string buffer */ F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ 0, /* no private data (complete pakets) */ { 0, 0}, '\2', '\3', '\0' } }; /* * cvt_meinberg * * convert simple type format */ static u_long cvt_meinberg(buffer, size, format, clock) register char *buffer; register int size; register struct format *format; register clocktime_t *clock; { if (!Strok(buffer, format->fixed_string)) { return CVT_NONE; } else { if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day, format->field_offsets[O_DAY].length) || Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month, format->field_offsets[O_MONTH].length) || Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year, format->field_offsets[O_YEAR].length) || Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour, format->field_offsets[O_HOUR].length) || Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute, format->field_offsets[O_MIN].length) || Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second, format->field_offsets[O_SEC].length)) { return CVT_FAIL|CVT_BADFMT; } else { char *f = &buffer[format->field_offsets[O_FLAGS].offset]; clock->flags = 0; clock->usecond = 0; /* * in the extended timecode format we have also the * indication that the timecode is in UTC * for compatibilty reasons we start at the USUAL * offset (POWERUP flag) and know that the UTC indication * is the character before the powerup flag */ if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U')) { /* * timecode is in UTC */ clock->utcoffset = 0; /* UTC */ clock->flags |= PARSEB_UTC; } else { /* * only calculate UTC offset if MET/MED is in time code * or we have the old time code format, where we do not * know whether it is UTC time or MET/MED * pray that nobody switches to UTC in the standard time code * ROMS !!!! */ switch (buffer[format->field_offsets[O_ZONE].offset]) { case ' ': clock->utcoffset = -1*60*60; /* MET */ break; case 'S': clock->utcoffset = -2*60*60; /* MED */ break; default: return CVT_FAIL|CVT_BADFMT; } } /* * gather status flags */ if (buffer[format->field_offsets[O_ZONE].offset] == 'S') clock->flags |= PARSEB_DST; if (f[0] == '#') clock->flags |= PARSEB_POWERUP; if (f[1] == '*') clock->flags |= PARSEB_NOSYNC; if (f[3] == '!') clock->flags |= PARSEB_ANNOUNCE; if (format->flags & MBG_EXTENDED) { clock->flags |= PARSEB_S_LEAP; clock->flags |= PARSEB_S_ANTENNA; /* * DCF77 does not encode the direction - * so we take the current default - * earth slowing down */ if (f[4] == 'A') clock->flags |= PARSEB_LEAPADD; if (f[5] == 'R') clock->flags |= PARSEB_ALTERNATE; } return CVT_OK; } } } /* * cvt_mgps * * convert Meinberg GPS format */ static u_long cvt_mgps(buffer, size, format, clock) register char *buffer; register int size; register struct format *format; register clocktime_t *clock; { if (!Strok(buffer, format->fixed_string)) { return CVT_NONE; } else { if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day, format->field_offsets[O_DAY].length) || Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month, format->field_offsets[O_MONTH].length) || Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year, format->field_offsets[O_YEAR].length) || Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour, format->field_offsets[O_HOUR].length) || Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute, format->field_offsets[O_MIN].length) || Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second, format->field_offsets[O_SEC].length)) { return CVT_FAIL|CVT_BADFMT; } else { long h; char *f = &buffer[format->field_offsets[O_FLAGS].offset]; clock->flags = PARSEB_S_LEAP|PARSEB_S_POSITION; clock->usecond = 0; /* * calculate UTC offset */ if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h, format->field_offsets[O_UTCHOFFSET].length)) { return CVT_FAIL|CVT_BADFMT; } else { if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock->utcoffset, format->field_offsets[O_UTCMOFFSET].length)) { return CVT_FAIL|CVT_BADFMT; } clock->utcoffset += TIMES60(h); if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-') { clock->utcoffset = -clock->utcoffset; } } /* * gather status flags */ if (buffer[format->field_offsets[O_ZONE].offset] == 'S') clock->flags |= PARSEB_DST; if ((f[0] == 'U') || (clock->utcoffset == 0)) clock->flags |= PARSEB_UTC; /* * no sv's seen - no time & position */ if (f[1] == '#') clock->flags |= PARSEB_POWERUP; /* * at least one sv seen - time (for last position) */ if (f[2] == '*') clock->flags |= PARSEB_NOSYNC; else if (!(clock->flags & PARSEB_POWERUP)) clock->flags |= PARSEB_POSITION; /* * oncoming zone switch */ if (f[4] == '!') clock->flags |= PARSEB_ANNOUNCE; /* * oncoming leap second * data format does not (yet) specify whether * to add or to delete a second - thus we * pick the current default */ if (f[5] == 'A') clock->flags |= PARSEB_LEAPADD; /* * this is the leap second */ if (f[7] == 'L') clock->flags |= PARSEB_LEAPSECOND; return CVT_OK; } } } #endif /* defined(PARSE) && defined(CLOCK_MEINBERG) */ /* * History: * * clk_meinberg.c,v * Revision 3.15 1994/05/30 10:19:59 kardel * LONG cleanup * * Revision 3.14 1994/02/20 13:04:37 kardel * parse add/delete second support * * Revision 3.13 1994/02/02 17:45:21 kardel * rcs ids fixed * * Revision 3.11 1994/01/25 19:05:10 kardel * 94/01/23 reconcilation * * Revision 3.10 1994/01/23 17:21:54 kardel * 1994 reconcilation * * Revision 3.9 1993/10/30 09:44:38 kardel * conditional compilation flag cleanup * * Revision 3.8 1993/10/22 14:27:48 kardel * Oct. 22nd 1993 reconcilation * * Revision 3.7 1993/10/09 15:01:30 kardel * file structure unified * * Revision 3.6 1993/10/03 19:10:43 kardel * restructured I/O handling * * Revision 3.5 1993/09/27 21:08:04 kardel * utcoffset now in seconds * * Revision 3.4 1993/09/26 23:40:22 kardel * new parse driver logic * * Revision 3.3 1993/08/18 09:29:32 kardel * GPS format is somewhat variable length - variable length part holds position * * Revision 3.2 1993/07/09 11:37:16 kardel * Initial restructured version + GPS support * * Revision 3.1 1993/07/06 10:00:17 kardel * DCF77 driver goes generic... * */