1 /* $NetBSD: parse.c,v 1.2 2003/12/04 16:23:37 drochner Exp $ */
4 * /src/NTP/ntp4-dev/libparse/parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
6 * parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
8 * Parser module for reference clock
10 * PARSEKERNEL define switches between two personalities of the module
11 * if PARSEKERNEL is defined this module can be used
12 * as kernel module. In this case the time stamps will be
14 * when PARSEKERNEL is not defined NTP time stamps will be used.
16 * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
17 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * 3. Neither the name of the author nor the names of its contributors
28 * may be used to endorse or promote products derived from this software
29 * without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
51 #if !(defined(lint) || defined(__GNUC__))
52 static char rcsid
[] = "parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A";
56 #include "ntp_unixtime.h"
57 #include "ntp_calendar.h"
58 #include "ntp_stdlib.h"
59 #include "ntp_machine.h"
60 #include "ntp.h" /* (get Y2KFixes definitions) Y2KFixes */
67 # include "sys/parsestreams.h"
70 extern clockformat_t
*clockformats
[];
71 extern unsigned short nformats
;
73 static u_long timepacket
P((parse_t
*));
76 * strings support usually not in kernel - duplicated, but what the heck
80 register const char *s
98 register const char *s
,
99 register const char *t
104 if (!s
|| !t
|| (s
== t
))
109 while (!(c
= *s
++ - *t
++) && *s
&& *t
)
122 struct timeval delta
;
125 delta
.tv_sec
= tstamp
->tv
.tv_sec
- parseio
->parse_lastchar
.tv
.tv_sec
;
126 delta
.tv_usec
= tstamp
->tv
.tv_usec
- parseio
->parse_lastchar
.tv
.tv_usec
;
127 if (delta
.tv_usec
< 0)
130 delta
.tv_usec
+= 1000000;
133 extern long tstouslo
[];
134 extern long tstousmid
[];
135 extern long tstoushi
[];
140 L_SUB(&delt
, &parseio
->parse_lastchar
.fp
);
141 TSTOTV(&delt
, &delta
);
144 if (timercmp(&delta
, del
, >))
146 parseprintf(DD_PARSE
, ("parse: timedout: TRUE\n"));
151 parseprintf(DD_PARSE
, ("parse: timedout: FALSE\n"));
159 register parse_t
*parseio
162 parseprintf(DD_PARSE
, ("parse_iostart\n"));
164 parseio
->parse_plen
= 0;
165 parseio
->parse_pdata
= (void *)0;
167 parseio
->parse_data
= 0;
168 parseio
->parse_ldata
= 0;
169 parseio
->parse_dsize
= 0;
171 parseio
->parse_badformat
= 0;
172 parseio
->parse_ioflags
= PARSE_IO_CS7
; /* usual unix default */
173 parseio
->parse_index
= 0;
174 parseio
->parse_ldsize
= 0;
182 register parse_t
*parseio
185 parseprintf(DD_PARSE
, ("parse_ioend\n"));
187 if (parseio
->parse_pdata
)
188 FREE(parseio
->parse_pdata
, parseio
->parse_plen
);
190 if (parseio
->parse_data
)
191 FREE(parseio
->parse_data
, (unsigned)(parseio
->parse_dsize
* 2 + 2));
200 unsigned int updated
= PARSE_INP_SKIP
;
203 * re-start packet - timeout - overflow - start symbol
206 if (parseio
->parse_index
)
209 * filled buffer - thus not end character found
212 parseio
->parse_data
[parseio
->parse_index
] = '\0';
213 memcpy(parseio
->parse_ldata
, parseio
->parse_data
, (unsigned)(parseio
->parse_index
+1));
214 parseio
->parse_ldsize
= parseio
->parse_index
;
215 updated
= PARSE_INP_TIME
;
218 parseio
->parse_index
= 1;
219 parseio
->parse_data
[0] = ch
;
220 parseprintf(DD_PARSE
, ("parse: parse_restart: buffer start (updated = %x)\n", updated
));
233 if (parseio
->parse_index
< parseio
->parse_dsize
)
236 * collect into buffer
238 parseprintf(DD_PARSE
, ("parse: parse_addchar: buffer[%d] = 0x%x\n", parseio
->parse_index
, ch
));
239 parseio
->parse_data
[parseio
->parse_index
++] = ch
;
240 return PARSE_INP_SKIP
;
244 * buffer overflow - attempt to make the best of it
246 return parse_restart(parseio
, ch
);
255 * message complete processing
257 parseio
->parse_data
[parseio
->parse_index
] = '\0';
258 memcpy(parseio
->parse_ldata
, parseio
->parse_data
, (unsigned)(parseio
->parse_index
+1));
259 parseio
->parse_ldsize
= parseio
->parse_index
;
260 parseio
->parse_index
= 0;
261 parseprintf(DD_PARSE
, ("parse: parse_end: buffer end\n"));
262 return PARSE_INP_TIME
;
268 register parse_t
*parseio
,
269 register unsigned int ch
,
270 register timestamp_t
*tstamp
273 register unsigned updated
= CVT_NONE
;
275 * within STREAMS CSx (x < 8) chars still have the upper bits set
276 * so we normalize the characters by masking unecessary bits off.
278 switch (parseio
->parse_ioflags
& PARSE_IO_CSIZE
)
297 parseprintf(DD_PARSE
, ("parse_ioread(0x%lx, char=0x%x, ..., ...)\n", (unsigned long)parseio
, ch
& 0xFF));
299 if (!clockformats
[parseio
->parse_lformat
]->convert
)
301 parseprintf(DD_PARSE
, ("parse_ioread: input dropped.\n"));
305 if (clockformats
[parseio
->parse_lformat
]->input
)
307 unsigned long input_status
;
309 input_status
= clockformats
[parseio
->parse_lformat
]->input(parseio
, ch
, tstamp
);
311 if (input_status
& PARSE_INP_SYNTH
)
316 if (input_status
& PARSE_INP_TIME
) /* time sample is available */
318 updated
= timepacket(parseio
);
321 if (input_status
& PARSE_INP_DATA
) /* got additional data */
323 updated
|= CVT_ADDITIONAL
;
329 * remember last character time
331 parseio
->parse_lastchar
= *tstamp
;
334 if ((updated
& CVT_MASK
) != CVT_NONE
)
336 parseprintf(DD_PARSE
, ("parse_ioread: time sample accumulated (status=0x%x)\n", updated
));
340 parseio
->parse_dtime
.parse_status
= updated
;
342 return (((updated
& CVT_MASK
) != CVT_NONE
) ||
343 ((updated
& CVT_ADDITIONAL
) != 0));
349 * take status line indication and derive synchronisation information
351 * It can also be used to decode a serial serial data format (such as the
352 * ONE, ZERO, MINUTE sync data stream from DCF77)
357 register parse_t
*parseio
,
359 register timestamp_t
*ptime
362 register unsigned updated
= CVT_NONE
;
365 * PPS pulse information will only be delivered to ONE clock format
366 * this is either the last successful conversion module with a ppssync
367 * routine, or a fixed format with a ppssync routine
369 parseprintf(DD_PARSE
, ("parse_iopps: STATUS %s\n", (status
== SYNC_ONE
) ? "ONE" : "ZERO"));
371 if (clockformats
[parseio
->parse_lformat
]->syncpps
)
373 updated
= clockformats
[parseio
->parse_lformat
]->syncpps(parseio
, status
== SYNC_ONE
, ptime
);
374 parseprintf(DD_PARSE
, ("parse_iopps: updated = 0x%x\n", updated
));
377 return (updated
& CVT_MASK
) != CVT_NONE
;
383 * clean up internal status for new round
388 register parse_t
*parseio
392 * we need to clean up certain flags for the next round
394 parseprintf(DD_PARSE
, ("parse_iodone: DONE\n"));
395 parseio
->parse_dtime
.parse_state
= 0; /* no problems with ISRs */
398 /*---------- conversion implementation --------------------*/
401 * convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
403 #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
407 register clocktime_t
*clock_time
,
408 register u_long
*cvtrtc
411 #define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); }
412 static int days_of_month
[] =
414 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
419 if (clock_time
->utctime
)
420 return clock_time
->utctime
; /* if the conversion routine gets it right away - why not */
422 if ( clock_time
->year
< YEAR_PIVOT
) /* Y2KFixes [ */
423 clock_time
->year
+= 100; /* convert 20xx%100 to 20xx-1900 */
424 if ( clock_time
->year
< YEAR_BREAK
) /* expand to full four-digits */
425 clock_time
->year
+= 1900;
427 if (clock_time
->year
< 1970 ) /* Y2KFixes ] */
429 SETRTC(CVT_FAIL
|CVT_BADDATE
);
434 * sorry, slow section here - but it's not time critical anyway
436 t
= julian0(clock_time
->year
) - julian0(1970); /* Y2kFixes */
438 if (clock_time
->month
<= 0 || clock_time
->month
> 12)
440 SETRTC(CVT_FAIL
|CVT_BADDATE
);
441 return -1; /* bad month */
445 /* adjust leap year */
446 if (clock_time
->month
< 3 && days_per_year(clock_time
->year
) == 366)
448 #else /* Y2KFixes [ */
449 if ( clock_time
->month
>= 3 && isleap_4(clock_time
->year
) )
450 t
++; /* add one more if within leap year */
451 #endif /* Y2KFixes ] */
453 for (i
= 1; i
< clock_time
->month
; i
++)
455 t
+= days_of_month
[i
];
458 if (clock_time
->day
< 1 || ((clock_time
->month
== 2 && days_per_year(clock_time
->year
) == 366) ?
459 clock_time
->day
> 29 : clock_time
->day
> days_of_month
[clock_time
->month
]))
461 SETRTC(CVT_FAIL
|CVT_BADDATE
);
462 return -1; /* bad day */
465 t
+= clock_time
->day
- 1;
467 if (clock_time
->hour
< 0 || clock_time
->hour
>= 24)
469 SETRTC(CVT_FAIL
|CVT_BADTIME
);
470 return -1; /* bad hour */
473 t
= TIMES24(t
) + clock_time
->hour
;
476 if (clock_time
->minute
< 0 || clock_time
->minute
> 59)
478 SETRTC(CVT_FAIL
|CVT_BADTIME
);
479 return -1; /* bad min */
482 t
= TIMES60(t
) + clock_time
->minute
;
485 if (clock_time
->second
< 0 || clock_time
->second
> 60) /* allow for LEAPs */
487 SETRTC(CVT_FAIL
|CVT_BADTIME
);
488 return -1; /* bad sec */
491 t
= TIMES60(t
) + clock_time
->second
;
493 t
+= clock_time
->utcoffset
; /* warp to UTC */
497 clock_time
->utctime
= t
; /* documentray only */
502 /*--------------- format conversion -----------------------------------*/
506 const unsigned char *s
,
511 char unsigned const *b
= s
;
532 if (c
== '\0' || c
< '0' || c
> '9' || (cnt
&& ((s
-b
) > cnt
)))
543 z
= (z
<< 3) + (z
<< 1) + ( c
- '0' );
550 const unsigned char *s
,
551 const unsigned char *m
559 if ((*m
== ' ') ? 1 : (*s
== *m
))
574 register parse_t
*parseio
,
575 register u_long flags
583 parseio
->parse_lstate
= parseio
->parse_dtime
.parse_state
| flags
| PARSEB_TIMECODE
;
585 parseio
->parse_dtime
.parse_state
= parseio
->parse_lstate
;
588 (void)splx((unsigned int)s
);
594 parseprintf(DD_PARSE
, ("updatetimeinfo status=0x%x, time=%x\n", parseio
->parse_dtime
.parse_state
,
595 parseio
->parse_dtime
.parse_time
.tv
.tv_sec
));
597 parseprintf(DD_PARSE
, ("updatetimeinfo status=0x%lx, time=%x\n", (long)parseio
->parse_dtime
.parse_state
,
598 parseio
->parse_dtime
.parse_time
.fp
.l_ui
));
601 return CVT_OK
; /* everything fine and dandy... */
608 * handle a sync time stamp
613 register parse_t
*parseio
,
614 register timestamp_t
*ts
,
615 register struct format
*format
,
619 parseio
->parse_dtime
.parse_stime
= *ts
;
625 * handle a pps time stamp
630 register parse_t
*parseio
,
632 register timestamp_t
*ptime
635 parseio
->parse_dtime
.parse_ptime
= *ptime
;
636 parseio
->parse_dtime
.parse_state
|= PARSEB_PPS
|PARSEB_S_PPS
;
644 * handle a pps time stamp in ONE edge
649 register parse_t
*parseio
,
651 register timestamp_t
*ptime
655 return pps_simple(parseio
, status
, ptime
);
663 * handle a pps time stamp in ZERO edge
668 register parse_t
*parseio
,
670 register timestamp_t
*ptime
674 return pps_simple(parseio
, status
, ptime
);
682 * process a data packet
686 register parse_t
*parseio
689 register unsigned short format
;
691 u_long cvtrtc
; /* current conversion result */
692 clocktime_t clock_time
;
694 memset((char *)&clock_time
, 0, sizeof clock_time
);
695 format
= parseio
->parse_lformat
;
697 if (format
== (unsigned short)~0)
700 switch ((cvtrtc
= clockformats
[format
]->convert
?
701 clockformats
[format
]->convert((unsigned char *)parseio
->parse_ldata
, parseio
->parse_ldsize
, (struct format
*)(clockformats
[format
]->data
), &clock_time
, parseio
->parse_pdata
) :
702 CVT_NONE
) & CVT_MASK
)
705 parseio
->parse_badformat
++;
710 * too bad - pretend bad format
712 parseio
->parse_badformat
++;
722 /* shouldn't happen */
724 msyslog(LOG_WARNING
, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats
[format
]->name
);
726 return CVT_FAIL
|cvtrtc
;
729 if ((t
= parse_to_unixtime(&clock_time
, &cvtrtc
)) == -1)
731 return CVT_FAIL
|cvtrtc
;
738 parseio
->parse_dtime
.parse_time
.tv
.tv_sec
= t
;
739 parseio
->parse_dtime
.parse_time
.tv
.tv_usec
= clock_time
.usecond
;
741 parseio
->parse_dtime
.parse_time
.fp
.l_ui
= t
+ JAN_1970
;
742 TVUTOTSF(clock_time
.usecond
, parseio
->parse_dtime
.parse_time
.fp
.l_uf
);
745 parseio
->parse_dtime
.parse_format
= format
;
747 return updatetimeinfo(parseio
, clock_time
.flags
);
757 dct
->parsegettc
.parse_state
= parse
->parse_lstate
;
758 dct
->parsegettc
.parse_format
= parse
->parse_lformat
;
760 * move out current bad packet count
761 * user program is expected to sum these up
762 * this is not a problem, as "parse" module are
763 * exclusive open only
765 dct
->parsegettc
.parse_badformat
= parse
->parse_badformat
;
766 parse
->parse_badformat
= 0;
768 if (parse
->parse_ldsize
<= PARSE_TCMAX
)
770 dct
->parsegettc
.parse_count
= parse
->parse_ldsize
;
771 memcpy(dct
->parsegettc
.parse_buffer
, parse
->parse_ldata
, dct
->parsegettc
.parse_count
);
788 if (dct
->parseformat
.parse_count
<= PARSE_TCMAX
)
790 if (dct
->parseformat
.parse_count
)
792 register unsigned short i
;
794 for (i
= 0; i
< nformats
; i
++)
796 if (!Strcmp(dct
->parseformat
.parse_buffer
, clockformats
[i
]->name
))
798 if (parse
->parse_pdata
)
799 FREE(parse
->parse_pdata
, parse
->parse_plen
);
800 parse
->parse_pdata
= 0;
802 parse
->parse_plen
= clockformats
[i
]->plen
;
804 if (parse
->parse_plen
)
806 parse
->parse_pdata
= MALLOC(parse
->parse_plen
);
807 if (!parse
->parse_pdata
)
809 parseprintf(DD_PARSE
, ("set format failed: malloc for private data area failed\n"));
812 memset((char *)parse
->parse_pdata
, 0, parse
->parse_plen
);
815 if (parse
->parse_data
)
816 FREE(parse
->parse_data
, (unsigned)(parse
->parse_dsize
* 2 + 2));
817 parse
->parse_ldata
= parse
->parse_data
= 0;
819 parse
->parse_dsize
= clockformats
[i
]->length
;
821 if (parse
->parse_dsize
)
823 parse
->parse_data
= (char*)MALLOC((unsigned)(parse
->parse_dsize
* 2 + 2));
824 if (!parse
->parse_data
)
826 if (parse
->parse_pdata
)
827 FREE(parse
->parse_pdata
, parse
->parse_plen
);
828 parse
->parse_pdata
= 0;
830 parseprintf(DD_PARSE
, ("init failed: malloc for data area failed\n"));
837 * leave room for '\0'
839 parse
->parse_ldata
= parse
->parse_data
+ parse
->parse_dsize
+ 1;
841 parse
->parse_lformat
= i
;
858 if (dct
->parseformat
.parse_format
< nformats
&&
859 Strlen(clockformats
[dct
->parseformat
.parse_format
]->name
) <= PARSE_TCMAX
)
861 dct
->parseformat
.parse_count
= Strlen(clockformats
[dct
->parseformat
.parse_format
]->name
)+1;
862 memcpy(dct
->parseformat
.parse_buffer
, clockformats
[dct
->parseformat
.parse_format
]->name
, dct
->parseformat
.parse_count
);
878 parse
->parse_ioflags
&= ~PARSE_IO_CSIZE
;
879 parse
->parse_ioflags
|= dct
->parsesetcs
.parse_cs
& PARSE_IO_CSIZE
;
883 #else /* not (REFCLOCK && CLOCK_PARSE) */
885 #endif /* not (REFCLOCK && CLOCK_PARSE) */
891 * Revision 4.20 2005/08/06 17:39:40 kardel
892 * cleanup size handling wrt/ to buffer boundaries
894 * Revision 4.19 2005/04/16 17:32:10 kardel
897 * Revision 4.18 2004/11/14 16:11:05 kardel
900 * Revision 4.17 2004/11/14 15:29:41 kardel
901 * support PPSAPI, upgrade Copyright to Berkeley style
903 * Revision 4.14 1999/11/28 09:13:52 kardel
906 * Revision 4.13 1999/02/28 11:50:20 kardel
907 * (timepacket): removed unecessary code
909 * Revision 4.12 1999/02/21 12:17:44 kardel
910 * 4.91f reconcilation
912 * Revision 4.11 1999/02/21 11:09:47 kardel
913 * unified debug output
915 * Revision 4.10 1998/12/20 23:45:30 kardel
916 * fix types and warnings
918 * Revision 4.9 1998/08/09 22:26:06 kardel
919 * Trimble TSIP support
921 * Revision 4.8 1998/06/14 21:09:39 kardel
924 * Revision 4.7 1998/06/13 15:19:13 kardel
925 * fix mem*() to b*() function macro emulation
927 * Revision 4.6 1998/06/13 13:24:13 kardel
930 * Revision 4.5 1998/06/13 13:01:10 kardel
933 * Revision 4.4 1998/06/13 12:12:10 kardel
934 * bcopy/memcpy cleanup
935 * fix SVSV name clash
937 * Revision 4.3 1998/06/12 15:22:30 kardel
940 * Revision 4.2 1998/06/12 09:13:27 kardel
941 * conditional compile macros fixed
944 * Revision 4.1 1998/05/24 09:39:55 kardel
945 * implementation of the new IO handling model
947 * Revision 4.0 1998/04/10 19:45:36 kardel
948 * Start 4.0 release version numbering
950 * from V3 3.46 log info deleted 1998/04/11 kardel