File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_jjy.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, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * refclock_jjy - clock driver for JJY receivers
    3:  */
    4: 
    5: /**********************************************************************/
    6: /*								      */
    7: /*  Copyright (C) 2001-2004, Takao Abe.  All rights reserved.	      */
    8: /*								      */
    9: /*  Permission to use, copy, modify, and distribute this software     */
   10: /*  and its documentation for any purpose is hereby granted	      */
   11: /*  without fee, provided that the following conditions are met:      */
   12: /*								      */
   13: /*  One retains the entire copyright notice properly, and both the    */
   14: /*  copyright notice and this license. in the documentation and/or    */
   15: /*  other materials provided with the distribution.		      */
   16: /*								      */
   17: /*  This software and the name of the author must not be used to      */
   18: /*  endorse or promote products derived from this software without    */
   19: /*  prior written permission.					      */
   20: /*								      */
   21: /*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
   22: /*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE	      */
   23: /*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A	      */
   24: /*  PARTICULAR PURPOSE.						      */
   25: /*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
   26: /*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
   27: /*  ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE	      */
   28: /*  GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS      */
   29: /*  INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     */
   30: /*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING	      */
   31: /*  NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF    */
   32: /*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
   33: /*								      */
   34: /*  This driver is developed in my private time, and is opened as     */
   35: /*  voluntary contributions for the NTP.			      */
   36: /*  The manufacturer of the JJY receiver has not participated in      */
   37: /*  a development of this driver.				      */
   38: /*  The manufacturer does not warrant anything about this driver,     */
   39: /*  and is not liable for anything about this driver.		      */
   40: /*								      */
   41: /**********************************************************************/
   42: /*								      */
   43: /*  Author     Takao Abe					      */
   44: /*  Email      takao_abe@xurb.jp				      */
   45: /*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/		      */
   46: /*								      */
   47: /*  The email address abetakao@bea.hi-ho.ne.jp is never read	      */
   48: /*  from 2010, because a few filtering rule are provided by the	      */
   49: /*  "hi-ho.ne.jp", and lots of spam mail are reached.		      */
   50: /*  New email address for supporting the refclock_jjy is	      */
   51: /*  takao_abe@xurb.jp						      */
   52: /*								      */
   53: /**********************************************************************/
   54: /*								      */
   55: /*  History							      */
   56: /*								      */
   57: /*  2001/07/15							      */
   58: /*    [New]    Support the Tristate Ltd. JJY receiver		      */
   59: /*								      */
   60: /*  2001/08/04							      */
   61: /*    [Change] Log to clockstats even if bad reply		      */
   62: /*    [Fix]    PRECISION = (-3) (about 100 ms)			      */
   63: /*    [Add]    Support the C-DEX Co.Ltd. JJY receiver		      */
   64: /*								      */
   65: /*  2001/12/04							      */
   66: /*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
   67: /*								      */
   68: /*  2002/07/12							      */
   69: /*    [Fix]    Portability for FreeBSD ( patched by the user )	      */
   70: /*								      */
   71: /*  2004/10/31							      */
   72: /*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
   73: /*	       JJY-01 ( Firmware version 2.01 )			      */
   74: /*	       Thanks to Andy Taki for testing under FreeBSD	      */
   75: /*								      */
   76: /*  2004/11/28							      */
   77: /*    [Add]    Support the Echo Keisokuki LT-2000 receiver	      */
   78: /*								      */
   79: /*  2006/11/04							      */
   80: /*    [Fix]    C-DEX JST2000					      */
   81: /*	       Thanks to Hideo Kuramatsu for the patch		      */
   82: /*								      */
   83: /*  2009/04/05							      */
   84: /*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver	      */
   85: /*								      */
   86: /*  2010/11/20							      */
   87: /*    [Change] Bug 1618 ( Harmless )				      */
   88: /*	       Code clean up ( Remove unreachable codes ) in	      */
   89: /*	       jjy_start()					      */
   90: /*    [Change] Change clockstats format of the Tristate JJY01/02      */
   91: /*	       Issues more command to get the status of the receiver  */
   92: /*	       when "fudge 127.127.40.X flag1 1" is specified	      */
   93: /*	       ( DATE,STIM -> DCST,STUS,DATE,STIM )		      */
   94: /*								      */
   95: /**********************************************************************/
   96: 
   97: #ifdef HAVE_CONFIG_H
   98: #include <config.h>
   99: #endif
  100: 
  101: #if defined(REFCLOCK) && defined(CLOCK_JJY)
  102: 
  103: #include <stdio.h>
  104: #include <ctype.h>
  105: #include <string.h>
  106: #include <sys/time.h>
  107: #include <time.h>
  108: 
  109: #include "ntpd.h"
  110: #include "ntp_io.h"
  111: #include "ntp_tty.h"
  112: #include "ntp_refclock.h"
  113: #include "ntp_calendar.h"
  114: #include "ntp_stdlib.h"
  115: 
  116: /**********************************************************************/
  117: /*								      */
  118: /*  The Tristate Ltd. JJY receiver JJY01			      */
  119: /*								      */
  120: /*  Command	   Response		    Remarks		      */
  121: /*  ------------   ----------------------   ---------------------     */
  122: /*  dcst<CR><LF>   VALID|INVALID<CR><LF>			      */
  123: /*  stus<CR><LF>   ADJUSTED|UNADJUSTED<CR><LF>			      */
  124: /*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>			      */
  125: /*  time<CR><LF>   HH:MM:SS<CR><LF>				      */
  126: /*  stim<CR><LF>   HH:MM:SS<CR><LF>	    Reply at just second      */
  127: /*								      */
  128: /*  During synchronization after a receiver is turned on,	      */
  129: /*  It replies the past time from 2000/01/01 00:00:00.		      */
  130: /*  The function "refclock_process" checks the time and tells	      */
  131: /*  as an insanity time.					      */
  132: /*								      */
  133: /**********************************************************************/
  134: /*								      */
  135: /*  The C-DEX Co. Ltd. JJY receiver JST2000			      */
  136: /*								      */
  137: /*  Command	   Response		    Remarks		      */
  138: /*  ------------   ----------------------   ---------------------     */
  139: /*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>			      */
  140: /*								      */
  141: /**********************************************************************/
  142: /*								      */
  143: /*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000		      */
  144: /*								      */
  145: /*  Command        Response		    Remarks		      */
  146: /*  ------------   ----------------------   ---------------------     */
  147: /*  #					    Mode 1 (Request&Send)     */
  148: /*  T		   YYMMDDWHHMMSS<BCC1><BCC2><CR>		      */
  149: /*  C					    Mode 2 (Continuous)	      */
  150: /*		   YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>	      */
  151: /*		   <SUB>		    Second signal	      */
  152: /*								      */
  153: /**********************************************************************/
  154: /*								      */
  155: /*  The CITIZEN T.I.C CO., LTD. JJY receiver JJY200		      */
  156: /*								      */
  157: /*  Command	   Response		    Remarks		      */
  158: /*  ------------   ----------------------   ---------------------     */
  159: /*		   'XX YY/MM/DD W HH:MM:SS<CR>			      */
  160: /*					    XX: OK|NG|ER	      */
  161: /*					    W:  0(Monday)-6(Sunday)   */
  162: /*								      */
  163: /**********************************************************************/
  164: 
  165: /*
  166:  * Interface definitions
  167:  */
  168: #define	DEVICE  	"/dev/jjy%d"	/* device name and unit */
  169: #define	SPEED232	B9600		/* uart speed (9600 baud) */
  170: #define	SPEED232_TRISTATE_JJY01		B9600   /* UART speed (9600 baud) */
  171: #define	SPEED232_CDEX_JST2000		B9600   /* UART speed (9600 baud) */
  172: #define	SPEED232_ECHOKEISOKUKI_LT2000	B9600   /* UART speed (9600 baud) */
  173: #define	SPEED232_CITIZENTIC_JJY200	B4800   /* UART speed (4800 baud) */
  174: #define	REFID   	"JJY"		/* reference ID */
  175: #define	DESCRIPTION	"JJY Receiver"
  176: #define	PRECISION	(-3)		/* precision assumed (about 100 ms) */
  177: 
  178: /*
  179:  * JJY unit control structure
  180:  */
  181: struct jjyunit {
  182: 	char	unittype ;	    /* UNITTYPE_XXXXXXXXXX */
  183: 	short   operationmode ;	    /* Echo Keisokuki LT-2000 : 1 or 2 */
  184: 	short	version ;
  185: 	short	linediscipline ;    /* LDISC_CLK or LDISC_RAW */
  186: 	char    bPollFlag ;	    /* Set by jjy_pool and Reset by jjy_receive */
  187: 	int 	linecount ;
  188: 	int 	lineerror ;
  189: 	int 	year, month, day, hour, minute, second, msecond ;
  190: /* LDISC_RAW only */
  191: #define	MAX_LINECOUNT	8
  192: #define	MAX_RAWBUF   	64
  193: 	int 	lineexpect ;
  194: 	int 	charexpect [ MAX_LINECOUNT ] ;
  195: 	int 	charcount ;
  196: 	char	rawbuf [ MAX_RAWBUF ] ;
  197: };
  198: 
  199: #define	UNITTYPE_TRISTATE_JJY01	1
  200: #define	UNITTYPE_CDEX_JST2000  	2
  201: #define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
  202: #define	UNITTYPE_CITIZENTIC_JJY200  	4
  203: 
  204: /*
  205:  * Function prototypes
  206:  */
  207: static	int 	jjy_start		    (int, struct peer *);
  208: static	void	jjy_shutdown		    (int, struct peer *);
  209: static	void	jjy_poll		    (int, struct peer *);
  210: static	void	jjy_poll_tristate_jjy01	    (int, struct peer *);
  211: static	void	jjy_poll_cdex_jst2000	    (int, struct peer *);
  212: static	void	jjy_poll_echokeisokuki_lt2000(int, struct peer *);
  213: static	void	jjy_poll_citizentic_jjy200  (int, struct peer *);
  214: static	void	jjy_receive		    (struct recvbuf *);
  215: static	int	jjy_receive_tristate_jjy01  (struct recvbuf *);
  216: static	int	jjy_receive_cdex_jst2000    (struct recvbuf *);
  217: static	int	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
  218: static  int	jjy_receive_citizentic_jjy200 (struct recvbuf *);
  219: 
  220: static	void	printableString ( char*, int, char*, int ) ;
  221: 
  222: /*
  223:  * Transfer vector
  224:  */
  225: struct	refclock refclock_jjy = {
  226: 	jjy_start,	/* start up driver */
  227: 	jjy_shutdown,	/* shutdown driver */
  228: 	jjy_poll,	/* transmit poll message */
  229: 	noentry,	/* not used */
  230: 	noentry,	/* not used */
  231: 	noentry,	/* not used */
  232: 	NOFLAGS		/* not used */
  233: };
  234: 
  235: /*
  236:  * Start up driver return code
  237:  */
  238: #define	RC_START_SUCCESS	1
  239: #define	RC_START_ERROR		0
  240: 
  241: /*
  242:  * Local constants definition
  243:  */
  244: 
  245: #define	MAX_LOGTEXT	64
  246: 
  247: /*
  248:  * Tristate JJY01/JJY02 constants definition
  249:  */
  250: 
  251: #define	TS_JJY01_COMMAND_NUMBER_DATE	1
  252: #define	TS_JJY01_COMMAND_NUMBER_TIME	2
  253: #define	TS_JJY01_COMMAND_NUMBER_STIM	3
  254: #define	TS_JJY01_COMMAND_NUMBER_STUS	4
  255: #define	TS_JJY01_COMMAND_NUMBER_DCST	5
  256: 
  257: #define	TS_JJY01_REPLY_DATE		"yyyy/mm/dd www\r\n"
  258: #define	TS_JJY01_REPLY_STIM		"hh:mm:ss\r\n"
  259: #define	TS_JJY01_REPLY_STUS_YES		"adjusted\r\n"
  260: #define	TS_JJY01_REPLY_STUS_NO		"unadjusted\r\n"
  261: #define	TS_JJY01_REPLY_DCST_VALID	"valid\r\n"
  262: #define	TS_JJY01_REPLY_DCST_INVALID	"invalid\r\n"
  263: 
  264: #define	TS_JJY01_REPLY_LENGTH_DATE	    14	/* Length without <CR><LF> */
  265: #define	TS_JJY01_REPLY_LENGTH_STIM	    8	/* Length without <CR><LF> */
  266: #define	TS_JJY01_REPLY_LENGTH_STUS_YES	    8	/* Length without <CR><LF> */
  267: #define	TS_JJY01_REPLY_LENGTH_STUS_NO	    10	/* Length without <CR><LF> */
  268: #define	TS_JJY01_REPLY_LENGTH_DCST_VALID    5	/* Length without <CR><LF> */
  269: #define	TS_JJY01_REPLY_LENGTH_DCST_INVALID  7	/* Length without <CR><LF> */
  270: 
  271: static  struct
  272: {
  273: 	char	commandNumber ;
  274: 	char	*commandLog ;
  275: 	char	*command ;
  276: 	int	commandLength ;
  277: } tristate_jjy01_command_sequence[] =
  278: {
  279: 	/* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */
  280: 	{ TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 },
  281: 	/* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
  282: 	{ TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
  283: 	/* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
  284: 	{ TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
  285: 	/* stim<CR><LF> -> HH:MM:SS<CR><LF> */
  286: 	{ TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 },
  287: 	{ 0			      , NULL  , NULL	  , 0 }
  288: } ;
  289: 
  290: 
  291: /**************************************************************************************************/
  292: /*  jjy_start - open the devices and initialize data for processing                               */
  293: /**************************************************************************************************/
  294: static int
  295: jjy_start ( int unit, struct peer *peer )
  296: {
  297: 
  298: 	struct jjyunit	    *up ;
  299: 	struct refclockproc *pp ;
  300: 	int 	fd ;
  301: 	char	*pDeviceName ;
  302: 	short	iDiscipline ;
  303: 	int 	iSpeed232 ;
  304: 
  305: #ifdef DEBUG
  306: 	if ( debug ) {
  307: 		printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
  308: 		printf ( DEVICE, unit ) ;
  309: 		printf ( "\n" ) ;
  310: 	}
  311: #endif
  312: 	/*
  313: 	 * Open serial port
  314: 	 */
  315: 	pDeviceName = emalloc ( strlen(DEVICE) + 10 );
  316: 	snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ;
  317: 
  318: 	/*
  319: 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
  320: 	 */
  321: 	switch ( peer->ttl ) {
  322: 	case 0 :
  323: 	case 1 :
  324: 		iDiscipline = LDISC_CLK ;
  325: 		iSpeed232   = SPEED232_TRISTATE_JJY01 ;
  326: 		break ;
  327: 	case 2 :
  328: 		iDiscipline = LDISC_RAW ;
  329: 		iSpeed232   = SPEED232_CDEX_JST2000   ;
  330: 		break ;
  331: 	case 3 :
  332: 		iDiscipline = LDISC_CLK ;
  333: 		iSpeed232   = SPEED232_ECHOKEISOKUKI_LT2000 ;
  334: 		break ;
  335: 	case 4 :
  336: 		iDiscipline = LDISC_CLK ;
  337: 		iSpeed232   = SPEED232_CITIZENTIC_JJY200 ;
  338: 		break ;
  339: 	default :
  340: 		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
  341: 			  ntoa(&peer->srcadr), peer->ttl ) ;
  342: 		free ( (void*) pDeviceName ) ;
  343: 		return RC_START_ERROR ;
  344: 	}
  345: 
  346: 	if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
  347: 		free ( (void*) pDeviceName ) ;
  348: 		return RC_START_ERROR ;
  349: 	}
  350: 	free ( (void*) pDeviceName ) ;
  351: 
  352: 	/*
  353: 	 * Allocate and initialize unit structure
  354: 	 */
  355: 	up = emalloc (sizeof(*up));
  356: 	memset ( up, 0, sizeof(*up) ) ;
  357: 	up->linediscipline = iDiscipline ;
  358: 
  359: 	/*
  360: 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
  361: 	 */
  362: 	switch ( peer->ttl ) {
  363: 	case 0 :
  364: 		/*
  365: 		 * The mode 0 is a default clock type at this time.
  366: 		 * But this will be change to auto-detect mode in the future.
  367: 		 */
  368: 	case 1 :
  369: 		up->unittype = UNITTYPE_TRISTATE_JJY01 ;
  370: 		up->version  = 100 ;
  371: 		/* 2010/11/20 */
  372: 		/* Command sequence is defined by the struct tristate_jjy01_command_sequence, */
  373: 		/* and the following 3 lines are not used in the mode LDISC_CLK. */
  374: 		/* up->lineexpect = 2 ; */
  375: 		/* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */
  376: 		/* up->charexpect[1] =  8 ; */ /* HH:MM:SS<CR><LF> */
  377: 		break ;
  378: 	case 2 :
  379: 		up->unittype = UNITTYPE_CDEX_JST2000 ;
  380: 		up->lineexpect = 1 ;
  381: 		up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
  382: 		break ;
  383: 	case 3 :
  384: 		up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
  385: 		up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
  386: 		up->lineexpect = 1 ;
  387: 		switch ( up->operationmode ) {
  388: 		case 1 :
  389: 			up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
  390: 			break ;
  391: 		case 2 :
  392: 			up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
  393: 			break ;
  394: 		}
  395: 		break ;
  396: 	case 4 :
  397: 		up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
  398: 		up->lineexpect = 1 ;
  399: 		up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
  400: 		break ;
  401: 
  402: 	/* 2010/11/20 */
  403: 	/* The "default:" section of this switch block is never executed,     */
  404: 	/* because the former switch block traps the same "default:" case.    */
  405: 	/* This "default:" section codes are removed to avoid spending time   */
  406: 	/* in the future looking, though the codes are functionally harmless. */
  407: 
  408: 	}
  409: 
  410: 	pp = peer->procptr ;
  411: 	pp->unitptr       = (caddr_t) up ;
  412: 	pp->io.clock_recv = jjy_receive ;
  413: 	pp->io.srcclock   = (caddr_t) peer ;
  414: 	pp->io.datalen	  = 0 ;
  415: 	pp->io.fd	  = fd ;
  416: 	if ( ! io_addclock(&pp->io) ) {
  417: 		close ( fd ) ;
  418: 		pp->io.fd = -1 ;
  419: 		free ( up ) ;
  420: 		pp->unitptr = NULL ;
  421: 		return RC_START_ERROR ;
  422: 	}
  423: 
  424: 	/*
  425: 	 * Initialize miscellaneous variables
  426: 	 */
  427: 	peer->precision = PRECISION ;
  428: 	peer->burst	= 1 ;
  429: 	pp->clockdesc	= DESCRIPTION ;
  430: 	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
  431: 
  432: 	return RC_START_SUCCESS ;
  433: 
  434: }
  435: 
  436: 
  437: /**************************************************************************************************/
  438: /*  jjy_shutdown - shutdown the clock                                                             */
  439: /**************************************************************************************************/
  440: static void
  441: jjy_shutdown ( int unit, struct peer *peer )
  442: {
  443: 
  444: 	struct jjyunit	    *up;
  445: 	struct refclockproc *pp;
  446: 
  447: 	pp = peer->procptr ;
  448: 	up = (struct jjyunit *) pp->unitptr ;
  449: 	if ( -1 != pp->io.fd )
  450: 		io_closeclock ( &pp->io ) ;
  451: 	if ( NULL != up )
  452: 		free ( up ) ;
  453: 
  454: }
  455: 
  456: 
  457: /**************************************************************************************************/
  458: /*  jjy_receive - receive data from the serial interface                                          */
  459: /**************************************************************************************************/
  460: static void
  461: jjy_receive ( struct recvbuf *rbufp )
  462: {
  463: 
  464: 	struct jjyunit	    *up ;
  465: 	struct refclockproc *pp ;
  466: 	struct peer	    *peer;
  467: 
  468: 	l_fp	tRecvTimestamp;		/* arrival timestamp */
  469: 	int 	rc ;
  470: 	char	sLogText [ MAX_LOGTEXT ] ;
  471: 	int 	i, bCntrlChar ;
  472: 
  473: 	/*
  474: 	 * Initialize pointers and read the timecode and timestamp
  475: 	 */
  476: 	peer = (struct peer *) rbufp->recv_srcclock ;
  477: 	pp = peer->procptr ;
  478: 	up = (struct jjyunit *) pp->unitptr ;
  479: 
  480: 	/*
  481: 	 * Get next input line
  482: 	 */
  483: 	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
  484: 
  485: 	if ( up->linediscipline == LDISC_RAW ) {
  486: 		/*
  487: 		 * The reply with <STX> and <ETX> may give a blank line
  488: 		 */
  489: 		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
  490: 		/*
  491: 		 * Copy received charaters to temporary buffer 
  492: 		 */
  493: 		for ( i = 0 ;
  494: 		      i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ;
  495: 		      i ++ , up->charcount ++ ) {
  496: 			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
  497: 		}
  498: 		while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
  499: 			for ( i = 0 ; i < up->charcount - 1 ; i ++ )
  500: 				up->rawbuf[i] = up->rawbuf[i+1] ;
  501: 			up->charcount -- ;
  502: 		}
  503: 		bCntrlChar = 0 ;
  504: 		for ( i = 0 ; i < up->charcount ; i ++ ) {
  505: 			if ( up->rawbuf[i] < ' ' ) {
  506: 				bCntrlChar = 1 ;
  507: 				break ;
  508: 			}
  509: 		}
  510: 		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
  511: 			if ( bCntrlChar == 0  &&
  512: 			     up->charcount < up->charexpect[up->linecount] )
  513: 				return ;
  514: 		}
  515: 		up->rawbuf[up->charcount] = 0 ;
  516: 	} else {
  517: 		/*
  518: 		 * The reply with <CR><LF> gives a blank line
  519: 		 */
  520: 		if ( pp->lencode == 0 ) return ;
  521: 	}
  522: 	/*
  523: 	 * We get down to business
  524: 	 */
  525: 
  526: 	pp->lastrec = tRecvTimestamp ;
  527: 
  528: 	up->linecount ++ ;
  529: 
  530: 	if ( up->lineerror != 0 ) return ;
  531: 
  532: 	switch ( up->unittype ) {
  533: 	
  534: 	case UNITTYPE_TRISTATE_JJY01 :
  535: 		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
  536: 		break ;
  537: 
  538: 	case UNITTYPE_CDEX_JST2000 :
  539: 		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
  540: 		break ;
  541: 
  542: 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
  543: 		rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
  544: 		break ;
  545: 
  546: 	case UNITTYPE_CITIZENTIC_JJY200 :
  547: 		rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
  548: 		break ;
  549: 
  550: 	default :
  551: 		rc = 0 ;
  552: 		break ;
  553: 
  554: 	}
  555: 
  556: 	if ( up->linediscipline == LDISC_RAW ) {
  557: 		if ( up->linecount <= up->lineexpect  &&
  558: 		     up->charcount > up->charexpect[up->linecount-1] ) {
  559: 			for ( i = 0 ;
  560: 			      i < up->charcount - up->charexpect[up->linecount-1] ;
  561: 			      i ++ ) {
  562: 				up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
  563: 			}
  564: 			up->charcount -= up->charexpect[up->linecount-1] ;
  565: 		} else {
  566: 			up->charcount = 0 ;
  567: 		}
  568: 	}
  569: 
  570: 	if ( rc == 0 ) 
  571: 		return ;
  572: 
  573: 	up->bPollFlag = 0 ;
  574: 
  575: 	if ( up->lineerror != 0 ) {
  576: 		refclock_report ( peer, CEVNT_BADREPLY ) ;
  577: 		strncpy  ( sLogText, "BAD REPLY [",
  578: 			   sizeof( sLogText ) ) ;
  579: 		if ( up->linediscipline == LDISC_RAW ) {
  580: 			strncat ( sLogText, up->rawbuf,
  581: 				  sizeof( sLogText ) -
  582: 				      strlen ( sLogText ) - 1 ) ;
  583: 		} else {
  584: 			strncat ( sLogText, pp->a_lastcode,
  585: 				  sizeof( sLogText ) -
  586: 				      strlen ( sLogText ) - 1 ) ;
  587: 		}
  588: 		sLogText[MAX_LOGTEXT-1] = 0 ;
  589: 		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 )
  590: 			strncat ( sLogText, "]",
  591: 				  sizeof( sLogText ) -
  592: 				      strlen ( sLogText ) - 1 ) ;
  593: 		record_clock_stats ( &peer->srcadr, sLogText ) ;
  594: 		return ;
  595: 	}
  596: 
  597: 	pp->year   = up->year ;
  598: 	pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
  599: 	pp->hour   = up->hour ;
  600: 	pp->minute = up->minute ;
  601: 	pp->second = up->second ;
  602: 	pp->nsec   = up->msecond * 1000000;
  603: 
  604: 	/* 
  605: 	 * JST to UTC 
  606: 	 */
  607: 	pp->hour -= 9 ;
  608: 	if ( pp->hour < 0 ) {
  609: 		pp->hour += 24 ;
  610: 		pp->day -- ;
  611: 		if ( pp->day < 1 ) {
  612: 			pp->year -- ;
  613: 			pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
  614: 		}
  615: 	}
  616: #ifdef DEBUG
  617: 	if ( debug ) {
  618: 		printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ", 
  619: 			  up->year, up->month, up->day, up->hour,
  620: 			  up->minute, up->second, up->msecond/100 ) ;
  621: 		printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
  622: 			  pp->year, pp->day, pp->hour, pp->minute,
  623: 			  pp->second, (int)(pp->nsec/100000000) ) ;
  624: 	}
  625: #endif
  626: 
  627: 	/*
  628: 	 * Process the new sample in the median filter and determine the
  629: 	 * timecode timestamp.
  630: 	 */
  631: 
  632: 	snprintf ( sLogText, sizeof(sLogText),
  633: 		   "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
  634: 		   up->year, up->month, up->day,
  635: 		   up->hour, up->minute, up->second, up->msecond/100 ) ;
  636: 	record_clock_stats ( &peer->srcadr, sLogText ) ;
  637: 
  638: 	if ( ! refclock_process ( pp ) ) {
  639: 		refclock_report(peer, CEVNT_BADTIME);
  640: 		return ;
  641: 	}
  642: 
  643: 	pp->lastref = pp->lastrec;
  644: 	refclock_receive(peer);
  645: 
  646: }
  647: 
  648: /**************************************************************************************************/
  649: 
  650: static int
  651: jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
  652: {
  653: 
  654: 	static	char	*sFunctionName = "jjy_receive_tristate_jjy01" ;
  655: 
  656: 	struct jjyunit	    *up ;
  657: 	struct refclockproc *pp ;
  658: 	struct peer	    *peer;
  659: 
  660: 	char	*pBuf ;
  661: 	int 	iLen ;
  662: 	int 	rc ;
  663: 
  664: 	int 	bOverMidnight = 0 ;
  665: 
  666: 	char	sLogText [ MAX_LOGTEXT ], sReplyText  [ MAX_LOGTEXT ] ;
  667: 
  668: 	char	*pCmd ;
  669: 	int 	iCmdLen ;
  670: 
  671: 	/*
  672: 	 * Initialize pointers and read the timecode and timestamp
  673: 	 */
  674: 	peer = (struct peer *) rbufp->recv_srcclock ;
  675: 	pp = peer->procptr ;
  676: 	up = (struct jjyunit *) pp->unitptr ;
  677: 
  678: 	if ( up->linediscipline == LDISC_RAW ) {
  679: 		pBuf = up->rawbuf ;
  680: 		iLen = up->charcount ;
  681: 	} else {
  682: 		pBuf = pp->a_lastcode ;
  683: 		iLen = pp->lencode ;
  684: 	}
  685: 
  686: 	switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) {
  687: 
  688: 	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
  689: 
  690: 		if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) {
  691: 			up->lineerror = 1 ;
  692: 			break ;
  693: 		}
  694: 
  695: 		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year,
  696: 			      &up->month, &up->day ) ;
  697: 		if ( rc != 3 || up->year < 2000 || up->month < 1 ||
  698: 		     up->month > 12 || up->day < 1 || up->day > 31 ) {
  699: 			up->lineerror = 1 ;
  700: 			break ;
  701: 		}
  702: 
  703: 		/*** Start of modification on 2004/10/31 ***/
  704: 		/*
  705: 		 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
  706: 		 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
  707: 		 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
  708: 		 * so this driver issues the second command "stim" after the reply of the first command "date".
  709: 		 */
  710: 
  711: 		/*** 2010/11/20 ***/
  712: 		/*
  713: 		 * Codes of a next command issue are moved to the end of this function.
  714: 		 */
  715: 
  716: 		/*** End of modification ***/
  717: 
  718: 		break ;
  719: 
  720: 	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
  721: 	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
  722: 
  723: 		if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) {
  724: 			up->lineerror = 1 ;
  725: 			break ;
  726: 		}
  727: 
  728: 		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour,
  729: 			      &up->minute, &up->second ) ;
  730: 		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
  731: 		     up->second > 60 ) {
  732: 			up->lineerror = 1 ;
  733: 			break ;
  734: 		}
  735: 
  736: 		up->msecond = 0 ;
  737: 		if ( up->hour == 0 && up->minute == 0 &&
  738: 		     up->second <= 2 ) {
  739: 			/*
  740: 			 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately,
  741: 			 * and the JJY receiver replies a date and time separately.
  742: 			 * Just after midnight transitions, we ignore this time.
  743: 			 */
  744: 			bOverMidnight = 1 ;
  745: 		}
  746: 		break ;
  747: 
  748: 	case TS_JJY01_COMMAND_NUMBER_STUS :
  749: 
  750: 		if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES
  751: 		    && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES,
  752: 				TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 )
  753: 		  || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO
  754: 		    && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO,
  755: 				TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) {
  756: 			/* Good */
  757: 		} else {
  758: 			up->lineerror = 1 ;
  759: 			break ;
  760: 		}
  761: 
  762: 		break ;
  763: 
  764: 	case TS_JJY01_COMMAND_NUMBER_DCST :
  765: 
  766: 		if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID
  767: 		    && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
  768: 				TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 )
  769: 		  || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID
  770: 		    && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
  771: 				TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) {
  772: 			/* Good */
  773: 		} else {
  774: 			up->lineerror = 1 ;
  775: 			break ;
  776: 		}
  777: 
  778: 		break ;
  779: 
  780: 	default : /*  Unexpected reply */
  781: 
  782: 		up->lineerror = 1 ;
  783: 		break ;
  784: 
  785: 	}
  786: 
  787: 	/* Clockstats Log */
  788: 
  789: 	printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
  790: 	snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
  791: 		   up->linecount,
  792: 		   tristate_jjy01_command_sequence[up->linecount-1].commandLog,
  793: 		   ( up->lineerror == 0 ) 
  794: 			? ( ( bOverMidnight == 0 )
  795: 				? 'O' 
  796: 				: 'S' ) 
  797: 			: 'X',
  798: 		   sReplyText ) ;
  799: 	record_clock_stats ( &peer->srcadr, sLogText ) ;
  800: 
  801: 	/* Check before issue next command */
  802: 
  803: 	if ( up->lineerror != 0 ) {
  804: 		/* Do not issue next command */
  805: 		return 0 ;
  806: 	}
  807: 
  808: 	if ( bOverMidnight != 0 ) {
  809: 		/* Do not issue next command */
  810: 		return 0 ;
  811: 	}
  812: 
  813: 	if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) {
  814: 		/* Command sequence completed */
  815: 		return 1 ;
  816: 	}
  817: 
  818: 	/* Issue next command */
  819: 
  820: #ifdef DEBUG
  821: 	if ( debug ) {
  822: 		printf ( "%s (refclock_jjy.c) : send '%s'\n",
  823: 			sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
  824: 	}
  825: #endif
  826: 
  827: 	pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
  828: 	iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
  829: 	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
  830: 		refclock_report ( peer, CEVNT_FAULT ) ;
  831: 	}
  832: 
  833: 	return 0 ;
  834: 
  835: }
  836: 
  837: /**************************************************************************************************/
  838: 
  839: static int
  840: jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
  841: {
  842: 
  843: 	static	char	*sFunctionName = "jjy_receive_cdex_jst2000" ;
  844: 
  845: 	struct jjyunit      *up ;
  846: 	struct refclockproc *pp ;
  847: 	struct peer         *peer;
  848: 
  849: 	char	*pBuf ;
  850: 	int 	iLen ;
  851: 	int 	rc ;
  852: 
  853: 	/*
  854: 	 * Initialize pointers and read the timecode and timestamp
  855: 	 */
  856: 	peer = (struct peer *) rbufp->recv_srcclock ;
  857: 	pp = peer->procptr ;
  858: 	up = (struct jjyunit *) pp->unitptr ;
  859: 
  860: 	if ( up->linediscipline == LDISC_RAW ) {
  861: 		pBuf = up->rawbuf ;
  862: 		iLen = up->charcount ;
  863: 	} else {
  864: 		pBuf = pp->a_lastcode ;
  865: 		iLen = pp->lencode ;
  866: 	}
  867: 
  868: 	switch ( up->linecount ) {
  869: 
  870: 	case 1 : /* JYYMMDD HHMMSSS */
  871: 
  872: 		if ( iLen != 15 ) {
  873: #ifdef DEBUG
  874: 			if ( debug >= 2 ) {
  875: 				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
  876: 					 sFunctionName, iLen ) ;
  877: 			}
  878: #endif
  879: 			up->lineerror = 1 ;
  880: 			break ;
  881: 		}
  882: 		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
  883: 			      &up->year, &up->month, &up->day,
  884: 			      &up->hour, &up->minute, &up->second,
  885: 			      &up->msecond ) ;
  886: 		if ( rc != 7 || up->month < 1 || up->month > 12 ||
  887: 		     up->day < 1 || up->day > 31 || up->hour > 23 ||
  888: 		     up->minute > 59 || up->second > 60 ) {
  889: #ifdef DEBUG
  890: 			if ( debug >= 2 ) {
  891: 				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n",
  892: 					 sFunctionName, rc, up->year,
  893: 					 up->month, up->day, up->hour,
  894: 					 up->minute, up->second,
  895: 					 up->msecond ) ;
  896: 			}
  897: #endif
  898: 			up->lineerror = 1 ;
  899: 			break ;
  900: 		}
  901: 		up->year    += 2000 ;
  902: 		up->msecond *= 100 ;
  903: 		break ;
  904: 
  905: 	default : /*  Unexpected reply */
  906: 
  907: 		up->lineerror = 1 ;
  908: 		break ;
  909: 
  910: 	}
  911: 
  912: 	return 1 ;
  913: 
  914: }
  915: 
  916: /**************************************************************************************************/
  917: 
  918: static int
  919: jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
  920: {
  921: 
  922: 	static	char	*sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
  923: 
  924: 	struct jjyunit      *up ;
  925: 	struct refclockproc *pp ;
  926: 	struct peer	    *peer;
  927: 
  928: 	char	*pBuf ;
  929: 	int 	iLen ;
  930: 	int 	rc ;
  931: 	int	i, ibcc, ibcc1, ibcc2 ;
  932: 
  933: 	/*
  934: 	 * Initialize pointers and read the timecode and timestamp
  935: 	 */
  936: 	peer = (struct peer *) rbufp->recv_srcclock ;
  937: 	pp = peer->procptr ;
  938: 	up = (struct jjyunit *) pp->unitptr ;
  939: 
  940: 	if ( up->linediscipline == LDISC_RAW ) {
  941: 		pBuf = up->rawbuf ;
  942: 		iLen = up->charcount ;
  943: 	} else {
  944: 		pBuf = pp->a_lastcode ;
  945: 		iLen = pp->lencode ;
  946: 	}
  947: 
  948: 	switch ( up->linecount ) {
  949: 
  950: 	case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
  951: 
  952: 		if ( ( up->operationmode == 1 && iLen != 15 ) ||
  953: 		     ( up->operationmode == 2 && iLen != 17 ) ) {
  954: #ifdef DEBUG
  955: 			if ( debug >= 2 ) {
  956: 				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
  957: 					 sFunctionName, iLen ) ;
  958: 			}
  959: #endif
  960: 			if ( up->operationmode == 1 ) {
  961: #ifdef DEBUG
  962: 				if ( debug ) {
  963: 					printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
  964: 				}
  965: #endif
  966: 				if ( write ( pp->io.fd, "#",1 ) != 1  ) {
  967: 					refclock_report ( peer, CEVNT_FAULT ) ;
  968: 				}
  969: 			}
  970: 			up->lineerror = 1 ;
  971: 			break ;
  972: 		}
  973: 
  974: 		if ( up->operationmode == 1 ) {
  975: 
  976: 			for ( i = ibcc = 0 ; i < 13 ; i ++ )
  977: 				ibcc ^= pBuf[i] ;
  978: 			ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
  979: 			ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
  980: 			if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
  981: #ifdef DEBUG
  982: 				if ( debug >= 2 ) {
  983: 					printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n",
  984: 						 sFunctionName,
  985: 						 pBuf[13] & 0xFF,
  986: 						 pBuf[14] & 0xFF,
  987: 						 ibcc1, ibcc2 ) ;
  988: 				}
  989: #endif
  990: 				up->lineerror = 1 ;
  991: 				break ;
  992: 			}
  993: 
  994: 		}
  995: 
  996: 		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
  997: 			      &up->year, &up->month, &up->day,
  998: 			      &up->hour, &up->minute, &up->second ) ;
  999: 		if ( rc != 6 || up->month < 1 || up->month > 12 ||
 1000: 		     up->day < 1 || up->day > 31 || up->hour > 23 ||
 1001: 		     up->minute > 59 || up->second > 60 ) {
 1002: #ifdef DEBUG
 1003: 			if ( debug >= 2 ) {
 1004: 				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n",
 1005: 					 sFunctionName, rc, up->year,
 1006: 					 up->month, up->day, up->hour,
 1007: 					 up->minute, up->second ) ;
 1008: 			}
 1009: #endif
 1010: 			up->lineerror = 1 ;
 1011: 			break ;
 1012: 		}
 1013: 
 1014: 		up->year += 2000 ;
 1015: 
 1016: 		if ( up->operationmode == 2 ) {
 1017: 
 1018: 			/* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
 1019: 			up->msecond = 500 ;
 1020: 			pp->second -- ;
 1021: 			if ( pp->second < 0 ) {
 1022: 				pp->second = 59 ;
 1023: 				pp->minute -- ;
 1024: 				if ( pp->minute < 0 ) {
 1025: 					pp->minute = 59 ;
 1026: 					pp->hour -- ;
 1027: 					if ( pp->hour < 0 ) {
 1028: 						pp->hour = 23 ;
 1029: 						pp->day -- ;
 1030: 						if ( pp->day < 1 ) {
 1031: 							pp->year -- ;
 1032: 							pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
 1033: 						}
 1034: 					}
 1035: 				}
 1036: 			}
 1037: 
 1038: 			/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
 1039: #ifdef DEBUG
 1040: 			if ( debug ) {
 1041: 				printf ( "%s (refclock_jjy.c) : send '#'\n",
 1042: 					 sFunctionName ) ;
 1043: 			}
 1044: #endif
 1045: 			if ( write ( pp->io.fd, "#",1 ) != 1  ) {
 1046: 				refclock_report ( peer, CEVNT_FAULT ) ;
 1047: 			}
 1048: 
 1049: 		}
 1050: 
 1051: 		break ;
 1052: 
 1053: 	default : /*  Unexpected reply */
 1054: 
 1055: #ifdef DEBUG
 1056: 		if ( debug ) {
 1057: 			printf ( "%s (refclock_jjy.c) : send '#'\n",
 1058: 				 sFunctionName ) ;
 1059: 		}
 1060: #endif
 1061: 		if ( write ( pp->io.fd, "#",1 ) != 1  ) {
 1062: 			refclock_report ( peer, CEVNT_FAULT ) ;
 1063: 		}
 1064: 
 1065: 		up->lineerror = 1 ;
 1066: 		break ;
 1067: 
 1068: 	}
 1069: 
 1070: 	return 1 ;
 1071: 
 1072: }
 1073: 
 1074: /**************************************************************************************************/
 1075: 
 1076: static int
 1077: jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
 1078: {
 1079: 
 1080: 	static char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
 1081: 
 1082: 	struct jjyunit		*up ;
 1083: 	struct refclockproc	*pp ;
 1084: 	struct peer		*peer;
 1085: 
 1086: 	char	*pBuf ;
 1087: 	int	iLen ;
 1088: 	int	rc ;
 1089: 	char	cApostrophe, sStatus[3] ;
 1090: 	int	iWeekday ;
 1091: 
 1092: 	/*
 1093: 	* Initialize pointers and read the timecode and timestamp
 1094: 	*/
 1095: 	peer = (struct peer *) rbufp->recv_srcclock ;
 1096: 	pp = peer->procptr ;
 1097: 	up = (struct jjyunit *) pp->unitptr ;
 1098: 
 1099: 	if ( up->linediscipline == LDISC_RAW ) {
 1100: 		pBuf = up->rawbuf ;
 1101: 		iLen = up->charcount ;
 1102: 	} else {
 1103: 		pBuf = pp->a_lastcode ;
 1104: 		iLen = pp->lencode ;
 1105: 	}
 1106: 
 1107: 	/*
 1108: 	* JJY-200 sends a timestamp every second.
 1109: 	* So, a timestamp is ignored unless it is right after polled.
 1110: 	*/
 1111: 	if ( ! up->bPollFlag )
 1112: 		return 0 ;
 1113: 
 1114: 	switch ( up->linecount ) {
 1115: 
 1116: 	case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
 1117: 
 1118: 		if ( iLen != 23 ) {
 1119: #ifdef DEBUG
 1120: 			if ( debug >= 2 ) {
 1121: 				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
 1122: 					 sFunctionName, iLen ) ;
 1123: 			}
 1124: #endif
 1125: 			up->lineerror = 1 ;
 1126: 			break ;
 1127: 		}
 1128: 
 1129: 		rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
 1130: 			      &cApostrophe, sStatus, &up->year,
 1131: 			      &up->month, &up->day, &iWeekday,
 1132: 			      &up->hour, &up->minute, &up->second ) ;
 1133: 		sStatus[2] = 0 ;
 1134: 		if ( rc != 9 || cApostrophe != '\'' ||
 1135: 		     strcmp( sStatus, "OK" ) != 0 || up->month < 1 ||
 1136: 		     up->month > 12 || up->day < 1 || up->day > 31 ||
 1137: 		     iWeekday > 6 || up->hour > 23 || up->minute > 59 ||
 1138: 		     up->second > 60 ) {
 1139: #ifdef DEBUG
 1140: 			if ( debug >= 2 ) {
 1141: 				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n",
 1142: 					 sFunctionName, rc, cApostrophe,
 1143: 					 sStatus, up->year, up->month,
 1144: 					 up->day, iWeekday, up->hour,
 1145: 					 up->minute, up->second ) ;
 1146: 			}
 1147: #endif
 1148: 			up->lineerror = 1 ;
 1149: 			break ;
 1150: 		}
 1151: 
 1152: 		up->year += 2000 ;
 1153: 		up->msecond = 0 ;
 1154: 
 1155: 		break ;
 1156: 
 1157: 	default : /* Unexpected reply */
 1158: 
 1159: 		up->lineerror = 1 ;
 1160: 		break ;
 1161: 
 1162: 	}
 1163: 
 1164: 	return 1 ;
 1165: 
 1166: }
 1167: 
 1168: /**************************************************************************************************/
 1169: /*  jjy_poll - called by the transmit procedure                                                   */
 1170: /**************************************************************************************************/
 1171: static void
 1172: jjy_poll ( int unit, struct peer *peer )
 1173: {
 1174: 
 1175: 	struct jjyunit      *up;
 1176: 	struct refclockproc *pp;
 1177: 
 1178: 	pp = peer->procptr;
 1179: 	up = (struct jjyunit *) pp->unitptr ;
 1180: 
 1181: 	if ( pp->polls > 0  &&  up->linecount == 0 ) {
 1182: 		/*
 1183: 		 * No reply for last command
 1184: 		 */
 1185: 		refclock_report ( peer, CEVNT_TIMEOUT ) ;
 1186: 	}
 1187: 
 1188: #ifdef DEBUG
 1189: 	if ( debug ) {
 1190: 		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
 1191: 	}
 1192: #endif
 1193: 
 1194: 	pp->polls ++ ;
 1195: 
 1196: 	up->bPollFlag = 1 ;
 1197: 	up->linecount = 0 ;
 1198: 	up->lineerror = 0 ;
 1199: 	up->charcount = 0 ;
 1200: 
 1201: 	switch ( up->unittype ) {
 1202: 	
 1203: 	case UNITTYPE_TRISTATE_JJY01 :
 1204: 		jjy_poll_tristate_jjy01  ( unit, peer ) ;
 1205: 		break ;
 1206: 
 1207: 	case UNITTYPE_CDEX_JST2000 :
 1208: 		jjy_poll_cdex_jst2000 ( unit, peer ) ;
 1209: 		break ;
 1210: 
 1211: 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
 1212: 		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
 1213: 		break ;
 1214: 
 1215: 	case UNITTYPE_CITIZENTIC_JJY200 :
 1216: 		jjy_poll_citizentic_jjy200 ( unit, peer ) ;
 1217: 		break ;
 1218: 
 1219: 	default :
 1220: 		break ;
 1221: 
 1222: 	}
 1223: 
 1224: }
 1225: 
 1226: /**************************************************************************************************/
 1227: 
 1228: static void
 1229: jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
 1230: {
 1231: 
 1232: 	static char *sFunctionName = "jjy_poll_tristate_jjy01" ;
 1233: 
 1234: 	struct jjyunit	    *up;
 1235: 	struct refclockproc *pp;
 1236: 
 1237: 	char	*pCmd ;
 1238: 	int 	iCmdLen ;
 1239: 
 1240: 	pp = peer->procptr;
 1241: 	up = (struct jjyunit *) pp->unitptr ;
 1242: 
 1243: 	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
 1244: 		up->linecount = 2 ;
 1245: 	}
 1246: 
 1247: #ifdef DEBUG
 1248: 	if ( debug ) {
 1249: 		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
 1250: 			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
 1251: 			up->linecount ) ;
 1252: 	}
 1253: #endif
 1254: 
 1255: 	/*
 1256: 	 * Send a first command
 1257: 	 */
 1258: 
 1259: #ifdef DEBUG
 1260: 	if ( debug ) {
 1261: 		printf ( "%s (refclock_jjy.c) : send '%s'\n",
 1262: 			 sFunctionName,
 1263: 			 tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
 1264: 	}
 1265: #endif
 1266: 
 1267: 	pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
 1268: 	iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
 1269: 	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
 1270: 		refclock_report ( peer, CEVNT_FAULT ) ;
 1271: 	}
 1272: 
 1273: }
 1274: 
 1275: /**************************************************************************************************/
 1276: 
 1277: static void
 1278: jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
 1279: {
 1280: 
 1281: 	struct refclockproc *pp;
 1282: 
 1283: 	pp = peer->procptr;
 1284: 
 1285: 	/*
 1286: 	 * Send "<ENQ>1J<ETX>" command
 1287: 	 */
 1288: 
 1289: #ifdef DEBUG
 1290: 	if ( debug ) {
 1291: 		printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
 1292: 	}
 1293: #endif
 1294: 
 1295: 	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
 1296: 		refclock_report ( peer, CEVNT_FAULT ) ;
 1297: 	}
 1298: 
 1299: }
 1300: 
 1301: /**************************************************************************************************/
 1302: 
 1303: static void
 1304: jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
 1305: {
 1306: 
 1307: 	struct jjyunit      *up;
 1308: 	struct refclockproc *pp;
 1309: 
 1310: 	char	sCmd[2] ;
 1311: 
 1312: 	pp = peer->procptr;
 1313: 	up = (struct jjyunit *) pp->unitptr ;
 1314: 
 1315: 	/*
 1316: 	 * Send "T" or "C" command
 1317: 	 */
 1318: 
 1319: 	switch ( up->operationmode ) {
 1320: 	case 1 : sCmd[0] = 'T' ; break ;
 1321: 	case 2 : sCmd[0] = 'C' ; break ;
 1322: 	}
 1323: 	sCmd[1] = 0 ;
 1324: 
 1325: #ifdef DEBUG
 1326: 	if ( debug ) {
 1327: 		printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
 1328: 	}
 1329: #endif
 1330: 
 1331: 	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
 1332: 		refclock_report ( peer, CEVNT_FAULT ) ;
 1333: 	}
 1334: 
 1335: }
 1336: 
 1337: /**************************************************************************************************/
 1338: 
 1339: static void
 1340: jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
 1341: {
 1342: 
 1343: 	/* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
 1344: 
 1345: }
 1346: 
 1347: /**************************************************************************************************/
 1348: 
 1349: static void
 1350: printableString ( char *sOutput, int iOutputLen, char *sInput, int iInputLen )
 1351: {
 1352: 
 1353: 	char	*printableControlChar[] = {
 1354: 			"<NUL>", "<SOH>", "<STX>", "<ETX>",
 1355: 			"<EOT>", "<ENQ>", "<ACK>", "<BEL>",
 1356: 			"<BS>" , "<HT>" , "<LF>" , "<VT>" ,
 1357: 			"<FF>" , "<CR>" , "<SO>" , "<SI>" ,
 1358: 			"<DLE>", "<DC1>", "<DC2>", "<DC3>",
 1359: 			"<DC4>", "<NAK>", "<SYN>", "<ETB>",
 1360: 			"<CAN>", "<EM>" , "<SUB>", "<ESC>",
 1361: 			"<FS>" , "<GS>" , "<RS>" , "<US>" ,
 1362: 			" " } ;
 1363: 
 1364: 	int	i, j, n ;
 1365: 
 1366: 	for ( i = j = 0 ; i < iInputLen && j < iOutputLen ; i ++ ) {
 1367: 		if ( isprint( sInput[i] ) ) {
 1368: 			n = 1 ;
 1369: 			if ( j + 1 >= iOutputLen )
 1370: 				break ;
 1371: 			sOutput[j] = sInput[i] ;
 1372: 		} else if ( ( sInput[i] & 0xFF ) < 
 1373: 			    COUNTOF(printableControlChar) ) {
 1374: 			n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
 1375: 			if ( j + n + 1 >= iOutputLen )
 1376: 				break ;
 1377: 			strncpy( sOutput + j,
 1378: 				 printableControlChar[sInput[i] & 0xFF],
 1379: 				 (size_t)iOutputLen - j ) ;
 1380: 		} else {
 1381: 			n = 5 ;
 1382: 			if ( j + n + 1 >= iOutputLen ) break ;
 1383: 			snprintf( sOutput + j, (size_t)iOutputLen - j,
 1384: 				  "<x%X>", sInput[i] & 0xFF ) ;
 1385: 		}
 1386: 		j += n ;
 1387: 	}
 1388: 
 1389: 	sOutput[min(j, iOutputLen - 1)] = '\0' ;
 1390: 
 1391: }
 1392: 
 1393: /**************************************************************************************************/
 1394: 
 1395: #else
 1396: int refclock_jjy_bs ;
 1397: #endif /* REFCLOCK */

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