refclock_jjy.c revision 1.3
1/*	$NetBSD: refclock_jjy.c,v 1.3 2012/02/01 07:46:22 kardel Exp $	*/
2
3/*
4 * refclock_jjy - clock driver for JJY receivers
5 */
6
7/**********************************************************************/
8/*								      */
9/*  Copyright (C) 2001-2004, Takao Abe.  All rights reserved.	      */
10/*								      */
11/*  Permission to use, copy, modify, and distribute this software     */
12/*  and its documentation for any purpose is hereby granted	      */
13/*  without fee, provided that the following conditions are met:      */
14/*								      */
15/*  One retains the entire copyright notice properly, and both the    */
16/*  copyright notice and this license. in the documentation and/or    */
17/*  other materials provided with the distribution.		      */
18/*								      */
19/*  This software and the name of the author must not be used to      */
20/*  endorse or promote products derived from this software without    */
21/*  prior written permission.					      */
22/*								      */
23/*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
24/*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE	      */
25/*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A	      */
26/*  PARTICULAR PURPOSE.						      */
27/*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
28/*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
29/*  ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE	      */
30/*  GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS      */
31/*  INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     */
32/*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING	      */
33/*  NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF    */
34/*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
35/*								      */
36/*  This driver is developed in my private time, and is opened as     */
37/*  voluntary contributions for the NTP.			      */
38/*  The manufacturer of the JJY receiver has not participated in      */
39/*  a development of this driver.				      */
40/*  The manufacturer does not warrant anything about this driver,     */
41/*  and is not liable for anything about this driver.		      */
42/*								      */
43/**********************************************************************/
44/*								      */
45/*  Author     Takao Abe					      */
46/*  Email      takao_abe@xurb.jp				      */
47/*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/		      */
48/*								      */
49/*  The email address abetakao@bea.hi-ho.ne.jp is never read	      */
50/*  from 2010, because a few filtering rule are provided by the	      */
51/*  "hi-ho.ne.jp", and lots of spam mail are reached.		      */
52/*  New email address for supporting the refclock_jjy is	      */
53/*  takao_abe@xurb.jp						      */
54/*								      */
55/**********************************************************************/
56/*								      */
57/*  History							      */
58/*								      */
59/*  2001/07/15							      */
60/*    [New]    Support the Tristate Ltd. JJY receiver		      */
61/*								      */
62/*  2001/08/04							      */
63/*    [Change] Log to clockstats even if bad reply		      */
64/*    [Fix]    PRECISION = (-3) (about 100 ms)			      */
65/*    [Add]    Support the C-DEX Co.Ltd. JJY receiver		      */
66/*								      */
67/*  2001/12/04							      */
68/*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
69/*								      */
70/*  2002/07/12							      */
71/*    [Fix]    Portability for FreeBSD ( patched by the user )	      */
72/*								      */
73/*  2004/10/31							      */
74/*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
75/*	       JJY-01 ( Firmware version 2.01 )			      */
76/*	       Thanks to Andy Taki for testing under FreeBSD	      */
77/*								      */
78/*  2004/11/28							      */
79/*    [Add]    Support the Echo Keisokuki LT-2000 receiver	      */
80/*								      */
81/*  2006/11/04							      */
82/*    [Fix]    C-DEX JST2000					      */
83/*	       Thanks to Hideo Kuramatsu for the patch		      */
84/*								      */
85/*  2009/04/05							      */
86/*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver	      */
87/*								      */
88/*  2010/11/20							      */
89/*    [Change] Bug 1618 ( Harmless )				      */
90/*	       Code clean up ( Remove unreachable codes ) in	      */
91/*	       jjy_start()					      */
92/*    [Change] Change clockstats format of the Tristate JJY01/02      */
93/*	       Issues more command to get the status of the receiver  */
94/*	       when "fudge 127.127.40.X flag1 1" is specified	      */
95/*	       ( DATE,STIM -> DCST,STUS,DATE,STIM )		      */
96/*								      */
97/**********************************************************************/
98
99#ifdef HAVE_CONFIG_H
100#include <config.h>
101#endif
102
103#if defined(REFCLOCK) && defined(CLOCK_JJY)
104
105#include <stdio.h>
106#include <ctype.h>
107#include <string.h>
108#include <sys/time.h>
109#include <time.h>
110
111#include "ntpd.h"
112#include "ntp_io.h"
113#include "ntp_tty.h"
114#include "ntp_refclock.h"
115#include "ntp_calendar.h"
116#include "ntp_stdlib.h"
117
118/**********************************************************************/
119/*								      */
120/*  The Tristate Ltd. JJY receiver JJY01			      */
121/*								      */
122/*  Command	   Response		    Remarks		      */
123/*  ------------   ----------------------   ---------------------     */
124/*  dcst<CR><LF>   VALID|INVALID<CR><LF>			      */
125/*  stus<CR><LF>   ADJUSTED|UNADJUSTED<CR><LF>			      */
126/*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>			      */
127/*  time<CR><LF>   HH:MM:SS<CR><LF>				      */
128/*  stim<CR><LF>   HH:MM:SS<CR><LF>	    Reply at just second      */
129/*								      */
130/*  During synchronization after a receiver is turned on,	      */
131/*  It replies the past time from 2000/01/01 00:00:00.		      */
132/*  The function "refclock_process" checks the time and tells	      */
133/*  as an insanity time.					      */
134/*								      */
135/**********************************************************************/
136/*								      */
137/*  The C-DEX Co. Ltd. JJY receiver JST2000			      */
138/*								      */
139/*  Command	   Response		    Remarks		      */
140/*  ------------   ----------------------   ---------------------     */
141/*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>			      */
142/*								      */
143/**********************************************************************/
144/*								      */
145/*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000		      */
146/*								      */
147/*  Command        Response		    Remarks		      */
148/*  ------------   ----------------------   ---------------------     */
149/*  #					    Mode 1 (Request&Send)     */
150/*  T		   YYMMDDWHHMMSS<BCC1><BCC2><CR>		      */
151/*  C					    Mode 2 (Continuous)	      */
152/*		   YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>	      */
153/*		   <SUB>		    Second signal	      */
154/*								      */
155/**********************************************************************/
156/*								      */
157/*  The CITIZEN T.I.C CO., LTD. JJY receiver JJY200		      */
158/*								      */
159/*  Command	   Response		    Remarks		      */
160/*  ------------   ----------------------   ---------------------     */
161/*		   'XX YY/MM/DD W HH:MM:SS<CR>			      */
162/*					    XX: OK|NG|ER	      */
163/*					    W:  0(Monday)-6(Sunday)   */
164/*								      */
165/**********************************************************************/
166
167/*
168 * Interface definitions
169 */
170#define	DEVICE  	"/dev/jjy%d"	/* device name and unit */
171#define	SPEED232	B9600		/* uart speed (9600 baud) */
172#define	SPEED232_TRISTATE_JJY01		B9600   /* UART speed (9600 baud) */
173#define	SPEED232_CDEX_JST2000		B9600   /* UART speed (9600 baud) */
174#define	SPEED232_ECHOKEISOKUKI_LT2000	B9600   /* UART speed (9600 baud) */
175#define	SPEED232_CITIZENTIC_JJY200	B4800   /* UART speed (4800 baud) */
176#define	REFID   	"JJY"		/* reference ID */
177#define	DESCRIPTION	"JJY Receiver"
178#define	PRECISION	(-3)		/* precision assumed (about 100 ms) */
179
180/*
181 * JJY unit control structure
182 */
183struct jjyunit {
184	char	unittype ;	    /* UNITTYPE_XXXXXXXXXX */
185	short   operationmode ;	    /* Echo Keisokuki LT-2000 : 1 or 2 */
186	short	version ;
187	short	linediscipline ;    /* LDISC_CLK or LDISC_RAW */
188	char    bPollFlag ;	    /* Set by jjy_pool and Reset by jjy_receive */
189	int 	linecount ;
190	int 	lineerror ;
191	int 	year, month, day, hour, minute, second, msecond ;
192/* LDISC_RAW only */
193#define	MAX_LINECOUNT	8
194#define	MAX_RAWBUF   	64
195	int 	lineexpect ;
196	int 	charexpect [ MAX_LINECOUNT ] ;
197	int 	charcount ;
198	char	rawbuf [ MAX_RAWBUF ] ;
199};
200
201#define	UNITTYPE_TRISTATE_JJY01	1
202#define	UNITTYPE_CDEX_JST2000  	2
203#define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
204#define	UNITTYPE_CITIZENTIC_JJY200  	4
205
206/*
207 * Function prototypes
208 */
209static	int 	jjy_start		    (int, struct peer *);
210static	void	jjy_shutdown		    (int, struct peer *);
211static	void	jjy_poll		    (int, struct peer *);
212static	void	jjy_poll_tristate_jjy01	    (int, struct peer *);
213static	void	jjy_poll_cdex_jst2000	    (int, struct peer *);
214static	void	jjy_poll_echokeisokuki_lt2000(int, struct peer *);
215static	void	jjy_poll_citizentic_jjy200  (int, struct peer *);
216static	void	jjy_receive		    (struct recvbuf *);
217static	int	jjy_receive_tristate_jjy01  (struct recvbuf *);
218static	int	jjy_receive_cdex_jst2000    (struct recvbuf *);
219static	int	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
220static  int	jjy_receive_citizentic_jjy200 (struct recvbuf *);
221
222static	void	printableString ( char*, int, char*, int ) ;
223
224/*
225 * Transfer vector
226 */
227struct	refclock refclock_jjy = {
228	jjy_start,	/* start up driver */
229	jjy_shutdown,	/* shutdown driver */
230	jjy_poll,	/* transmit poll message */
231	noentry,	/* not used */
232	noentry,	/* not used */
233	noentry,	/* not used */
234	NOFLAGS		/* not used */
235};
236
237/*
238 * Start up driver return code
239 */
240#define	RC_START_SUCCESS	1
241#define	RC_START_ERROR		0
242
243/*
244 * Local constants definition
245 */
246
247#define	MAX_LOGTEXT	64
248
249/*
250 * Tristate JJY01/JJY02 constants definition
251 */
252
253#define	TS_JJY01_COMMAND_NUMBER_DATE	1
254#define	TS_JJY01_COMMAND_NUMBER_TIME	2
255#define	TS_JJY01_COMMAND_NUMBER_STIM	3
256#define	TS_JJY01_COMMAND_NUMBER_STUS	4
257#define	TS_JJY01_COMMAND_NUMBER_DCST	5
258
259#define	TS_JJY01_REPLY_DATE		"yyyy/mm/dd www\r\n"
260#define	TS_JJY01_REPLY_STIM		"hh:mm:ss\r\n"
261#define	TS_JJY01_REPLY_STUS_YES		"adjusted\r\n"
262#define	TS_JJY01_REPLY_STUS_NO		"unadjusted\r\n"
263#define	TS_JJY01_REPLY_DCST_VALID	"valid\r\n"
264#define	TS_JJY01_REPLY_DCST_INVALID	"invalid\r\n"
265
266#define	TS_JJY01_REPLY_LENGTH_DATE	    14	/* Length without <CR><LF> */
267#define	TS_JJY01_REPLY_LENGTH_STIM	    8	/* Length without <CR><LF> */
268#define	TS_JJY01_REPLY_LENGTH_STUS_YES	    8	/* Length without <CR><LF> */
269#define	TS_JJY01_REPLY_LENGTH_STUS_NO	    10	/* Length without <CR><LF> */
270#define	TS_JJY01_REPLY_LENGTH_DCST_VALID    5	/* Length without <CR><LF> */
271#define	TS_JJY01_REPLY_LENGTH_DCST_INVALID  7	/* Length without <CR><LF> */
272
273static  struct
274{
275	char	commandNumber ;
276	char	*commandLog ;
277	char	*command ;
278	int	commandLength ;
279} tristate_jjy01_command_sequence[] =
280{
281	/* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */
282	{ TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 },
283	/* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
284	{ TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
285	/* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
286	{ TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
287	/* stim<CR><LF> -> HH:MM:SS<CR><LF> */
288	{ TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 },
289	{ 0			      , NULL  , NULL	  , 0 }
290} ;
291
292
293/**************************************************************************************************/
294/*  jjy_start - open the devices and initialize data for processing                               */
295/**************************************************************************************************/
296static int
297jjy_start ( int unit, struct peer *peer )
298{
299
300	struct jjyunit	    *up ;
301	struct refclockproc *pp ;
302	int 	fd ;
303	char	*pDeviceName ;
304	short	iDiscipline ;
305	int 	iSpeed232 ;
306
307#ifdef DEBUG
308	if ( debug ) {
309		printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
310		printf ( DEVICE, unit ) ;
311		printf ( "\n" ) ;
312	}
313#endif
314	/*
315	 * Open serial port
316	 */
317	pDeviceName = emalloc ( strlen(DEVICE) + 10 );
318	snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ;
319
320	/*
321	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
322	 */
323	switch ( peer->ttl ) {
324	case 0 :
325	case 1 :
326		iDiscipline = LDISC_CLK ;
327		iSpeed232   = SPEED232_TRISTATE_JJY01 ;
328		break ;
329	case 2 :
330		iDiscipline = LDISC_RAW ;
331		iSpeed232   = SPEED232_CDEX_JST2000   ;
332		break ;
333	case 3 :
334		iDiscipline = LDISC_CLK ;
335		iSpeed232   = SPEED232_ECHOKEISOKUKI_LT2000 ;
336		break ;
337	case 4 :
338		iDiscipline = LDISC_CLK ;
339		iSpeed232   = SPEED232_CITIZENTIC_JJY200 ;
340		break ;
341	default :
342		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
343			  ntoa(&peer->srcadr), peer->ttl ) ;
344		free ( (void*) pDeviceName ) ;
345		return RC_START_ERROR ;
346	}
347
348	if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
349		free ( (void*) pDeviceName ) ;
350		return RC_START_ERROR ;
351	}
352	free ( (void*) pDeviceName ) ;
353
354	/*
355	 * Allocate and initialize unit structure
356	 */
357	up = emalloc (sizeof(*up));
358	memset ( up, 0, sizeof(*up) ) ;
359	up->linediscipline = iDiscipline ;
360
361	/*
362	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
363	 */
364	switch ( peer->ttl ) {
365	case 0 :
366		/*
367		 * The mode 0 is a default clock type at this time.
368		 * But this will be change to auto-detect mode in the future.
369		 */
370	case 1 :
371		up->unittype = UNITTYPE_TRISTATE_JJY01 ;
372		up->version  = 100 ;
373		/* 2010/11/20 */
374		/* Command sequence is defined by the struct tristate_jjy01_command_sequence, */
375		/* and the following 3 lines are not used in the mode LDISC_CLK. */
376		/* up->lineexpect = 2 ; */
377		/* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */
378		/* up->charexpect[1] =  8 ; */ /* HH:MM:SS<CR><LF> */
379		break ;
380	case 2 :
381		up->unittype = UNITTYPE_CDEX_JST2000 ;
382		up->lineexpect = 1 ;
383		up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
384		break ;
385	case 3 :
386		up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
387		up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
388		up->lineexpect = 1 ;
389		switch ( up->operationmode ) {
390		case 1 :
391			up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
392			break ;
393		case 2 :
394			up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
395			break ;
396		}
397		break ;
398	case 4 :
399		up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
400		up->lineexpect = 1 ;
401		up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
402		break ;
403
404	/* 2010/11/20 */
405	/* The "default:" section of this switch block is never executed,     */
406	/* because the former switch block traps the same "default:" case.    */
407	/* This "default:" section codes are removed to avoid spending time   */
408	/* in the future looking, though the codes are functionally harmless. */
409
410	}
411
412	pp = peer->procptr ;
413	pp->unitptr       = (caddr_t) up ;
414	pp->io.clock_recv = jjy_receive ;
415	pp->io.srcclock   = (caddr_t) peer ;
416	pp->io.datalen	  = 0 ;
417	pp->io.fd	  = fd ;
418	if ( ! io_addclock(&pp->io) ) {
419		close ( fd ) ;
420		pp->io.fd = -1 ;
421		free ( up ) ;
422		pp->unitptr = NULL ;
423		return RC_START_ERROR ;
424	}
425
426	/*
427	 * Initialize miscellaneous variables
428	 */
429	peer->precision = PRECISION ;
430	peer->burst	= 1 ;
431	pp->clockdesc	= DESCRIPTION ;
432	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
433
434	return RC_START_SUCCESS ;
435
436}
437
438
439/**************************************************************************************************/
440/*  jjy_shutdown - shutdown the clock                                                             */
441/**************************************************************************************************/
442static void
443jjy_shutdown ( int unit, struct peer *peer )
444{
445
446	struct jjyunit	    *up;
447	struct refclockproc *pp;
448
449	pp = peer->procptr ;
450	up = (struct jjyunit *) pp->unitptr ;
451	if ( -1 != pp->io.fd )
452		io_closeclock ( &pp->io ) ;
453	if ( NULL != up )
454		free ( up ) ;
455
456}
457
458
459/**************************************************************************************************/
460/*  jjy_receive - receive data from the serial interface                                          */
461/**************************************************************************************************/
462static void
463jjy_receive ( struct recvbuf *rbufp )
464{
465
466	struct jjyunit	    *up ;
467	struct refclockproc *pp ;
468	struct peer	    *peer;
469
470	l_fp	tRecvTimestamp;		/* arrival timestamp */
471	int 	rc ;
472	char	sLogText [ MAX_LOGTEXT ] ;
473	int 	i, bCntrlChar ;
474
475	/*
476	 * Initialize pointers and read the timecode and timestamp
477	 */
478	peer = (struct peer *) rbufp->recv_srcclock ;
479	pp = peer->procptr ;
480	up = (struct jjyunit *) pp->unitptr ;
481
482	/*
483	 * Get next input line
484	 */
485	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
486
487	if ( up->linediscipline == LDISC_RAW ) {
488		/*
489		 * The reply with <STX> and <ETX> may give a blank line
490		 */
491		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
492		/*
493		 * Copy received charaters to temporary buffer
494		 */
495		for ( i = 0 ;
496		      i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ;
497		      i ++ , up->charcount ++ ) {
498			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
499		}
500		while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
501			for ( i = 0 ; i < up->charcount - 1 ; i ++ )
502				up->rawbuf[i] = up->rawbuf[i+1] ;
503			up->charcount -- ;
504		}
505		bCntrlChar = 0 ;
506		for ( i = 0 ; i < up->charcount ; i ++ ) {
507			if ( up->rawbuf[i] < ' ' ) {
508				bCntrlChar = 1 ;
509				break ;
510			}
511		}
512		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
513			if ( bCntrlChar == 0  &&
514			     up->charcount < up->charexpect[up->linecount] )
515				return ;
516		}
517		up->rawbuf[up->charcount] = 0 ;
518	} else {
519		/*
520		 * The reply with <CR><LF> gives a blank line
521		 */
522		if ( pp->lencode == 0 ) return ;
523	}
524	/*
525	 * We get down to business
526	 */
527
528	pp->lastrec = tRecvTimestamp ;
529
530	up->linecount ++ ;
531
532	if ( up->lineerror != 0 ) return ;
533
534	switch ( up->unittype ) {
535
536	case UNITTYPE_TRISTATE_JJY01 :
537		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
538		break ;
539
540	case UNITTYPE_CDEX_JST2000 :
541		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
542		break ;
543
544	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
545		rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
546		break ;
547
548	case UNITTYPE_CITIZENTIC_JJY200 :
549		rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
550		break ;
551
552	default :
553		rc = 0 ;
554		break ;
555
556	}
557
558	if ( up->linediscipline == LDISC_RAW ) {
559		if ( up->linecount <= up->lineexpect  &&
560		     up->charcount > up->charexpect[up->linecount-1] ) {
561			for ( i = 0 ;
562			      i < up->charcount - up->charexpect[up->linecount-1] ;
563			      i ++ ) {
564				up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
565			}
566			up->charcount -= up->charexpect[up->linecount-1] ;
567		} else {
568			up->charcount = 0 ;
569		}
570	}
571
572	if ( rc == 0 )
573		return ;
574
575	up->bPollFlag = 0 ;
576
577	if ( up->lineerror != 0 ) {
578		refclock_report ( peer, CEVNT_BADREPLY ) ;
579		strncpy  ( sLogText, "BAD REPLY [",
580			   sizeof( sLogText ) ) ;
581		if ( up->linediscipline == LDISC_RAW ) {
582			strncat ( sLogText, up->rawbuf,
583				  sizeof( sLogText ) -
584				      strlen ( sLogText ) - 1 ) ;
585		} else {
586			strncat ( sLogText, pp->a_lastcode,
587				  sizeof( sLogText ) -
588				      strlen ( sLogText ) - 1 ) ;
589		}
590		sLogText[MAX_LOGTEXT-1] = 0 ;
591		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 )
592			strncat ( sLogText, "]",
593				  sizeof( sLogText ) -
594				      strlen ( sLogText ) - 1 ) ;
595		record_clock_stats ( &peer->srcadr, sLogText ) ;
596		return ;
597	}
598
599	pp->year   = up->year ;
600	pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
601	pp->hour   = up->hour ;
602	pp->minute = up->minute ;
603	pp->second = up->second ;
604	pp->nsec   = up->msecond * 1000000;
605
606	/*
607	 * JST to UTC
608	 */
609	pp->hour -= 9 ;
610	if ( pp->hour < 0 ) {
611		pp->hour += 24 ;
612		pp->day -- ;
613		if ( pp->day < 1 ) {
614			pp->year -- ;
615			pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
616		}
617	}
618#ifdef DEBUG
619	if ( debug ) {
620		printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ",
621			  up->year, up->month, up->day, up->hour,
622			  up->minute, up->second, up->msecond/100 ) ;
623		printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
624			  pp->year, pp->day, pp->hour, pp->minute,
625			  pp->second, (int)(pp->nsec/100000000) ) ;
626	}
627#endif
628
629	/*
630	 * Process the new sample in the median filter and determine the
631	 * timecode timestamp.
632	 */
633
634	snprintf ( sLogText, sizeof(sLogText),
635		   "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
636		   up->year, up->month, up->day,
637		   up->hour, up->minute, up->second, up->msecond/100 ) ;
638	record_clock_stats ( &peer->srcadr, sLogText ) ;
639
640	if ( ! refclock_process ( pp ) ) {
641		refclock_report(peer, CEVNT_BADTIME);
642		return ;
643	}
644
645	pp->lastref = pp->lastrec;
646	refclock_receive(peer);
647
648}
649
650/**************************************************************************************************/
651
652static int
653jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
654{
655
656	static	char	*sFunctionName = "jjy_receive_tristate_jjy01" ;
657
658	struct jjyunit	    *up ;
659	struct refclockproc *pp ;
660	struct peer	    *peer;
661
662	char	*pBuf ;
663	int 	iLen ;
664	int 	rc ;
665
666	int 	bOverMidnight = 0 ;
667
668	char	sLogText [ MAX_LOGTEXT ], sReplyText  [ MAX_LOGTEXT ] ;
669
670	char	*pCmd ;
671	int 	iCmdLen ;
672
673	/*
674	 * Initialize pointers and read the timecode and timestamp
675	 */
676	peer = (struct peer *) rbufp->recv_srcclock ;
677	pp = peer->procptr ;
678	up = (struct jjyunit *) pp->unitptr ;
679
680	if ( up->linediscipline == LDISC_RAW ) {
681		pBuf = up->rawbuf ;
682		iLen = up->charcount ;
683	} else {
684		pBuf = pp->a_lastcode ;
685		iLen = pp->lencode ;
686	}
687
688	switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) {
689
690	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
691
692		if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) {
693			up->lineerror = 1 ;
694			break ;
695		}
696
697		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year,
698			      &up->month, &up->day ) ;
699		if ( rc != 3 || up->year < 2000 || up->month < 1 ||
700		     up->month > 12 || up->day < 1 || up->day > 31 ) {
701			up->lineerror = 1 ;
702			break ;
703		}
704
705		/*** Start of modification on 2004/10/31 ***/
706		/*
707		 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
708		 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
709		 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
710		 * so this driver issues the second command "stim" after the reply of the first command "date".
711		 */
712
713		/*** 2010/11/20 ***/
714		/*
715		 * Codes of a next command issue are moved to the end of this function.
716		 */
717
718		/*** End of modification ***/
719
720		break ;
721
722	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
723	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
724
725		if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) {
726			up->lineerror = 1 ;
727			break ;
728		}
729
730		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour,
731			      &up->minute, &up->second ) ;
732		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
733		     up->second > 60 ) {
734			up->lineerror = 1 ;
735			break ;
736		}
737
738		up->msecond = 0 ;
739		if ( up->hour == 0 && up->minute == 0 &&
740		     up->second <= 2 ) {
741			/*
742			 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately,
743			 * and the JJY receiver replies a date and time separately.
744			 * Just after midnight transitions, we ignore this time.
745			 */
746			bOverMidnight = 1 ;
747		}
748		break ;
749
750	case TS_JJY01_COMMAND_NUMBER_STUS :
751
752		if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES
753		    && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES,
754				TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 )
755		  || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO
756		    && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO,
757				TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) {
758			/* Good */
759		} else {
760			up->lineerror = 1 ;
761			break ;
762		}
763
764		break ;
765
766	case TS_JJY01_COMMAND_NUMBER_DCST :
767
768		if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID
769		    && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
770				TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 )
771		  || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID
772		    && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
773				TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) {
774			/* Good */
775		} else {
776			up->lineerror = 1 ;
777			break ;
778		}
779
780		break ;
781
782	default : /*  Unexpected reply */
783
784		up->lineerror = 1 ;
785		break ;
786
787	}
788
789	/* Clockstats Log */
790
791	printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
792	snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
793		   up->linecount,
794		   tristate_jjy01_command_sequence[up->linecount-1].commandLog,
795		   ( up->lineerror == 0 )
796			? ( ( bOverMidnight == 0 )
797				? 'O'
798				: 'S' )
799			: 'X',
800		   sReplyText ) ;
801	record_clock_stats ( &peer->srcadr, sLogText ) ;
802
803	/* Check before issue next command */
804
805	if ( up->lineerror != 0 ) {
806		/* Do not issue next command */
807		return 0 ;
808	}
809
810	if ( bOverMidnight != 0 ) {
811		/* Do not issue next command */
812		return 0 ;
813	}
814
815	if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) {
816		/* Command sequence completed */
817		return 1 ;
818	}
819
820	/* Issue next command */
821
822#ifdef DEBUG
823	if ( debug ) {
824		printf ( "%s (refclock_jjy.c) : send '%s'\n",
825			sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
826	}
827#endif
828
829	pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
830	iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
831	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
832		refclock_report ( peer, CEVNT_FAULT ) ;
833	}
834
835	return 0 ;
836
837}
838
839/**************************************************************************************************/
840
841static int
842jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
843{
844	static	char	*sFunctionName = "jjy_receive_cdex_jst2000" ;
845
846	struct jjyunit      *up ;
847	struct refclockproc *pp ;
848	struct peer         *peer;
849
850	char	*pBuf ;
851	int 	iLen ;
852	int 	rc ;
853
854	/*
855	 * Initialize pointers and read the timecode and timestamp
856	 */
857	peer = (struct peer *) rbufp->recv_srcclock ;
858	pp = peer->procptr ;
859	up = (struct jjyunit *) pp->unitptr ;
860
861	if ( up->linediscipline == LDISC_RAW ) {
862		pBuf = up->rawbuf ;
863		iLen = up->charcount ;
864	} else {
865		pBuf = pp->a_lastcode ;
866		iLen = pp->lencode ;
867	}
868
869	switch ( up->linecount ) {
870
871	case 1 : /* JYYMMDD HHMMSSS */
872
873		if ( iLen != 15 ) {
874#ifdef DEBUG
875			if ( debug >= 2 ) {
876				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
877					 sFunctionName, iLen ) ;
878			}
879#endif
880			up->lineerror = 1 ;
881			break ;
882		}
883		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
884			      &up->year, &up->month, &up->day,
885			      &up->hour, &up->minute, &up->second,
886			      &up->msecond ) ;
887		if ( rc != 7 || up->month < 1 || up->month > 12 ||
888		     up->day < 1 || up->day > 31 || up->hour > 23 ||
889		     up->minute > 59 || up->second > 60 ) {
890#ifdef DEBUG
891			if ( debug >= 2 ) {
892				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n",
893					 sFunctionName, rc, up->year,
894					 up->month, up->day, up->hour,
895					 up->minute, up->second,
896					 up->msecond ) ;
897			}
898#endif
899			up->lineerror = 1 ;
900			break ;
901		}
902		up->year    += 2000 ;
903		up->msecond *= 100 ;
904		break ;
905
906	default : /*  Unexpected reply */
907
908		up->lineerror = 1 ;
909		break ;
910
911	}
912
913	return 1 ;
914
915}
916
917/**************************************************************************************************/
918
919static int
920jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
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", __func__ ) ;
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
1076static int
1077jjy_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/**************************************************************************************************/
1171static void
1172jjy_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
1228static void
1229jjy_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
1277static void
1278jjy_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
1303static void
1304jjy_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
1339static void
1340jjy_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
1349static void
1350printableString ( 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
1396int refclock_jjy_bs ;
1397#endif /* REFCLOCK */
1398