2 * /src/NTP/ntp4-dev/libparse/parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
4 * parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
6 * Parser module for reference clock
8 * PARSEKERNEL define switches between two personalities of the module
9 * if PARSEKERNEL is defined this module can be used
10 * as kernel module. In this case the time stamps will be
12 * when PARSEKERNEL is not defined NTP time stamps will be used.
14 * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
15 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the author nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
49 #if !(defined(lint) || defined(__GNUC__))
50 static char rcsid[] = "parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A";
54 #include "timevalops.h"
55 #include "ntp_calendar.h"
56 #include "ntp_stdlib.h"
57 #include "ntp_machine.h"
58 #include "ntp.h" /* (get Y2KFixes definitions) Y2KFixes */
65 # include "sys/parsestreams.h"
68 extern clockformat_t *clockformats[];
69 extern unsigned short nformats;
71 static u_long timepacket (parse_t *);
74 * strings support usually not in kernel - duplicated, but what the heck
78 register const char *s
96 register const char *s,
97 register const char *t
102 if (!s || !t || (s == t))
107 while (!(c = *s++ - *t++) && *s && *t)
120 struct timeval delta;
123 delta.tv_sec = tstamp->tv.tv_sec - parseio->parse_lastchar.tv.tv_sec;
124 delta.tv_usec = tstamp->tv.tv_usec - parseio->parse_lastchar.tv.tv_usec;
125 if (delta.tv_usec < 0)
128 delta.tv_usec += 1000000;
134 L_SUB(&delt, &parseio->parse_lastchar.fp);
135 TSTOTV(&delt, &delta);
138 if (timercmp(&delta, del, >))
140 parseprintf(DD_PARSE, ("parse: timedout: TRUE\n"));
145 parseprintf(DD_PARSE, ("parse: timedout: FALSE\n"));
153 register parse_t *parseio
156 parseprintf(DD_PARSE, ("parse_iostart\n"));
158 parseio->parse_plen = 0;
159 parseio->parse_pdata = (void *)0;
161 parseio->parse_data = 0;
162 parseio->parse_ldata = 0;
163 parseio->parse_dsize = 0;
165 parseio->parse_badformat = 0;
166 parseio->parse_ioflags = PARSE_IO_CS7; /* usual unix default */
167 parseio->parse_index = 0;
168 parseio->parse_ldsize = 0;
176 register parse_t *parseio
179 parseprintf(DD_PARSE, ("parse_ioend\n"));
181 if (parseio->parse_pdata)
182 FREE(parseio->parse_pdata, parseio->parse_plen);
184 if (parseio->parse_data)
185 FREE(parseio->parse_data, (unsigned)(parseio->parse_dsize * 2 + 2));
194 unsigned int updated = PARSE_INP_SKIP;
197 * re-start packet - timeout - overflow - start symbol
200 if (parseio->parse_index)
203 * filled buffer - thus not end character found
206 parseio->parse_data[parseio->parse_index] = '\0';
207 memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
208 parseio->parse_ldsize = parseio->parse_index;
209 updated = PARSE_INP_TIME;
212 parseio->parse_index = 1;
213 parseio->parse_data[0] = ch;
214 parseprintf(DD_PARSE, ("parse: parse_restart: buffer start (updated = %x)\n", updated));
227 if (parseio->parse_index < parseio->parse_dsize)
230 * collect into buffer
232 parseprintf(DD_PARSE, ("parse: parse_addchar: buffer[%d] = 0x%x\n", parseio->parse_index, ch));
233 parseio->parse_data[parseio->parse_index++] = (char)ch;
234 return PARSE_INP_SKIP;
238 * buffer overflow - attempt to make the best of it
240 return parse_restart(parseio, ch);
249 * message complete processing
251 parseio->parse_data[parseio->parse_index] = '\0';
252 memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
253 parseio->parse_ldsize = parseio->parse_index;
254 parseio->parse_index = 0;
255 parseprintf(DD_PARSE, ("parse: parse_end: buffer end\n"));
256 return PARSE_INP_TIME;
262 register parse_t *parseio,
264 register timestamp_t *tstamp
267 register u_int updated = CVT_NONE;
269 * within STREAMS CSx (x < 8) chars still have the upper bits set
270 * so we normalize the characters by masking unecessary bits off.
272 switch (parseio->parse_ioflags & PARSE_IO_CSIZE)
291 parseprintf(DD_PARSE, ("parse_ioread(0x%p, char=0x%x, ..., ...)\n", (void*)parseio, ch & 0xFF));
293 if (!clockformats[parseio->parse_lformat]->convert)
295 parseprintf(DD_PARSE, ("parse_ioread: input dropped.\n"));
299 if (clockformats[parseio->parse_lformat]->input)
301 unsigned long input_status;
303 input_status = clockformats[parseio->parse_lformat]->input(parseio, ch, tstamp);
305 if (input_status & PARSE_INP_SYNTH)
310 if (input_status & PARSE_INP_TIME) /* time sample is available */
312 updated = (u_int) timepacket(parseio);
315 if (input_status & PARSE_INP_DATA) /* got additional data */
317 updated |= CVT_ADDITIONAL;
323 * remember last character time
325 parseio->parse_lastchar = *tstamp;
328 if ((updated & CVT_MASK) != CVT_NONE)
330 parseprintf(DD_PARSE, ("parse_ioread: time sample accumulated (status=0x%x)\n", updated));
334 parseio->parse_dtime.parse_status = updated;
336 return (((updated & CVT_MASK) != CVT_NONE) ||
337 ((updated & CVT_ADDITIONAL) != 0));
343 * take status line indication and derive synchronisation information
345 * It can also be used to decode a serial serial data format (such as the
346 * ONE, ZERO, MINUTE sync data stream from DCF77)
351 register parse_t *parseio,
353 register timestamp_t *ptime
356 register u_int updated = CVT_NONE;
359 * PPS pulse information will only be delivered to ONE clock format
360 * this is either the last successful conversion module with a ppssync
361 * routine, or a fixed format with a ppssync routine
363 parseprintf(DD_PARSE, ("parse_iopps: STATUS %s\n", (status == SYNC_ONE) ? "ONE" : "ZERO"));
365 if (clockformats[parseio->parse_lformat]->syncpps)
367 updated = (u_int) clockformats[parseio->parse_lformat]->syncpps(parseio, status == SYNC_ONE, ptime);
368 parseprintf(DD_PARSE, ("parse_iopps: updated = 0x%x\n", updated));
371 return (updated & CVT_MASK) != CVT_NONE;
377 * clean up internal status for new round
382 register parse_t *parseio
386 * we need to clean up certain flags for the next round
388 parseprintf(DD_PARSE, ("parse_iodone: DONE\n"));
389 parseio->parse_dtime.parse_state = 0; /* no problems with ISRs */
392 /*---------- conversion implementation --------------------*/
395 * convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
397 #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
401 register clocktime_t *clock_time,
402 register u_long *cvtrtc
405 #define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); }
406 static int days_of_month[] =
408 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
413 if (clock_time->utctime)
414 return clock_time->utctime; /* if the conversion routine gets it right away - why not */
416 if ( clock_time->year < YEAR_PIVOT ) /* Y2KFixes [ */
417 clock_time->year += 100; /* convert 20xx%100 to 20xx-1900 */
418 if ( clock_time->year < YEAR_BREAK ) /* expand to full four-digits */
419 clock_time->year += 1900;
421 if (clock_time->year < 1970 ) /* Y2KFixes ] */
423 SETRTC(CVT_FAIL|CVT_BADDATE);
428 * sorry, slow section here - but it's not time critical anyway
430 t = julian0(clock_time->year) - julian0(1970); /* Y2kFixes */
432 if (clock_time->month <= 0 || clock_time->month > 12)
434 SETRTC(CVT_FAIL|CVT_BADDATE);
435 return -1; /* bad month */
439 /* adjust leap year */
440 if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
442 #else /* Y2KFixes [ */
443 if ( clock_time->month >= 3 && isleap_4(clock_time->year) )
444 t++; /* add one more if within leap year */
445 #endif /* Y2KFixes ] */
447 for (i = 1; i < clock_time->month; i++)
449 t += days_of_month[i];
452 if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
453 clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
455 SETRTC(CVT_FAIL|CVT_BADDATE);
456 return -1; /* bad day */
459 t += clock_time->day - 1;
461 if (clock_time->hour < 0 || clock_time->hour >= 24)
463 SETRTC(CVT_FAIL|CVT_BADTIME);
464 return -1; /* bad hour */
467 t = TIMES24(t) + clock_time->hour;
470 if (clock_time->minute < 0 || clock_time->minute > 59)
472 SETRTC(CVT_FAIL|CVT_BADTIME);
473 return -1; /* bad min */
476 t = TIMES60(t) + clock_time->minute;
479 if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */
481 SETRTC(CVT_FAIL|CVT_BADTIME);
482 return -1; /* bad sec */
485 t = TIMES60(t) + clock_time->second;
487 t += clock_time->utcoffset; /* warp to UTC */
491 clock_time->utctime = t; /* documentray only */
496 /*--------------- format conversion -----------------------------------*/
500 const unsigned char *s,
505 char unsigned const *b = s;
526 if (c == '\0' || c < '0' || c > '9' || (cnt && ((s-b) > cnt)))
537 z = (z << 3) + (z << 1) + ( c - '0' );
544 const unsigned char *s,
545 const unsigned char *m
553 if ((*m == ' ') ? 1 : (*s == *m))
568 register parse_t *parseio,
569 register u_long flags
577 parseio->parse_lstate = parseio->parse_dtime.parse_state | flags | PARSEB_TIMECODE;
579 parseio->parse_dtime.parse_state = parseio->parse_lstate;
582 (void)splx((unsigned int)s);
588 parseprintf(DD_PARSE, ("updatetimeinfo status=0x%x, time=%x\n", parseio->parse_dtime.parse_state,
589 parseio->parse_dtime.parse_time.tv.tv_sec));
591 parseprintf(DD_PARSE, ("updatetimeinfo status=0x%lx, time=%x\n", (long)parseio->parse_dtime.parse_state,
592 parseio->parse_dtime.parse_time.fp.l_ui));
595 return CVT_OK; /* everything fine and dandy... */
602 * handle a sync time stamp
607 register parse_t *parseio,
608 register timestamp_t *ts,
609 register struct format *format,
613 parseio->parse_dtime.parse_stime = *ts;
617 * parse_pps_fnc_t pps_simple
619 * handle a pps time stamp
624 register parse_t *parseio,
626 register timestamp_t *ptime
629 parseio->parse_dtime.parse_ptime = *ptime;
630 parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
636 * parse_pps_fnc_t pps_one
638 * handle a pps time stamp in ONE edge
643 register parse_t *parseio,
645 register timestamp_t *ptime
649 return pps_simple(parseio, status, ptime);
655 * parse_pps_fnc_t pps_zero
657 * handle a pps time stamp in ZERO edge
662 register parse_t *parseio,
664 register timestamp_t *ptime
668 return pps_simple(parseio, status, ptime);
676 * process a data packet
680 register parse_t *parseio
683 register unsigned short format;
685 u_long cvtrtc; /* current conversion result */
686 clocktime_t clock_time;
688 memset((char *)&clock_time, 0, sizeof clock_time);
689 format = parseio->parse_lformat;
691 if (format == (unsigned short)~0)
694 switch ((cvtrtc = clockformats[format]->convert ?
695 clockformats[format]->convert((unsigned char *)parseio->parse_ldata, parseio->parse_ldsize, (struct format *)(clockformats[format]->data), &clock_time, parseio->parse_pdata) :
696 CVT_NONE) & CVT_MASK)
699 parseio->parse_badformat++;
704 * too bad - pretend bad format
706 parseio->parse_badformat++;
716 /* shouldn't happen */
718 msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"", clockformats[format]->name);
720 return CVT_FAIL|cvtrtc;
723 if ((t = parse_to_unixtime(&clock_time, &cvtrtc)) == -1)
725 return CVT_FAIL|cvtrtc;
732 parseio->parse_dtime.parse_time.tv.tv_sec = t;
733 parseio->parse_dtime.parse_time.tv.tv_usec = clock_time.usecond;
735 parseio->parse_dtime.parse_time.fp.l_ui = (uint32_t) (t + JAN_1970);
736 TVUTOTSF(clock_time.usecond, parseio->parse_dtime.parse_time.fp.l_uf);
739 parseio->parse_dtime.parse_format = format;
741 return updatetimeinfo(parseio, clock_time.flags);
751 dct->parsegettc.parse_state = parse->parse_lstate;
752 dct->parsegettc.parse_format = parse->parse_lformat;
754 * move out current bad packet count
755 * user program is expected to sum these up
756 * this is not a problem, as "parse" module are
757 * exclusive open only
759 dct->parsegettc.parse_badformat = parse->parse_badformat;
760 parse->parse_badformat = 0;
762 if (parse->parse_ldsize <= PARSE_TCMAX)
764 dct->parsegettc.parse_count = parse->parse_ldsize;
765 memcpy(dct->parsegettc.parse_buffer, parse->parse_ldata, dct->parsegettc.parse_count);
782 if (dct->parseformat.parse_count <= PARSE_TCMAX)
784 if (dct->parseformat.parse_count)
786 register unsigned short i;
788 for (i = 0; i < nformats; i++)
790 if (!Strcmp(dct->parseformat.parse_buffer, clockformats[i]->name))
792 if (parse->parse_pdata)
793 FREE(parse->parse_pdata, parse->parse_plen);
794 parse->parse_pdata = 0;
796 parse->parse_plen = clockformats[i]->plen;
798 if (parse->parse_plen)
800 parse->parse_pdata = MALLOC(parse->parse_plen);
801 if (!parse->parse_pdata)
803 parseprintf(DD_PARSE, ("set format failed: malloc for private data area failed\n"));
806 memset((char *)parse->parse_pdata, 0, parse->parse_plen);
809 if (parse->parse_data)
810 FREE(parse->parse_data, (unsigned)(parse->parse_dsize * 2 + 2));
811 parse->parse_ldata = parse->parse_data = 0;
813 parse->parse_dsize = clockformats[i]->length;
815 if (parse->parse_dsize)
817 parse->parse_data = (char*)MALLOC((unsigned)(parse->parse_dsize * 2 + 2));
818 if (!parse->parse_data)
820 if (parse->parse_pdata)
821 FREE(parse->parse_pdata, parse->parse_plen);
822 parse->parse_pdata = 0;
824 parseprintf(DD_PARSE, ("init failed: malloc for data area failed\n"));
831 * leave room for '\0'
833 parse->parse_ldata = parse->parse_data + parse->parse_dsize + 1;
835 parse->parse_lformat = i;
852 if (dct->parseformat.parse_format < nformats &&
853 Strlen(clockformats[dct->parseformat.parse_format]->name) <= PARSE_TCMAX)
855 dct->parseformat.parse_count = (unsigned short) (Strlen(clockformats[dct->parseformat.parse_format]->name) + 1);
856 memcpy(dct->parseformat.parse_buffer, clockformats[dct->parseformat.parse_format]->name, dct->parseformat.parse_count);
872 parse->parse_ioflags &= ~PARSE_IO_CSIZE;
873 parse->parse_ioflags |= (int) (dct->parsesetcs.parse_cs & PARSE_IO_CSIZE);
877 #else /* not (REFCLOCK && CLOCK_PARSE) */
879 #endif /* not (REFCLOCK && CLOCK_PARSE) */
885 * Revision 4.20 2005/08/06 17:39:40 kardel
886 * cleanup size handling wrt/ to buffer boundaries
888 * Revision 4.19 2005/04/16 17:32:10 kardel
891 * Revision 4.18 2004/11/14 16:11:05 kardel
894 * Revision 4.17 2004/11/14 15:29:41 kardel
895 * support PPSAPI, upgrade Copyright to Berkeley style
897 * Revision 4.14 1999/11/28 09:13:52 kardel
900 * Revision 4.13 1999/02/28 11:50:20 kardel
901 * (timepacket): removed unecessary code
903 * Revision 4.12 1999/02/21 12:17:44 kardel
904 * 4.91f reconcilation
906 * Revision 4.11 1999/02/21 11:09:47 kardel
907 * unified debug output
909 * Revision 4.10 1998/12/20 23:45:30 kardel
910 * fix types and warnings
912 * Revision 4.9 1998/08/09 22:26:06 kardel
913 * Trimble TSIP support
915 * Revision 4.8 1998/06/14 21:09:39 kardel
918 * Revision 4.7 1998/06/13 15:19:13 kardel
919 * fix mem*() to b*() function macro emulation
921 * Revision 4.6 1998/06/13 13:24:13 kardel
924 * Revision 4.5 1998/06/13 13:01:10 kardel
927 * Revision 4.4 1998/06/13 12:12:10 kardel
928 * bcopy/memcpy cleanup
929 * fix SVSV name clash
931 * Revision 4.3 1998/06/12 15:22:30 kardel
934 * Revision 4.2 1998/06/12 09:13:27 kardel
935 * conditional compile macros fixed
938 * Revision 4.1 1998/05/24 09:39:55 kardel
939 * implementation of the new IO handling model
941 * Revision 4.0 1998/04/10 19:45:36 kardel
942 * Start 4.0 release version numbering
944 * from V3 3.46 log info deleted 1998/04/11 kardel