File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / libparse / clk_meinberg.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 4 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
    3:  *  
    4:  * clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
    5:  *
    6:  * Meinberg clock support
    7:  *
    8:  * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
    9:  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
   10:  *
   11:  * Redistribution and use in source and binary forms, with or without
   12:  * modification, are permitted provided that the following conditions
   13:  * are met:
   14:  * 1. Redistributions of source code must retain the above copyright
   15:  *    notice, this list of conditions and the following disclaimer.
   16:  * 2. Redistributions in binary form must reproduce the above copyright
   17:  *    notice, this list of conditions and the following disclaimer in the
   18:  *    documentation and/or other materials provided with the distribution.
   19:  * 3. Neither the name of the author nor the names of its contributors
   20:  *    may be used to endorse or promote products derived from this software
   21:  *    without specific prior written permission.
   22:  *
   23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33:  * SUCH DAMAGE.
   34:  *
   35:  */
   36: 
   37: #ifdef HAVE_CONFIG_H
   38: # include <config.h>
   39: #endif
   40: 
   41: #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_MEINBERG)
   42: 
   43: #include "ntp_fp.h"
   44: #include "ntp_unixtime.h"
   45: #include "ntp_calendar.h"
   46: 
   47: #include "ntp_machine.h"
   48: 
   49: #include "parse.h"
   50: 
   51: #ifndef PARSESTREAM
   52: #include <stdio.h>
   53: #else
   54: #include "sys/parsestreams.h"
   55: #endif
   56: 
   57: #include "ntp_stdlib.h"
   58: 
   59: #include "ntp_stdlib.h"
   60: 
   61: #include "mbg_gps166.h"
   62: #include "binio.h"
   63: #include "ascii.h"
   64: 
   65: /*
   66:  * The Meinberg receiver every second sends a datagram of the following form
   67:  * (Standard Format)
   68:  * 
   69:  *     <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
   70:  * pos:  0  00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2  2  3  3   3
   71:  *       1  23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8  9  0  1   2
   72:  * <STX>           = '\002' ASCII start of text
   73:  * <ETX>           = '\003' ASCII end of text
   74:  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
   75:  * <w>             = day of week (sunday= 0)
   76:  * <hh>,<mm>,<ss>  = hour, minute, second
   77:  * <S>             = '#' if never synced since powerup for DCF C51
   78:  *                 = '#' if not PZF sychronisation available for PZF 535/509
   79:  *                 = ' ' if ok
   80:  * <F>             = '*' if time comes from internal quartz
   81:  *                 = ' ' if completely synched
   82:  * <D>             = 'S' if daylight saving time is active
   83:  *                 = 'U' if time is represented in UTC
   84:  *                 = ' ' if no special condition exists
   85:  * <A>             = '!' during the hour preceeding an daylight saving time
   86:  *                       start/end change
   87:  *                 = 'A' leap second insert warning
   88:  *                 = ' ' if no special condition exists
   89:  *
   90:  * Extended data format (PZFUERL for PZF type clocks)
   91:  *
   92:  *     <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
   93:  * pos:  0   00 0 00 0 00 11 1 11 11 1 11 2 22 22 2  2  2  2  2  3  3   3
   94:  *       1   23 4 56 7 89 01 2 34 56 7 89 0 12 34 5  6  7  8  9  0  1   2
   95:  * <STX>           = '\002' ASCII start of text
   96:  * <ETX>           = '\003' ASCII end of text
   97:  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
   98:  * <w>             = day of week (sunday= 0)
   99:  * <hh>,<mm>,<ss>  = hour, minute, second
  100:  * <U>             = 'U' UTC time display
  101:  * <S>             = '#' if never synced since powerup else ' ' for DCF C51
  102:  *                   '#' if not PZF sychronisation available else ' ' for PZF 535/509
  103:  * <F>             = '*' if time comes from internal quartz else ' '
  104:  * <D>             = 'S' if daylight saving time is active else ' '
  105:  * <A>             = '!' during the hour preceeding an daylight saving time
  106:  *                       start/end change
  107:  * <L>             = 'A' LEAP second announcement
  108:  * <R>             = 'R' alternate antenna
  109:  *
  110:  * Meinberg GPS166 receiver
  111:  *
  112:  * You must get the Uni-Erlangen firmware for the GPS receiver support
  113:  * to work to full satisfaction !
  114:  *
  115:  *     <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
  116:  *
  117:  *        000000000111111111122222222223333333333444444444455555555556666666
  118:  *        123456789012345678901234567890123456789012345678901234567890123456
  119:  *     \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N  11.0280E  373m\x03
  120:  *
  121:  * 
  122:  * <STX>           = '\002' ASCII start of text
  123:  * <ETX>           = '\003' ASCII end of text
  124:  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
  125:  * <w>             = day of week (sunday= 0)
  126:  * <hh>,<mm>,<ss>  = hour, minute, second
  127:  * <+/->,<00:00>   = offset to UTC
  128:  * <S>             = '#' if never synced since powerup else ' '
  129:  * <F>             = '*' if position is not confirmed else ' '
  130:  * <D>             = 'S' if daylight saving time is active else ' '
  131:  * <A>             = '!' during the hour preceeding an daylight saving time
  132:  *                       start/end change
  133:  * <L>             = 'A' LEAP second announcement
  134:  * <R>             = 'R' alternate antenna (reminiscent of PZF535) usually ' '
  135:  * <L>		   = 'L' on 23:59:60
  136:  *
  137:  * Binary messages have a lead in for a fixed header of SOH
  138:  */
  139: 
  140: /*--------------------------------------------------------------*/
  141: /* Name:         csum()                                         */
  142: /*                                                              */
  143: /* Purpose:      Compute a checksum about a number of bytes     */
  144: /*                                                              */
  145: /* Input:        uchar *p    address of the first byte          */
  146: /*               short n     the number of bytes                */
  147: /*                                                              */
  148: /* Output:       --                                             */
  149: /*                                                              */
  150: /* Ret val:      the checksum                                   */
  151: /*+-------------------------------------------------------------*/
  152: 
  153: unsigned long
  154: mbg_csum(
  155: 	 unsigned char *p,
  156: 	 unsigned int n
  157: 	 )
  158: {
  159:   unsigned long sum = 0;
  160:   short i;
  161:   
  162:   for ( i = 0; i < n; i++ )
  163:     sum += *p++;
  164:   
  165:   return( sum );
  166: }  /* csum */
  167: 
  168: void
  169: get_mbg_header(
  170: 	       unsigned char **bufpp,
  171: 	       GPS_MSG_HDR *headerp
  172: 	       )
  173: {
  174:   headerp->gps_cmd = get_lsb_short(bufpp);
  175:   headerp->gps_len = get_lsb_short(bufpp);
  176:   headerp->gps_data_csum = get_lsb_short(bufpp);
  177:   headerp->gps_hdr_csum  = get_lsb_short(bufpp);
  178: }
  179: 
  180: static struct format meinberg_fmt[] =
  181: {
  182: 	{
  183: 		{
  184: 			{ 3, 2},  {  6, 2}, {  9, 2},
  185: 			{ 18, 2}, { 21, 2}, { 24, 2},
  186: 			{ 14, 1}, { 27, 4}, { 29, 1},
  187: 		},
  188: 		(const unsigned char *)"\2D:  .  .  ;T: ;U:  .  .  ;    \3",
  189: 		0
  190: 	},
  191: 	{			/* special extended FAU Erlangen extended format */
  192: 		{
  193: 			{ 1, 2},  { 4,  2}, {  7, 2},
  194: 			{ 14, 2}, { 17, 2}, { 20, 2},
  195: 			{ 11, 1}, { 25, 4}, { 27, 1},
  196: 		},
  197: 		(const unsigned char *)"\2  .  .  ;  ;   :  :  ;        \3",
  198: 		MBG_EXTENDED
  199: 	},
  200: 	{			/* special extended FAU Erlangen GPS format */
  201: 		{
  202: 			{ 1,  2}, {  4, 2}, {  7, 2},
  203: 			{ 14, 2}, { 17, 2}, { 20, 2},
  204: 			{ 11, 1}, { 32, 7}, { 35, 1},
  205: 			{ 25, 2}, { 28, 2}, { 24, 1}
  206: 		},
  207: 		(const unsigned char *)"\2  .  .  ;  ;   :  :  ;    :  ;        ;   .         .       ",
  208: 		0
  209: 	}
  210: };
  211: 
  212: static u_long cvt_meinberg (unsigned char *, int, struct format *, clocktime_t *, void *);
  213: static u_long cvt_mgps     (unsigned char *, int, struct format *, clocktime_t *, void *);
  214: static u_long mbg_input    (parse_t *, unsigned int, timestamp_t *);
  215: static u_long gps_input    (parse_t *, unsigned int, timestamp_t *);
  216: 
  217: struct msg_buf
  218: {
  219:   unsigned short len;		/* len to fill */
  220:   unsigned short phase;		/* current input phase */
  221: };
  222: 
  223: #define MBG_NONE	0	/* no data input */
  224: #define MBG_HEADER	1	/* receiving header */
  225: #define MBG_DATA	2	/* receiving data */
  226: #define MBG_STRING      3	/* receiving standard data message */
  227:   
  228: clockformat_t clock_meinberg[] =
  229: {
  230: 	{
  231: 		mbg_input,	/* normal input handling */
  232: 		cvt_meinberg,	/* Meinberg conversion */
  233: 		pps_one,	/* easy PPS monitoring */
  234: 		0,		/* conversion configuration */
  235: 		"Meinberg Standard", /* Meinberg simple format - beware */
  236: 		32,				/* string buffer */
  237: 		0		/* no private data (complete pakets) */
  238: 	},
  239: 	{
  240: 		mbg_input,	/* normal input handling */
  241: 		cvt_meinberg,	/* Meinberg conversion */
  242: 		pps_one,	/* easy PPS monitoring */
  243: 		0,		/* conversion configuration */
  244: 		"Meinberg Extended", /* Meinberg enhanced format */
  245: 		32,		/* string buffer */
  246: 		0		/* no private data (complete pakets) */
  247: 	},
  248: 	{
  249: 		gps_input,	/* no input handling */
  250: 		cvt_mgps,	/* Meinberg GPS166 conversion */
  251: 		pps_one,	/* easy PPS monitoring */
  252: 		(void *)&meinberg_fmt[2], /* conversion configuration */
  253: 		"Meinberg GPS Extended", /* Meinberg FAU GPS format */
  254: 		512,		/* string buffer */
  255: 		sizeof(struct msg_buf)	/* no private data (complete pakets) */
  256: 	}
  257: };
  258: 
  259: /*
  260:  * cvt_meinberg
  261:  *
  262:  * convert simple type format
  263:  */
  264: static u_long
  265: cvt_meinberg(
  266: 	     unsigned char *buffer,
  267: 	     int            size,
  268: 	     struct format *unused,
  269: 	     clocktime_t   *clock_time,
  270: 	     void          *local
  271: 	     )
  272: {
  273: 	struct format *format;
  274: 	
  275: 	/*
  276: 	 * select automagically correct data format
  277: 	 */
  278: 	if (Strok(buffer, meinberg_fmt[0].fixed_string))
  279: 	{
  280: 		format = &meinberg_fmt[0];
  281: 	}
  282: 	else
  283: 	{
  284: 		if (Strok(buffer, meinberg_fmt[1].fixed_string))
  285: 		{
  286: 			format = &meinberg_fmt[1];
  287: 		}
  288: 		else
  289: 		{
  290: 			return CVT_FAIL|CVT_BADFMT;
  291: 		}
  292: 	}
  293: 
  294: 	/*
  295: 	 * collect data
  296: 	 */
  297: 	if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
  298: 		 format->field_offsets[O_DAY].length) ||
  299: 	    Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
  300: 		 format->field_offsets[O_MONTH].length) ||
  301: 	    Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
  302: 		 format->field_offsets[O_YEAR].length) ||
  303: 	    Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
  304: 		 format->field_offsets[O_HOUR].length) ||
  305: 	    Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
  306: 		 format->field_offsets[O_MIN].length) ||
  307: 	    Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
  308: 		 format->field_offsets[O_SEC].length))
  309: 	{
  310: 		return CVT_FAIL|CVT_BADFMT;
  311: 	}
  312: 	else
  313: 	{
  314: 		unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
  315: 		
  316: 		clock_time->usecond = 0;
  317: 		clock_time->flags   = PARSEB_S_LEAP;
  318: 
  319: 		if (clock_time->second == 60)
  320: 			clock_time->flags |= PARSEB_LEAPSECOND;
  321: 
  322: 		/*
  323: 		 * in the extended timecode format we have also the
  324: 		 * indication that the timecode is in UTC
  325: 		 * for compatibilty reasons we start at the USUAL
  326: 		 * offset (POWERUP flag) and know that the UTC indication
  327: 		 * is the character before the powerup flag
  328: 		 */
  329: 		if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U'))
  330: 		{
  331: 			/*
  332: 			 * timecode is in UTC
  333: 			 */
  334: 			clock_time->utcoffset = 0; /* UTC */
  335: 			clock_time->flags    |= PARSEB_UTC;
  336: 		}
  337: 		else
  338: 		{
  339: 			/*
  340: 			 * only calculate UTC offset if MET/MED is in time code
  341: 			 * or we have the old time code format, where we do not
  342: 			 * know whether it is UTC time or MET/MED
  343: 			 * pray that nobody switches to UTC in the *old* standard time code
  344: 			 * ROMS !!!! The new ROMS have 'U' at the ZONE field - good.
  345: 			 */
  346: 			switch (buffer[format->field_offsets[O_ZONE].offset])
  347: 			{
  348: 			case ' ':
  349: 				clock_time->utcoffset = -1*60*60; /* MET */
  350: 				break;
  351: 				
  352: 			case 'S':
  353: 				clock_time->utcoffset = -2*60*60; /* MED */
  354: 				break;
  355: 
  356: 			case 'U':
  357: 				/*
  358: 				 * timecode is in UTC
  359: 				 */
  360: 				clock_time->utcoffset = 0;        /* UTC */
  361: 				clock_time->flags    |= PARSEB_UTC;
  362: 				break;
  363: 				
  364: 			default:
  365: 				return CVT_FAIL|CVT_BADFMT;
  366: 			}
  367: 		}
  368: 		
  369: 		/*
  370: 		 * gather status flags
  371: 		 */
  372: 		if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
  373: 			clock_time->flags    |= PARSEB_DST;
  374: 		
  375: 		if (f[0] == '#')
  376: 			clock_time->flags |= PARSEB_POWERUP;
  377: 		
  378: 		if (f[1] == '*')
  379: 			clock_time->flags |= PARSEB_NOSYNC;
  380: 		
  381: 		if (f[3] == '!')
  382: 			clock_time->flags |= PARSEB_ANNOUNCE;
  383: 		
  384: 		/*
  385: 		 * oncoming leap second
  386: 		 * 'a' code not confirmed - earth is not
  387: 		 * expected to speed up
  388: 		 */
  389: 		if (f[3] == 'A')
  390: 			clock_time->flags |= PARSEB_LEAPADD;
  391: 		
  392: 		if (f[3] == 'a')
  393: 			clock_time->flags |= PARSEB_LEAPDEL;
  394: 		
  395: 		
  396: 		if (format->flags & MBG_EXTENDED)
  397: 		{
  398: 			clock_time->flags |= PARSEB_S_ANTENNA;
  399: 			
  400: 			/*
  401: 			 * DCF77 does not encode the direction -
  402: 			 * so we take the current default -
  403: 			 * earth slowing down
  404: 			 */
  405: 			clock_time->flags &= ~PARSEB_LEAPDEL;
  406: 			
  407: 			if (f[4] == 'A')
  408: 				clock_time->flags |= PARSEB_LEAPADD;
  409: 			
  410: 			if (f[5] == 'R')
  411: 				clock_time->flags |= PARSEB_ALTERNATE;
  412: 		}
  413: 		return CVT_OK;
  414: 	}
  415: }
  416: 
  417: 
  418: /*
  419:  * mbg_input
  420:  *
  421:  * grep data from input stream
  422:  */
  423: static u_long
  424: mbg_input(
  425: 	  parse_t      *parseio,
  426: 	  unsigned int  ch,
  427: 	  timestamp_t  *tstamp
  428: 	  )
  429: {
  430: 	unsigned int rtc;
  431: 	
  432: 	parseprintf(DD_PARSE, ("mbg_input(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
  433: 	
  434: 	switch (ch)
  435: 	{
  436: 	case STX:
  437: 		parseprintf(DD_PARSE, ("mbg_input: STX seen\n"));
  438: 		
  439: 		parseio->parse_index = 1;
  440: 		parseio->parse_data[0] = ch;
  441: 		parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
  442: 		return PARSE_INP_SKIP;
  443: 	  
  444: 	case ETX:
  445: 		parseprintf(DD_PARSE, ("mbg_input: ETX seen\n"));
  446: 		if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
  447: 			return parse_end(parseio);
  448: 		else
  449: 			return rtc;
  450: 
  451: 	default:
  452: 		return parse_addchar(parseio, ch);
  453: 	}
  454: }
  455: 
  456: 
  457: /*
  458:  * cvt_mgps
  459:  *
  460:  * convert Meinberg GPS format
  461:  */
  462: static u_long
  463: cvt_mgps(
  464: 	 unsigned char *buffer,
  465: 	 int            size,
  466: 	 struct format *format,
  467: 	 clocktime_t   *clock_time,
  468: 	 void          *local
  469: 	)
  470: {
  471: 	if (!Strok(buffer, format->fixed_string))
  472: 	{
  473: 		return cvt_meinberg(buffer, size, format, clock_time, local);
  474: 	}
  475: 	else
  476: 	{
  477: 		if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
  478: 			 format->field_offsets[O_DAY].length) ||
  479: 		    Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
  480: 			 format->field_offsets[O_MONTH].length) ||
  481: 		    Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
  482: 			 format->field_offsets[O_YEAR].length) ||
  483: 		    Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
  484: 			 format->field_offsets[O_HOUR].length) ||
  485: 		    Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
  486: 			 format->field_offsets[O_MIN].length) ||
  487: 		    Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
  488: 			 format->field_offsets[O_SEC].length))
  489: 		{
  490: 			return CVT_FAIL|CVT_BADFMT;
  491: 		}
  492: 		else
  493: 		{
  494: 			long h;
  495: 			unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
  496: 	  
  497: 			clock_time->flags = PARSEB_S_LEAP|PARSEB_S_POSITION;
  498: 	      
  499: 			clock_time->usecond = 0;
  500: 
  501: 			/*
  502: 			 * calculate UTC offset
  503: 			 */
  504: 			if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h,
  505: 				 format->field_offsets[O_UTCHOFFSET].length))
  506: 			{
  507: 				return CVT_FAIL|CVT_BADFMT;
  508: 			}
  509: 			else
  510: 			{
  511: 				if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock_time->utcoffset,
  512: 					 format->field_offsets[O_UTCMOFFSET].length))
  513: 				{
  514: 					return CVT_FAIL|CVT_BADFMT;
  515: 				}
  516: 
  517: 				clock_time->utcoffset += TIMES60(h);
  518: 				clock_time->utcoffset  = TIMES60(clock_time->utcoffset);
  519: 
  520: 				if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-')
  521: 				{
  522: 					clock_time->utcoffset = -clock_time->utcoffset;
  523: 				}
  524: 			}
  525: 	  
  526: 			/*
  527: 			 * gather status flags
  528: 			 */
  529: 			if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
  530: 			    clock_time->flags    |= PARSEB_DST;
  531: 	  
  532: 			if (clock_time->utcoffset == 0)
  533: 			    clock_time->flags |= PARSEB_UTC;
  534: 	  
  535: 			/*
  536: 			 * no sv's seen - no time & position
  537: 			 */
  538: 			if (f[0] == '#')
  539: 			    clock_time->flags |= PARSEB_POWERUP;
  540: 	  
  541: 			/*
  542: 			 * at least one sv seen - time (for last position)
  543: 			 */
  544: 			if (f[1] == '*')
  545: 			    clock_time->flags |= PARSEB_NOSYNC;
  546: 			else
  547: 			    if (!(clock_time->flags & PARSEB_POWERUP))
  548: 				clock_time->flags |= PARSEB_POSITION;
  549: 	  
  550: 			/*
  551: 			 * oncoming zone switch
  552: 			 */
  553: 			if (f[3] == '!')
  554: 			    clock_time->flags |= PARSEB_ANNOUNCE;
  555: 	  
  556: 			/*
  557: 			 * oncoming leap second
  558: 			 * 'a' code not confirmed - earth is not
  559: 			 * expected to speed up
  560: 			 */
  561: 			if (f[4] == 'A')
  562: 			    clock_time->flags |= PARSEB_LEAPADD;
  563: 	  
  564: 			if (f[4] == 'a')
  565: 			    clock_time->flags |= PARSEB_LEAPDEL;
  566: 
  567: 			/*
  568: 			 * f[5] == ' '
  569: 			 */
  570: 	  
  571: 			/*
  572: 			 * this is the leap second
  573: 			 */
  574: 			if ((f[6] == 'L') || (clock_time->second == 60))
  575: 			    clock_time->flags |= PARSEB_LEAPSECOND;
  576: 
  577: 			return CVT_OK;
  578: 		}
  579: 	}
  580: }
  581: 
  582: /*
  583:  * gps_input
  584:  *
  585:  * grep binary data from input stream
  586:  */
  587: static u_long
  588: gps_input(
  589: 	  parse_t      *parseio,
  590: 	  unsigned int  ch,
  591: 	  timestamp_t  *tstamp
  592: 	  )
  593: {
  594:   CSUM calc_csum;                    /* used to compare the incoming csums */
  595:   GPS_MSG_HDR header;
  596:   struct msg_buf *msg_buf;
  597:   
  598:   msg_buf = (struct msg_buf *)parseio->parse_pdata;
  599: 
  600:   parseprintf(DD_PARSE, ("gps_input(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
  601: 
  602:   if (!msg_buf)
  603:     return PARSE_INP_SKIP;
  604:   
  605:   if ( msg_buf->phase == MBG_NONE )
  606:     {                  /* not receiving yet */
  607:       switch (ch)
  608: 	{
  609: 	case SOH:
  610: 	  parseprintf(DD_PARSE, ("gps_input: SOH seen\n"));
  611: 	  
  612: 	  msg_buf->len = sizeof( header ); /* prepare to receive msg header */
  613: 	  msg_buf->phase = MBG_HEADER; /* receiving header */
  614: 	  break;
  615: 
  616: 	case STX:
  617: 	  parseprintf(DD_PARSE, ("gps_input: STX seen\n"));
  618: 
  619: 	  msg_buf->len = 0;
  620: 	  msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */
  621: 	  parseio->parse_index = 1;
  622: 	  parseio->parse_data[0] = ch;
  623: 	  break;
  624: 	  
  625: 	default:
  626: 	  return PARSE_INP_SKIP;	/* keep searching */
  627: 	}
  628: 
  629:       parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */
  630:       parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */
  631:       parseio->parse_dtime.parse_stime  = *tstamp; /* collect timestamp */
  632:       return PARSE_INP_SKIP;
  633:     }
  634: 
  635:   /* SOH/STX has already been received */
  636: 
  637:   /* save incoming character in both buffers if needbe */
  638:   if ((msg_buf->phase == MBG_STRING) &&
  639:       (parseio->parse_index < parseio->parse_dsize))
  640:     parseio->parse_data[parseio->parse_index++] = ch;
  641:   
  642:   parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
  643: 
  644:   if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg))
  645:     {
  646:       msg_buf->phase = MBG_NONE; /* buffer overflow - discard */
  647:       parseio->parse_data[parseio->parse_index] = '\0';
  648:       memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
  649:       parseio->parse_ldsize = parseio->parse_index;
  650:       return PARSE_INP_DATA;
  651:     }
  652:   
  653:   switch (msg_buf->phase)
  654:     {
  655:     case MBG_HEADER:
  656:     case MBG_DATA:
  657:       msg_buf->len--;
  658: 
  659:       if ( msg_buf->len )               /* transfer not complete */
  660: 	return PARSE_INP_SKIP;
  661: 
  662:       parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header"));
  663: 
  664:       break;
  665: 
  666:     case MBG_STRING:
  667:       if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize))
  668: 	{
  669: 	  msg_buf->phase = MBG_NONE;
  670: 	  parseprintf(DD_PARSE, ("gps_input: string complete\n"));
  671: 	  parseio->parse_data[parseio->parse_index] = '\0';
  672: 	  memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
  673: 	  parseio->parse_ldsize = parseio->parse_index;
  674: 	  parseio->parse_index = 0;
  675: 	  return PARSE_INP_TIME;
  676: 	}
  677:       else
  678: 	{
  679: 	  return PARSE_INP_SKIP;
  680: 	}
  681:     }
  682: 
  683:   /* cnt == 0, so the header or the whole message is complete */
  684: 
  685:   if ( msg_buf->phase == MBG_HEADER )
  686:     {         /* header complete now */
  687:       unsigned char *datap = parseio->parse_dtime.parse_msg + 1;
  688:       
  689:       get_mbg_header(&datap, &header);
  690:       
  691:       parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n",
  692: 			     (int)header.gps_cmd, (int)header.gps_len, (int)header.gps_data_csum,
  693: 			     (int)header.gps_hdr_csum));
  694:       
  695: 
  696:       calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 );
  697: 
  698:       if ( calc_csum != header.gps_hdr_csum )
  699: 	{
  700: 	  parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n",
  701: 				 (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 )));
  702: 	  
  703: 	  msg_buf->phase = MBG_NONE;  /* back to hunting mode */
  704: 	  return PARSE_INP_DATA;      /* invalid header checksum received - pass up for detection */
  705: 	}
  706: 
  707:       if ((header.gps_len == 0)  ||       /* no data to wait for */
  708: 	  (header.gps_len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1)))	/* blows anything we have space for */
  709: 	{
  710: 	  msg_buf->phase = MBG_NONE;  /* back to hunting mode */
  711: 	  return (header.gps_len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */
  712: 	}
  713:     
  714:       parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.gps_len));
  715:       
  716:       msg_buf->len   = header.gps_len;/* save number of bytes to wait for */
  717:       msg_buf->phase = MBG_DATA;      /* flag header already complete */
  718:       return PARSE_INP_SKIP;
  719:     }
  720: 
  721:   parseprintf(DD_PARSE, ("gps_input: message data complete\n"));
  722:   
  723:   /* Header and data have been received. The header checksum has been */
  724:   /* checked */
  725: 
  726:   msg_buf->phase = MBG_NONE;	      /* back to hunting mode */
  727:   return PARSE_INP_DATA;              /* message complete, must be evaluated */
  728: }
  729: 
  730: #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
  731: int clk_meinberg_bs;
  732: #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
  733: 
  734: /*
  735:  * History:
  736:  *
  737:  * clk_meinberg.c,v
  738:  * Revision 4.12.2.1  2005/09/25 10:22:35  kardel
  739:  * cleanup buffer bounds
  740:  *
  741:  * Revision 4.12  2005/04/16 17:32:10  kardel
  742:  * update copyright
  743:  *
  744:  * Revision 4.11  2004/11/14 15:29:41  kardel
  745:  * support PPSAPI, upgrade Copyright to Berkeley style
  746:  *
  747:  * Revision 4.8  1999/11/28 09:13:50  kardel
  748:  * RECON_4_0_98F
  749:  *
  750:  * Revision 4.7  1999/02/21 11:09:14  kardel
  751:  * cleanup
  752:  *
  753:  * Revision 4.6  1998/06/14 21:09:36  kardel
  754:  * Sun acc cleanup
  755:  *
  756:  * Revision 4.5  1998/06/13 15:18:54  kardel
  757:  * fix mem*() to b*() function macro emulation
  758:  *
  759:  * Revision 4.4  1998/06/13 12:03:23  kardel
  760:  * fix SYSV clock name clash
  761:  *
  762:  * Revision 4.3  1998/06/12 15:22:28  kardel
  763:  * fix prototypes
  764:  *
  765:  * Revision 4.2  1998/05/24 16:14:42  kardel
  766:  * support current Meinberg standard data formats
  767:  *
  768:  * Revision 4.1  1998/05/24 09:39:52  kardel
  769:  * implementation of the new IO handling model
  770:  *
  771:  * Revision 4.0  1998/04/10 19:45:29  kardel
  772:  * Start 4.0 release version numbering
  773:  *
  774:  * from V3 3.23 - log info deleted 1998/04/11 kardel
  775:  *
  776:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>