1 /* $NetBSD: clk_meinberg.c,v 1.4 2006/06/11 19:34:10 kardel Exp $ */
4 * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
6 * clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
8 * Meinberg clock support
10 * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
11 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the author nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_MEINBERG)
46 #include "ntp_unixtime.h"
47 #include "ntp_calendar.h"
49 #include "ntp_machine.h"
56 #include "sys/parsestreams.h"
59 #include "ntp_stdlib.h"
61 #include "ntp_stdlib.h"
63 #include "mbg_gps166.h"
68 * The Meinberg receiver every second sends a datagram of the following form
71 * <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
72 * pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3
73 * 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2
74 * <STX> = '\002' ASCII start of text
75 * <ETX> = '\003' ASCII end of text
76 * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
77 * <w> = day of week (sunday= 0)
78 * <hh>,<mm>,<ss> = hour, minute, second
79 * <S> = '#' if never synced since powerup for DCF C51
80 * = '#' if not PZF sychronisation available for PZF 535/509
82 * <F> = '*' if time comes from internal quartz
83 * = ' ' if completely synched
84 * <D> = 'S' if daylight saving time is active
85 * = 'U' if time is represented in UTC
86 * = ' ' if no special condition exists
87 * <A> = '!' during the hour preceeding an daylight saving time
89 * = 'A' leap second insert warning
90 * = ' ' if no special condition exists
92 * Extended data format (PZFUERL for PZF type clocks)
94 * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
95 * pos: 0 00 0 00 0 00 11 1 11 11 1 11 2 22 22 2 2 2 2 2 3 3 3
96 * 1 23 4 56 7 89 01 2 34 56 7 89 0 12 34 5 6 7 8 9 0 1 2
97 * <STX> = '\002' ASCII start of text
98 * <ETX> = '\003' ASCII end of text
99 * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
100 * <w> = day of week (sunday= 0)
101 * <hh>,<mm>,<ss> = hour, minute, second
102 * <U> = 'U' UTC time display
103 * <S> = '#' if never synced since powerup else ' ' for DCF C51
104 * '#' if not PZF sychronisation available else ' ' for PZF 535/509
105 * <F> = '*' if time comes from internal quartz else ' '
106 * <D> = 'S' if daylight saving time is active else ' '
107 * <A> = '!' during the hour preceeding an daylight saving time
109 * <L> = 'A' LEAP second announcement
110 * <R> = 'R' alternate antenna
112 * Meinberg GPS166 receiver
114 * You must get the Uni-Erlangen firmware for the GPS receiver support
115 * to work to full satisfaction !
117 * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
119 * 000000000111111111122222222223333333333444444444455555555556666666
120 * 123456789012345678901234567890123456789012345678901234567890123456
121 * \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N 11.0280E 373m\x03
124 * <STX> = '\002' ASCII start of text
125 * <ETX> = '\003' ASCII end of text
126 * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
127 * <w> = day of week (sunday= 0)
128 * <hh>,<mm>,<ss> = hour, minute, second
129 * <+/->,<00:00> = offset to UTC
130 * <S> = '#' if never synced since powerup else ' '
131 * <F> = '*' if position is not confirmed else ' '
132 * <D> = 'S' if daylight saving time is active else ' '
133 * <A> = '!' during the hour preceeding an daylight saving time
135 * <L> = 'A' LEAP second announcement
136 * <R> = 'R' alternate antenna (reminiscent of PZF535) usually ' '
137 * <L> = 'L' on 23:59:60
139 * Binary messages have a lead in for a fixed header of SOH
142 /*--------------------------------------------------------------*/
145 /* Purpose: Compute a checksum about a number of bytes */
147 /* Input: uchar *p address of the first byte */
148 /* short n the number of bytes */
152 /* Ret val: the checksum */
153 /*+-------------------------------------------------------------*/
161 unsigned long sum
= 0;
164 for ( i
= 0; i
< n
; i
++ )
172 unsigned char **bufpp
,
176 headerp
->gps_cmd
= get_lsb_short(bufpp
);
177 headerp
->gps_len
= get_lsb_short(bufpp
);
178 headerp
->gps_data_csum
= get_lsb_short(bufpp
);
179 headerp
->gps_hdr_csum
= get_lsb_short(bufpp
);
182 static struct format meinberg_fmt
[] =
186 { 3, 2}, { 6, 2}, { 9, 2},
187 { 18, 2}, { 21, 2}, { 24, 2},
188 { 14, 1}, { 27, 4}, { 29, 1},
190 (const unsigned char *)"\2D: . . ;T: ;U: . . ; \3",
193 { /* special extended FAU Erlangen extended format */
195 { 1, 2}, { 4, 2}, { 7, 2},
196 { 14, 2}, { 17, 2}, { 20, 2},
197 { 11, 1}, { 25, 4}, { 27, 1},
199 (const unsigned char *)"\2 . . ; ; : : ; \3",
202 { /* special extended FAU Erlangen GPS format */
204 { 1, 2}, { 4, 2}, { 7, 2},
205 { 14, 2}, { 17, 2}, { 20, 2},
206 { 11, 1}, { 32, 7}, { 35, 1},
207 { 25, 2}, { 28, 2}, { 24, 1}
209 (const unsigned char *)"\2 . . ; ; : : ; : ; ; . . ",
214 static u_long cvt_meinberg
P((unsigned char *, int, struct format
*, clocktime_t
*, void *));
215 static u_long cvt_mgps
P((unsigned char *, int, struct format
*, clocktime_t
*, void *));
216 static u_long mbg_input
P((parse_t
*, unsigned int, timestamp_t
*));
217 static u_long gps_input
P((parse_t
*, unsigned int, timestamp_t
*));
221 unsigned short len
; /* len to fill */
222 unsigned short phase
; /* current input phase */
225 #define MBG_NONE 0 /* no data input */
226 #define MBG_HEADER 1 /* receiving header */
227 #define MBG_DATA 2 /* receiving data */
228 #define MBG_STRING 3 /* receiving standard data message */
230 clockformat_t clock_meinberg
[] =
233 mbg_input
, /* normal input handling */
234 cvt_meinberg
, /* Meinberg conversion */
235 pps_one
, /* easy PPS monitoring */
236 0, /* conversion configuration */
237 "Meinberg Standard", /* Meinberg simple format - beware */
238 32, /* string buffer */
239 0 /* no private data (complete pakets) */
242 mbg_input
, /* normal input handling */
243 cvt_meinberg
, /* Meinberg conversion */
244 pps_one
, /* easy PPS monitoring */
245 0, /* conversion configuration */
246 "Meinberg Extended", /* Meinberg enhanced format */
247 32, /* string buffer */
248 0 /* no private data (complete pakets) */
251 gps_input
, /* no input handling */
252 cvt_mgps
, /* Meinberg GPS166 conversion */
253 pps_one
, /* easy PPS monitoring */
254 (void *)&meinberg_fmt
[2], /* conversion configuration */
255 "Meinberg GPS Extended", /* Meinberg FAU GPS format */
256 512, /* string buffer */
257 sizeof(struct msg_buf
) /* no private data (complete pakets) */
264 * convert simple type format
268 unsigned char *buffer
,
270 struct format
*unused
,
271 clocktime_t
*clock_time
,
275 struct format
*format
;
278 * select automagically correct data format
280 if (Strok(buffer
, meinberg_fmt
[0].fixed_string
))
282 format
= &meinberg_fmt
[0];
286 if (Strok(buffer
, meinberg_fmt
[1].fixed_string
))
288 format
= &meinberg_fmt
[1];
292 return CVT_FAIL
|CVT_BADFMT
;
299 if (Stoi(&buffer
[format
->field_offsets
[O_DAY
].offset
], &clock_time
->day
,
300 format
->field_offsets
[O_DAY
].length
) ||
301 Stoi(&buffer
[format
->field_offsets
[O_MONTH
].offset
], &clock_time
->month
,
302 format
->field_offsets
[O_MONTH
].length
) ||
303 Stoi(&buffer
[format
->field_offsets
[O_YEAR
].offset
], &clock_time
->year
,
304 format
->field_offsets
[O_YEAR
].length
) ||
305 Stoi(&buffer
[format
->field_offsets
[O_HOUR
].offset
], &clock_time
->hour
,
306 format
->field_offsets
[O_HOUR
].length
) ||
307 Stoi(&buffer
[format
->field_offsets
[O_MIN
].offset
], &clock_time
->minute
,
308 format
->field_offsets
[O_MIN
].length
) ||
309 Stoi(&buffer
[format
->field_offsets
[O_SEC
].offset
], &clock_time
->second
,
310 format
->field_offsets
[O_SEC
].length
))
312 return CVT_FAIL
|CVT_BADFMT
;
316 unsigned char *f
= &buffer
[format
->field_offsets
[O_FLAGS
].offset
];
318 clock_time
->usecond
= 0;
319 clock_time
->flags
= PARSEB_S_LEAP
;
321 if (clock_time
->second
== 60)
322 clock_time
->flags
|= PARSEB_LEAPSECOND
;
325 * in the extended timecode format we have also the
326 * indication that the timecode is in UTC
327 * for compatibilty reasons we start at the USUAL
328 * offset (POWERUP flag) and know that the UTC indication
329 * is the character before the powerup flag
331 if ((format
->flags
& MBG_EXTENDED
) && (f
[-1] == 'U'))
336 clock_time
->utcoffset
= 0; /* UTC */
337 clock_time
->flags
|= PARSEB_UTC
;
342 * only calculate UTC offset if MET/MED is in time code
343 * or we have the old time code format, where we do not
344 * know whether it is UTC time or MET/MED
345 * pray that nobody switches to UTC in the *old* standard time code
346 * ROMS !!!! The new ROMS have 'U' at the ZONE field - good.
348 switch (buffer
[format
->field_offsets
[O_ZONE
].offset
])
351 clock_time
->utcoffset
= -1*60*60; /* MET */
355 clock_time
->utcoffset
= -2*60*60; /* MED */
362 clock_time
->utcoffset
= 0; /* UTC */
363 clock_time
->flags
|= PARSEB_UTC
;
367 return CVT_FAIL
|CVT_BADFMT
;
372 * gather status flags
374 if (buffer
[format
->field_offsets
[O_ZONE
].offset
] == 'S')
375 clock_time
->flags
|= PARSEB_DST
;
378 clock_time
->flags
|= PARSEB_POWERUP
;
381 clock_time
->flags
|= PARSEB_NOSYNC
;
384 clock_time
->flags
|= PARSEB_ANNOUNCE
;
387 * oncoming leap second
388 * 'a' code not confirmed - earth is not
389 * expected to speed up
392 clock_time
->flags
|= PARSEB_LEAPADD
;
395 clock_time
->flags
|= PARSEB_LEAPDEL
;
398 if (format
->flags
& MBG_EXTENDED
)
400 clock_time
->flags
|= PARSEB_S_ANTENNA
;
403 * DCF77 does not encode the direction -
404 * so we take the current default -
407 clock_time
->flags
&= ~PARSEB_LEAPDEL
;
410 clock_time
->flags
|= PARSEB_LEAPADD
;
413 clock_time
->flags
|= PARSEB_ALTERNATE
;
423 * grep data from input stream
434 parseprintf(DD_PARSE
, ("mbg_input(0x%lx, 0x%x, ...)\n", (long)parseio
, ch
));
439 parseprintf(DD_PARSE
, ("mbg_input: STX seen\n"));
441 parseio
->parse_index
= 1;
442 parseio
->parse_data
[0] = ch
;
443 parseio
->parse_dtime
.parse_stime
= *tstamp
; /* collect timestamp */
444 return PARSE_INP_SKIP
;
447 parseprintf(DD_PARSE
, ("mbg_input: ETX seen\n"));
448 if ((rtc
= parse_addchar(parseio
, ch
)) == PARSE_INP_SKIP
)
449 return parse_end(parseio
);
454 return parse_addchar(parseio
, ch
);
462 * convert Meinberg GPS format
466 unsigned char *buffer
,
468 struct format
*format
,
469 clocktime_t
*clock_time
,
473 if (!Strok(buffer
, format
->fixed_string
))
475 return cvt_meinberg(buffer
, size
, format
, clock_time
, local
);
479 if (Stoi(&buffer
[format
->field_offsets
[O_DAY
].offset
], &clock_time
->day
,
480 format
->field_offsets
[O_DAY
].length
) ||
481 Stoi(&buffer
[format
->field_offsets
[O_MONTH
].offset
], &clock_time
->month
,
482 format
->field_offsets
[O_MONTH
].length
) ||
483 Stoi(&buffer
[format
->field_offsets
[O_YEAR
].offset
], &clock_time
->year
,
484 format
->field_offsets
[O_YEAR
].length
) ||
485 Stoi(&buffer
[format
->field_offsets
[O_HOUR
].offset
], &clock_time
->hour
,
486 format
->field_offsets
[O_HOUR
].length
) ||
487 Stoi(&buffer
[format
->field_offsets
[O_MIN
].offset
], &clock_time
->minute
,
488 format
->field_offsets
[O_MIN
].length
) ||
489 Stoi(&buffer
[format
->field_offsets
[O_SEC
].offset
], &clock_time
->second
,
490 format
->field_offsets
[O_SEC
].length
))
492 return CVT_FAIL
|CVT_BADFMT
;
497 unsigned char *f
= &buffer
[format
->field_offsets
[O_FLAGS
].offset
];
499 clock_time
->flags
= PARSEB_S_LEAP
|PARSEB_S_POSITION
;
501 clock_time
->usecond
= 0;
504 * calculate UTC offset
506 if (Stoi(&buffer
[format
->field_offsets
[O_UTCHOFFSET
].offset
], &h
,
507 format
->field_offsets
[O_UTCHOFFSET
].length
))
509 return CVT_FAIL
|CVT_BADFMT
;
513 if (Stoi(&buffer
[format
->field_offsets
[O_UTCMOFFSET
].offset
], &clock_time
->utcoffset
,
514 format
->field_offsets
[O_UTCMOFFSET
].length
))
516 return CVT_FAIL
|CVT_BADFMT
;
519 clock_time
->utcoffset
+= TIMES60(h
);
520 clock_time
->utcoffset
= TIMES60(clock_time
->utcoffset
);
522 if (buffer
[format
->field_offsets
[O_UTCSOFFSET
].offset
] != '-')
524 clock_time
->utcoffset
= -clock_time
->utcoffset
;
529 * gather status flags
531 if (buffer
[format
->field_offsets
[O_ZONE
].offset
] == 'S')
532 clock_time
->flags
|= PARSEB_DST
;
534 if (clock_time
->utcoffset
== 0)
535 clock_time
->flags
|= PARSEB_UTC
;
538 * no sv's seen - no time & position
541 clock_time
->flags
|= PARSEB_POWERUP
;
544 * at least one sv seen - time (for last position)
547 clock_time
->flags
|= PARSEB_NOSYNC
;
549 if (!(clock_time
->flags
& PARSEB_POWERUP
))
550 clock_time
->flags
|= PARSEB_POSITION
;
553 * oncoming zone switch
556 clock_time
->flags
|= PARSEB_ANNOUNCE
;
559 * oncoming leap second
560 * 'a' code not confirmed - earth is not
561 * expected to speed up
564 clock_time
->flags
|= PARSEB_LEAPADD
;
567 clock_time
->flags
|= PARSEB_LEAPDEL
;
574 * this is the leap second
576 if ((f
[6] == 'L') || (clock_time
->second
== 60))
577 clock_time
->flags
|= PARSEB_LEAPSECOND
;
587 * grep binary data from input stream
596 CSUM calc_csum
; /* used to compare the incoming csums */
598 struct msg_buf
*msg_buf
;
600 msg_buf
= (struct msg_buf
*)parseio
->parse_pdata
;
602 parseprintf(DD_PARSE
, ("gps_input(0x%lx, 0x%x, ...)\n", (long)parseio
, ch
));
605 return PARSE_INP_SKIP
;
607 if ( msg_buf
->phase
== MBG_NONE
)
608 { /* not receiving yet */
612 parseprintf(DD_PARSE
, ("gps_input: SOH seen\n"));
614 msg_buf
->len
= sizeof( header
); /* prepare to receive msg header */
615 msg_buf
->phase
= MBG_HEADER
; /* receiving header */
619 parseprintf(DD_PARSE
, ("gps_input: STX seen\n"));
622 msg_buf
->phase
= MBG_STRING
; /* prepare to receive ASCII ETX delimited message */
623 parseio
->parse_index
= 1;
624 parseio
->parse_data
[0] = ch
;
628 return PARSE_INP_SKIP
; /* keep searching */
631 parseio
->parse_dtime
.parse_msglen
= 1; /* reset buffer pointer */
632 parseio
->parse_dtime
.parse_msg
[0] = ch
; /* fill in first character */
633 parseio
->parse_dtime
.parse_stime
= *tstamp
; /* collect timestamp */
634 return PARSE_INP_SKIP
;
637 /* SOH/STX has already been received */
639 /* save incoming character in both buffers if needbe */
640 if ((msg_buf
->phase
== MBG_STRING
) &&
641 (parseio
->parse_index
< parseio
->parse_dsize
))
642 parseio
->parse_data
[parseio
->parse_index
++] = ch
;
644 parseio
->parse_dtime
.parse_msg
[parseio
->parse_dtime
.parse_msglen
++] = ch
;
646 if (parseio
->parse_dtime
.parse_msglen
> sizeof(parseio
->parse_dtime
.parse_msg
))
648 msg_buf
->phase
= MBG_NONE
; /* buffer overflow - discard */
649 parseio
->parse_data
[parseio
->parse_index
] = '\0';
650 memcpy(parseio
->parse_ldata
, parseio
->parse_data
, (unsigned)(parseio
->parse_index
+1));
651 parseio
->parse_ldsize
= parseio
->parse_index
;
652 return PARSE_INP_DATA
;
655 switch (msg_buf
->phase
)
661 if ( msg_buf
->len
) /* transfer not complete */
662 return PARSE_INP_SKIP
;
664 parseprintf(DD_PARSE
, ("gps_input: %s complete\n", (msg_buf
->phase
== MBG_DATA
) ? "data" : "header"));
669 if ((ch
== ETX
) || (parseio
->parse_index
>= parseio
->parse_dsize
))
671 msg_buf
->phase
= MBG_NONE
;
672 parseprintf(DD_PARSE
, ("gps_input: string complete\n"));
673 parseio
->parse_data
[parseio
->parse_index
] = '\0';
674 memcpy(parseio
->parse_ldata
, parseio
->parse_data
, (unsigned)(parseio
->parse_index
+1));
675 parseio
->parse_ldsize
= parseio
->parse_index
;
676 parseio
->parse_index
= 0;
677 return PARSE_INP_TIME
;
681 return PARSE_INP_SKIP
;
685 /* cnt == 0, so the header or the whole message is complete */
687 if ( msg_buf
->phase
== MBG_HEADER
)
688 { /* header complete now */
689 unsigned char *datap
= parseio
->parse_dtime
.parse_msg
+ 1;
691 get_mbg_header(&datap
, &header
);
693 parseprintf(DD_PARSE
, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n",
694 (int)header
.gps_cmd
, (int)header
.gps_len
, (int)header
.gps_data_csum
,
695 (int)header
.gps_hdr_csum
));
698 calc_csum
= mbg_csum( (unsigned char *) parseio
->parse_dtime
.parse_msg
+ 1, (unsigned short)6 );
700 if ( calc_csum
!= header
.gps_hdr_csum
)
702 parseprintf(DD_PARSE
, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n",
703 (int)calc_csum
, (int)mbg_csum( (unsigned char *) parseio
->parse_dtime
.parse_msg
, (unsigned short)6 )));
705 msg_buf
->phase
= MBG_NONE
; /* back to hunting mode */
706 return PARSE_INP_DATA
; /* invalid header checksum received - pass up for detection */
709 if ((header
.gps_len
== 0) || /* no data to wait for */
710 (header
.gps_len
>= (sizeof (parseio
->parse_dtime
.parse_msg
) - sizeof(header
) - 1))) /* blows anything we have space for */
712 msg_buf
->phase
= MBG_NONE
; /* back to hunting mode */
713 return (header
.gps_len
== 0) ? PARSE_INP_DATA
: PARSE_INP_SKIP
; /* message complete/throwaway */
716 parseprintf(DD_PARSE
, ("gps_input: expecting %d bytes of data message\n", (int)header
.gps_len
));
718 msg_buf
->len
= header
.gps_len
;/* save number of bytes to wait for */
719 msg_buf
->phase
= MBG_DATA
; /* flag header already complete */
720 return PARSE_INP_SKIP
;
723 parseprintf(DD_PARSE
, ("gps_input: message data complete\n"));
725 /* Header and data have been received. The header checksum has been */
728 msg_buf
->phase
= MBG_NONE
; /* back to hunting mode */
729 return PARSE_INP_DATA
; /* message complete, must be evaluated */
732 #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
734 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
740 * Revision 4.12.2.1 2005/09/25 10:22:35 kardel
741 * cleanup buffer bounds
743 * Revision 4.12 2005/04/16 17:32:10 kardel
746 * Revision 4.11 2004/11/14 15:29:41 kardel
747 * support PPSAPI, upgrade Copyright to Berkeley style
749 * Revision 4.8 1999/11/28 09:13:50 kardel
752 * Revision 4.7 1999/02/21 11:09:14 kardel
755 * Revision 4.6 1998/06/14 21:09:36 kardel
758 * Revision 4.5 1998/06/13 15:18:54 kardel
759 * fix mem*() to b*() function macro emulation
761 * Revision 4.4 1998/06/13 12:03:23 kardel
762 * fix SYSV clock name clash
764 * Revision 4.3 1998/06/12 15:22:28 kardel
767 * Revision 4.2 1998/05/24 16:14:42 kardel
768 * support current Meinberg standard data formats
770 * Revision 4.1 1998/05/24 09:39:52 kardel
771 * implementation of the new IO handling model
773 * Revision 4.0 1998/04/10 19:45:29 kardel
774 * Start 4.0 release version numbering
776 * from V3 3.23 - log info deleted 1998/04/11 kardel