refclock_jjy.c revision 106163
1106163Sroberto/*
2106163Sroberto * refclock_jjy - clock driver for JJY receivers
3106163Sroberto */
4106163Sroberto
5106163Sroberto/**********************************************************************/
6106163Sroberto/*                                                                    */
7106163Sroberto/*  Copyright (C) 2001, Takao Abe.  All rights reserved.              */
8106163Sroberto/*                                                                    */
9106163Sroberto/*  Permission to use, copy, modify, and distribute this software     */
10106163Sroberto/*  and its documentation for any purpose is hereby granted           */
11106163Sroberto/*  without fee, provided that the following conditions are met:      */
12106163Sroberto/*                                                                    */
13106163Sroberto/*  One retains the entire copyright notice properly, and both the    */
14106163Sroberto/*  copyright notice and this license. in the documentation and/or    */
15106163Sroberto/*  other materials provided with the distribution.                   */
16106163Sroberto/*                                                                    */
17106163Sroberto/*  This software and the name of the author must not be used to      */
18106163Sroberto/*  endorse or promote products derived from this software without    */
19106163Sroberto/*  prior written permission.                                         */
20106163Sroberto/*                                                                    */
21106163Sroberto/*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
22106163Sroberto/*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE        */
23106163Sroberto/*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A          */
24106163Sroberto/*  PARTICULAR PURPOSE.                                               */
25106163Sroberto/*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
26106163Sroberto/*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
27106163Sroberto/*  ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE        */
28106163Sroberto/*  GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS      */
29106163Sroberto/*  INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     */
30106163Sroberto/*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING        */
31106163Sroberto/*  NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF    */
32106163Sroberto/*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
33106163Sroberto/*                                                                    */
34106163Sroberto/*  This driver is developed in my private time, and is opened as     */
35106163Sroberto/*  voluntary contributions for the NTP.                              */
36106163Sroberto/*  The manufacturer of the JJY receiver has not participated in      */
37106163Sroberto/*  a development of this driver.                                     */
38106163Sroberto/*  The manufacturer does not warrant anything about this driver,     */
39106163Sroberto/*  and is not liable for anything about this driver.                 */
40106163Sroberto/*                                                                    */
41106163Sroberto/**********************************************************************/
42106163Sroberto/*                                                                    */
43106163Sroberto/*  Author     Takao Abe                                              */
44106163Sroberto/*  Email      abetakao@bea.hi-ho.ne.jp                               */
45106163Sroberto/*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/                   */
46106163Sroberto/*                                                                    */
47106163Sroberto/**********************************************************************/
48106163Sroberto/*                                                                    */
49106163Sroberto/*  History                                                           */
50106163Sroberto/*                                                                    */
51106163Sroberto/*  2001/07/15                                                        */
52106163Sroberto/*    [New]    Support the Tristate Ltd. JJY receiver                 */
53106163Sroberto/*                                                                    */
54106163Sroberto/*  2001/08/04                                                        */
55106163Sroberto/*    [Change] Log to clockstats even if bad reply                    */
56106163Sroberto/*    [Fix]    PRECISION = (-3) (about 100 ms)                        */
57106163Sroberto/*    [Add]    Support the C-DEX Co.Ltd. JJY receiver                 */
58106163Sroberto/*  2001/12/04                                                        */
59106163Sroberto/*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
60106163Sroberto/*                                                                    */
61106163Sroberto/**********************************************************************/
62106163Sroberto
63106163Sroberto#ifdef HAVE_CONFIG_H
64106163Sroberto#include <config.h>
65106163Sroberto#endif
66106163Sroberto
67106163Sroberto#if defined(REFCLOCK) && defined(CLOCK_JJY)
68106163Sroberto
69106163Sroberto#include <stdio.h>
70106163Sroberto#include <ctype.h>
71106163Sroberto#include <string.h>
72106163Sroberto#include <sys/time.h>
73106163Sroberto#include <time.h>
74106163Sroberto
75106163Sroberto#include "ntpd.h"
76106163Sroberto#include "ntp_io.h"
77106163Sroberto#include "ntp_tty.h"
78106163Sroberto#include "ntp_refclock.h"
79106163Sroberto#include "ntp_calendar.h"
80106163Sroberto#include "ntp_stdlib.h"
81106163Sroberto
82106163Sroberto/**********************************************************************/
83106163Sroberto/*                                                                    */
84106163Sroberto/*  The Tristate Ltd. JJY receiver JJY01                              */
85106163Sroberto/*                                                                    */
86106163Sroberto/*  Command        Response                 Remarks                   */
87106163Sroberto/*  ------------   ----------------------   ---------------------     */
88106163Sroberto/*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>                             */
89106163Sroberto/*  time<CR><LF>   HH:MM:SS<CR><LF>                                   */
90106163Sroberto/*  stim<CR><LF>   HH:MM:SS<CR><LF>         Reply at just second      */
91106163Sroberto/*                                                                    */
92106163Sroberto/*  During synchronization after a receiver is turned on,             */
93106163Sroberto/*  It replies the past time from 2000/01/01 00:00:00.                */
94106163Sroberto/*  The function "refclock_process" checks the time and tells         */
95106163Sroberto/*  as an insanity time.                                              */
96106163Sroberto/*                                                                    */
97106163Sroberto/**********************************************************************/
98106163Sroberto/*                                                                    */
99106163Sroberto/*  The C-DEX Co. Ltd. JJY receiver JST2000                           */
100106163Sroberto/*                                                                    */
101106163Sroberto/*  Command        Response                 Remarks                   */
102106163Sroberto/*  ------------   ----------------------   ---------------------     */
103106163Sroberto/*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>                          */
104106163Sroberto/*                                                                    */
105106163Sroberto/**********************************************************************/
106106163Sroberto
107106163Sroberto/*
108106163Sroberto * Interface definitions
109106163Sroberto */
110106163Sroberto#define	DEVICE  	"/dev/jjy%d"    /* device name and unit */
111106163Sroberto#define	SPEED232	B9600           /* uart speed (9600 baud) */
112106163Sroberto#define	REFID   	"JJY"           /* reference ID */
113106163Sroberto#define	DESCRIPTION	"JJY Receiver"
114106163Sroberto#define	PRECISION	(-3)           /* precision assumed (about 100 ms) */
115106163Sroberto
116106163Sroberto/*
117106163Sroberto * JJY unit control structure
118106163Sroberto */
119106163Srobertostruct jjyunit {
120106163Sroberto	char	unittype ;	/* UNITTYPE_XXXXXXXXXX */
121106163Sroberto	short	version ;
122106163Sroberto	short	linediscipline ;	/* LDISC_CLK or LDISC_RAW */
123106163Sroberto	int 	linecount ;
124106163Sroberto	int 	lineerror ;
125106163Sroberto	int 	year, month, day, hour, minute, second, msecond ;
126106163Sroberto/* LDISC_RAW only */
127106163Sroberto#define	MAX_LINECOUNT	8
128106163Sroberto#define	MAX_RAWBUF   	64
129106163Sroberto	int 	lineexpect ;
130106163Sroberto	int 	charexpect [ MAX_LINECOUNT ] ;
131106163Sroberto	int 	charcount ;
132106163Sroberto	char	rawbuf [ MAX_RAWBUF ] ;
133106163Sroberto};
134106163Sroberto
135106163Sroberto#define	UNITTYPE_TRISTATE_JJY01	1
136106163Sroberto#define	UNITTYPE_CDEX_JST2000  	2
137106163Sroberto
138106163Sroberto/*
139106163Sroberto * Function prototypes
140106163Sroberto */
141106163Srobertostatic	int 	jjy_start                   P((int, struct peer *));
142106163Srobertostatic	void	jjy_shutdown                P((int, struct peer *));
143106163Srobertostatic	void	jjy_poll                    P((int, struct peer *));
144106163Srobertostatic	void	jjy_poll_tristate_jjy01     P((int, struct peer *));
145106163Srobertostatic	void	jjy_poll_cdex_jst2000       P((int, struct peer *));
146106163Srobertostatic	void	jjy_receive                 P((struct recvbuf *));
147106163Srobertostatic	int 	jjy_receive_tristate_jjy01  P((struct recvbuf *));
148106163Srobertostatic	int 	jjy_receive_cdex_jst2000    P((struct recvbuf *));
149106163Sroberto
150106163Sroberto/*
151106163Sroberto * Transfer vector
152106163Sroberto */
153106163Srobertostruct	refclock refclock_jjy = {
154106163Sroberto	jjy_start,      /* start up driver */
155106163Sroberto	jjy_shutdown,   /* shutdown driver */
156106163Sroberto	jjy_poll,       /* transmit poll message */
157106163Sroberto	noentry,        /* not used */
158106163Sroberto	noentry,        /* not used */
159106163Sroberto	noentry,        /* not used */
160106163Sroberto	NOFLAGS         /* not used */
161106163Sroberto};
162106163Sroberto
163106163Sroberto/*
164106163Sroberto * Start up driver return code
165106163Sroberto */
166106163Sroberto#define	RC_START_SUCCESS	1
167106163Sroberto#define	RC_START_ERROR  	0
168106163Sroberto
169106163Sroberto/*
170106163Sroberto * Local constants definition
171106163Sroberto */
172106163Sroberto
173106163Sroberto#define	MAX_LOGTEXT	64
174106163Sroberto
175106163Sroberto
176106163Sroberto/**************************************************************************************************/
177106163Sroberto/*  jjy_start - open the devices and initialize data for processing                               */
178106163Sroberto/**************************************************************************************************/
179106163Srobertostatic int
180106163Srobertojjy_start ( int unit, struct peer *peer )
181106163Sroberto{
182106163Sroberto
183106163Sroberto	struct jjyunit      *up ;
184106163Sroberto	struct refclockproc *pp ;
185106163Sroberto	int 	fd ;
186106163Sroberto	char	*pDeviceName ;
187106163Sroberto	short	iDiscipline ;
188106163Sroberto
189106163Sroberto#ifdef DEBUG
190106163Sroberto	if ( debug ) {
191106163Sroberto		printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttlmax ) ;
192106163Sroberto		printf ( DEVICE, unit ) ;
193106163Sroberto		printf ( "\n" ) ;
194106163Sroberto	}
195106163Sroberto#endif
196106163Sroberto	/*
197106163Sroberto	 * Open serial port
198106163Sroberto	 */
199106163Sroberto	if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
200106163Sroberto		return RC_START_ERROR ;
201106163Sroberto	}
202106163Sroberto	sprintf ( pDeviceName, DEVICE, unit ) ;
203106163Sroberto
204106163Sroberto	/*
205106163Sroberto	 * peer->ttlmax is a mode number specified by "127.127.40.X mode N" in the ntp.conf
206106163Sroberto	 */
207106163Sroberto	switch ( peer->ttlmax ) {
208106163Sroberto	case 0 :
209106163Sroberto	case 1 : iDiscipline = LDISC_CLK ; break ;
210106163Sroberto	case 2 : iDiscipline = LDISC_RAW ; break ;
211106163Sroberto	default :
212106163Sroberto		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
213106163Sroberto		          ntoa(&peer->srcadr), peer->ttlmax ) ;
214106163Sroberto		free ( (void*) pDeviceName ) ;
215106163Sroberto		return RC_START_ERROR ;
216106163Sroberto	}
217106163Sroberto
218106163Sroberto	if ( ! ( fd = refclock_open ( pDeviceName, SPEED232, iDiscipline ) ) ) {
219106163Sroberto		free ( (void*) pDeviceName ) ;
220106163Sroberto		return RC_START_ERROR ;
221106163Sroberto	}
222106163Sroberto	free ( (void*) pDeviceName ) ;
223106163Sroberto
224106163Sroberto	/*
225106163Sroberto	 * Allocate and initialize unit structure
226106163Sroberto	 */
227106163Sroberto	if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
228106163Sroberto		close ( fd ) ;
229106163Sroberto		return RC_START_ERROR ;
230106163Sroberto	}
231106163Sroberto
232106163Sroberto	memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
233106163Sroberto	up->linediscipline = iDiscipline ;
234106163Sroberto
235106163Sroberto	/*
236106163Sroberto	 * peer->ttlmax is a mode number specified by "127.127.40.X mode N" in the ntp.conf
237106163Sroberto	 */
238106163Sroberto	switch ( peer->ttlmax ) {
239106163Sroberto	case 0 :
240106163Sroberto		/*
241106163Sroberto		 * The mode 0 is a default clock type at this time.
242106163Sroberto		 * But this will be change to auto-detect mode in the future.
243106163Sroberto		 */
244106163Sroberto	case 1 :
245106163Sroberto		up->unittype = UNITTYPE_TRISTATE_JJY01 ;
246106163Sroberto		up->version  = 100 ;
247106163Sroberto		up->lineexpect = 2 ;
248106163Sroberto		up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
249106163Sroberto		up->charexpect[1] =  8 ; /* HH:MM:SS<CR><LF> */
250106163Sroberto		break ;
251106163Sroberto	case 2 :
252106163Sroberto		up->unittype = UNITTYPE_CDEX_JST2000 ;
253106163Sroberto		up->lineexpect = 1 ;
254106163Sroberto		up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
255106163Sroberto		break ;
256106163Sroberto	default :
257106163Sroberto		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
258106163Sroberto		          ntoa(&peer->srcadr), peer->ttlmax ) ;
259106163Sroberto		close ( fd ) ;
260106163Sroberto		free ( (void*) up ) ;
261106163Sroberto		return RC_START_ERROR ;
262106163Sroberto	}
263106163Sroberto
264106163Sroberto	pp = peer->procptr ;
265106163Sroberto	pp->unitptr       = (caddr_t) up ;
266106163Sroberto	pp->io.clock_recv = jjy_receive ;
267106163Sroberto	pp->io.srcclock   = (caddr_t) peer ;
268106163Sroberto	pp->io.datalen    = 0 ;
269106163Sroberto	pp->io.fd         = fd ;
270106163Sroberto	if ( ! io_addclock(&pp->io) ) {
271106163Sroberto		close ( fd ) ;
272106163Sroberto		free ( (void*) up ) ;
273106163Sroberto		return RC_START_ERROR ;
274106163Sroberto	}
275106163Sroberto
276106163Sroberto	/*
277106163Sroberto	 * Initialize miscellaneous variables
278106163Sroberto	 */
279106163Sroberto	peer->precision = PRECISION ;
280106163Sroberto	peer->burst     = 1 ;
281106163Sroberto	pp->clockdesc   = DESCRIPTION ;
282106163Sroberto	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
283106163Sroberto
284106163Sroberto	return RC_START_SUCCESS ;
285106163Sroberto
286106163Sroberto}
287106163Sroberto
288106163Sroberto
289106163Sroberto/**************************************************************************************************/
290106163Sroberto/*  jjy_shutdown - shutdown the clock                                                             */
291106163Sroberto/**************************************************************************************************/
292106163Srobertostatic void
293106163Srobertojjy_shutdown ( int unit, struct peer *peer )
294106163Sroberto{
295106163Sroberto
296106163Sroberto	struct jjyunit      *up;
297106163Sroberto	struct refclockproc *pp;
298106163Sroberto
299106163Sroberto	pp = peer->procptr ;
300106163Sroberto	up = (struct jjyunit *) pp->unitptr ;
301106163Sroberto	io_closeclock ( &pp->io ) ;
302106163Sroberto	free ( (void*) up ) ;
303106163Sroberto
304106163Sroberto}
305106163Sroberto
306106163Sroberto
307106163Sroberto/**************************************************************************************************/
308106163Sroberto/*  jjy_receive - receive data from the serial interface                                          */
309106163Sroberto/**************************************************************************************************/
310106163Srobertostatic void
311106163Srobertojjy_receive ( struct recvbuf *rbufp )
312106163Sroberto{
313106163Sroberto
314106163Sroberto	struct jjyunit      *up ;
315106163Sroberto	struct refclockproc *pp ;
316106163Sroberto	struct peer         *peer;
317106163Sroberto
318106163Sroberto	l_fp	tRecvTimestamp;		/* arrival timestamp */
319106163Sroberto	int 	rc ;
320106163Sroberto	char	sLogText [ MAX_LOGTEXT ] ;
321106163Sroberto	int 	i, bCntrlChar ;
322106163Sroberto
323106163Sroberto	/*
324106163Sroberto	 * Initialize pointers and read the timecode and timestamp
325106163Sroberto	 */
326106163Sroberto	peer = (struct peer *) rbufp->recv_srcclock ;
327106163Sroberto	pp = peer->procptr ;
328106163Sroberto	up = (struct jjyunit *) pp->unitptr ;
329106163Sroberto
330106163Sroberto	/*
331106163Sroberto	 * Get next input line
332106163Sroberto	 */
333106163Sroberto	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
334106163Sroberto
335106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
336106163Sroberto		/*
337106163Sroberto		 * The reply with <STX> and <ETX> may give a blank line
338106163Sroberto		 */
339106163Sroberto		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
340106163Sroberto		/*
341106163Sroberto		 * Copy received charaters to temporary buffer
342106163Sroberto		 */
343106163Sroberto		for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
344106163Sroberto			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
345106163Sroberto		}
346106163Sroberto		while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
347106163Sroberto			for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
348106163Sroberto			up->charcount -- ;
349106163Sroberto		}
350106163Sroberto		bCntrlChar = 0 ;
351106163Sroberto		for ( i = 0 ; i < up->charcount ; i ++ ) {
352106163Sroberto			if ( up->rawbuf[i] < ' ' ) {
353106163Sroberto				bCntrlChar = 1 ;
354106163Sroberto				break ;
355106163Sroberto			}
356106163Sroberto		}
357106163Sroberto		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
358106163Sroberto			if ( bCntrlChar == 0  &&  up->charcount < up->charexpect[up->linecount] ) return ;
359106163Sroberto		}
360106163Sroberto		up->rawbuf[up->charcount] = 0 ;
361106163Sroberto	} else {
362106163Sroberto		/*
363106163Sroberto		 * The reply with <CR><LF> gives a blank line
364106163Sroberto		 */
365106163Sroberto		if ( pp->lencode == 0 ) return ;
366106163Sroberto	}
367106163Sroberto	/*
368106163Sroberto	 * We get down to business
369106163Sroberto	 */
370106163Sroberto
371106163Sroberto	pp->lastrec = tRecvTimestamp ;
372106163Sroberto
373106163Sroberto	up->linecount ++ ;
374106163Sroberto
375106163Sroberto	if ( up->lineerror != 0 ) return ;
376106163Sroberto
377106163Sroberto	switch ( up->unittype ) {
378106163Sroberto
379106163Sroberto	case UNITTYPE_TRISTATE_JJY01 :
380106163Sroberto		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
381106163Sroberto		break ;
382106163Sroberto
383106163Sroberto	case UNITTYPE_CDEX_JST2000 :
384106163Sroberto		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
385106163Sroberto		break ;
386106163Sroberto
387106163Sroberto	default :
388106163Sroberto		rc = 0 ;
389106163Sroberto		break ;
390106163Sroberto
391106163Sroberto	}
392106163Sroberto
393106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
394106163Sroberto		if ( up->linecount <= up->lineexpect  &&  up->charcount > up->charexpect[up->linecount-1] ) {
395106163Sroberto			for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
396106163Sroberto				up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
397106163Sroberto			}
398106163Sroberto			up->charcount -= up->charexpect[up->linecount-1] ;
399106163Sroberto		} else {
400106163Sroberto			up->charcount = 0 ;
401106163Sroberto		}
402106163Sroberto	}
403106163Sroberto
404106163Sroberto	if ( rc == 0 ) return ;
405106163Sroberto
406106163Sroberto	if ( up->lineerror != 0 ) {
407106163Sroberto		refclock_report ( peer, CEVNT_BADREPLY ) ;
408106163Sroberto		strcpy  ( sLogText, "BAD REPLY [" ) ;
409106163Sroberto		if ( up->linediscipline == LDISC_RAW ) {
410106163Sroberto			strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
411106163Sroberto		} else {
412106163Sroberto			strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
413106163Sroberto		}
414106163Sroberto		sLogText[MAX_LOGTEXT-1] = 0 ;
415106163Sroberto		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
416106163Sroberto		record_clock_stats ( &peer->srcadr, sLogText ) ;
417106163Sroberto		return ;
418106163Sroberto	}
419106163Sroberto
420106163Sroberto	pp->year   = up->year ;
421106163Sroberto	pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
422106163Sroberto	pp->hour   = up->hour ;
423106163Sroberto	pp->minute = up->minute ;
424106163Sroberto	pp->second = up->second ;
425106163Sroberto	pp->msec   = up->msecond ;
426106163Sroberto	pp->usec   = 0;
427106163Sroberto
428106163Sroberto	/*
429106163Sroberto	 * JST to UTC
430106163Sroberto	 */
431106163Sroberto	pp->hour -= 9 ;
432106163Sroberto	if ( pp->hour < 0 ) {
433106163Sroberto		pp->hour += 24 ;
434106163Sroberto		pp->day -- ;
435106163Sroberto		if ( pp->day < 1 ) {
436106163Sroberto			pp->year -- ;
437106163Sroberto			pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
438106163Sroberto		}
439106163Sroberto	}
440106163Sroberto#ifdef DEBUG
441106163Sroberto	if ( debug ) {
442106163Sroberto		printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d JST   ",
443106163Sroberto		          up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
444106163Sroberto		printf ( "( %04d/%03d %02d:%02d:%02d UTC )\n",
445106163Sroberto		          pp->year, pp->day, pp->hour, pp->minute, pp->second ) ;
446106163Sroberto	}
447106163Sroberto#endif
448106163Sroberto
449106163Sroberto	/*
450106163Sroberto	 * Process the new sample in the median filter and determine the
451106163Sroberto	 * timecode timestamp.
452106163Sroberto	 */
453106163Sroberto	if ( ! refclock_process ( pp ) ) {
454106163Sroberto		refclock_report(peer, CEVNT_BADTIME);
455106163Sroberto		sprintf ( sLogText, "BAD TIME %04d/%02d/%02d %02d:%02d:%02d JST",
456106163Sroberto		          up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
457106163Sroberto		record_clock_stats ( &peer->srcadr, sLogText ) ;
458106163Sroberto		return ;
459106163Sroberto	}
460106163Sroberto
461106163Sroberto	sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d JST",
462106163Sroberto	          up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
463106163Sroberto	record_clock_stats ( &peer->srcadr, sLogText ) ;
464106163Sroberto
465106163Sroberto	refclock_receive(peer);
466106163Sroberto
467106163Sroberto}
468106163Sroberto
469106163Sroberto/**************************************************************************************************/
470106163Sroberto
471106163Srobertostatic int
472106163Srobertojjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
473106163Sroberto{
474106163Sroberto
475106163Sroberto	struct jjyunit      *up ;
476106163Sroberto	struct refclockproc *pp ;
477106163Sroberto	struct peer         *peer;
478106163Sroberto
479106163Sroberto	char	*pBuf ;
480106163Sroberto	int 	iLen ;
481106163Sroberto	int 	rc ;
482106163Sroberto
483106163Sroberto	/*
484106163Sroberto	 * Initialize pointers and read the timecode and timestamp
485106163Sroberto	 */
486106163Sroberto	peer = (struct peer *) rbufp->recv_srcclock ;
487106163Sroberto	pp = peer->procptr ;
488106163Sroberto	up = (struct jjyunit *) pp->unitptr ;
489106163Sroberto
490106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
491106163Sroberto		pBuf = up->rawbuf ;
492106163Sroberto		iLen = up->charcount ;
493106163Sroberto	} else {
494106163Sroberto	    pBuf = pp->a_lastcode ;
495106163Sroberto	    iLen = pp->lencode ;
496106163Sroberto	}
497106163Sroberto
498106163Sroberto	switch ( up->linecount ) {
499106163Sroberto
500106163Sroberto	case 1 : /* YYYY/MM/DD */
501106163Sroberto
502106163Sroberto		if ( iLen < 10 ) {
503106163Sroberto			up->lineerror = 1 ;
504106163Sroberto			break ;
505106163Sroberto		}
506106163Sroberto		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
507106163Sroberto		if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
508106163Sroberto			up->lineerror = 1 ;
509106163Sroberto			break ;
510106163Sroberto		}
511106163Sroberto		return 0 ;
512106163Sroberto
513106163Sroberto	case 2 : /* HH:MM:SS */
514106163Sroberto
515106163Sroberto		if ( iLen < 8 ) {
516106163Sroberto			up->lineerror = 1 ;
517106163Sroberto			break ;
518106163Sroberto		}
519106163Sroberto		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
520106163Sroberto		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
521106163Sroberto			up->lineerror = 1 ;
522106163Sroberto			break ;
523106163Sroberto		}
524106163Sroberto		up->msecond = 0 ;
525106163Sroberto		if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
526106163Sroberto			/*
527106163Sroberto			 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
528106163Sroberto			 * But the JJY receiver replies a date and time separately.
529106163Sroberto			 * Just after midnight transtions, we ignore this time.
530106163Sroberto			 */
531106163Sroberto			return 0 ;
532106163Sroberto		}
533106163Sroberto		break ;
534106163Sroberto
535106163Sroberto	default : /*  Unexpected reply */
536106163Sroberto
537106163Sroberto		up->lineerror = 1 ;
538106163Sroberto		break ;
539106163Sroberto
540106163Sroberto	}
541106163Sroberto
542106163Sroberto	return 1 ;
543106163Sroberto
544106163Sroberto}
545106163Sroberto
546106163Sroberto/**************************************************************************************************/
547106163Sroberto
548106163Srobertostatic int
549106163Srobertojjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
550106163Sroberto{
551106163Sroberto
552106163Sroberto	struct jjyunit      *up ;
553106163Sroberto	struct refclockproc *pp ;
554106163Sroberto	struct peer         *peer;
555106163Sroberto
556106163Sroberto	char	*pBuf ;
557106163Sroberto	int 	iLen ;
558106163Sroberto	int 	rc ;
559106163Sroberto
560106163Sroberto	/*
561106163Sroberto	 * Initialize pointers and read the timecode and timestamp
562106163Sroberto	 */
563106163Sroberto	peer = (struct peer *) rbufp->recv_srcclock ;
564106163Sroberto	pp = peer->procptr ;
565106163Sroberto	up = (struct jjyunit *) pp->unitptr ;
566106163Sroberto
567106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
568106163Sroberto		pBuf = up->rawbuf ;
569106163Sroberto		iLen = up->charcount ;
570106163Sroberto	} else {
571106163Sroberto	    pBuf = pp->a_lastcode ;
572106163Sroberto	    iLen = pp->lencode ;
573106163Sroberto	}
574106163Sroberto
575106163Sroberto	switch ( up->linecount ) {
576106163Sroberto
577106163Sroberto	case 1 : /* JYYMMDD HHMMSSS */
578106163Sroberto
579106163Sroberto		if ( iLen < 15 ) {
580106163Sroberto			up->lineerror = 1 ;
581106163Sroberto			break ;
582106163Sroberto		}
583106163Sroberto		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
584106163Sroberto		              &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
585106163Sroberto		if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
586106163Sroberto		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
587106163Sroberto			up->lineerror = 1 ;
588106163Sroberto			break ;
589106163Sroberto		}
590106163Sroberto		up->year    += 2000 ;
591106163Sroberto		up->msecond *= 100 ;
592106163Sroberto		break ;
593106163Sroberto
594106163Sroberto	default : /*  Unexpected reply */
595106163Sroberto
596106163Sroberto		up->lineerror = 1 ;
597106163Sroberto		break ;
598106163Sroberto
599106163Sroberto	}
600106163Sroberto
601106163Sroberto	return 1 ;
602106163Sroberto
603106163Sroberto}
604106163Sroberto
605106163Sroberto/**************************************************************************************************/
606106163Sroberto/*  jjy_poll - called by the transmit procedure                                                   */
607106163Sroberto/**************************************************************************************************/
608106163Srobertostatic void
609106163Srobertojjy_poll ( int unit, struct peer *peer )
610106163Sroberto{
611106163Sroberto
612106163Sroberto	struct jjyunit      *up;
613106163Sroberto	struct refclockproc *pp;
614106163Sroberto
615106163Sroberto	pp = peer->procptr;
616106163Sroberto	up = (struct jjyunit *) pp->unitptr ;
617106163Sroberto
618106163Sroberto	if ( pp->polls > 0  &&  up->linecount == 0 ) {
619106163Sroberto		/*
620106163Sroberto		 * No reply for last command
621106163Sroberto		 */
622106163Sroberto		refclock_report ( peer, CEVNT_TIMEOUT ) ;
623106163Sroberto	}
624106163Sroberto
625106163Sroberto#ifdef DEBUG
626106163Sroberto	if ( debug ) {
627106163Sroberto		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
628106163Sroberto	}
629106163Sroberto#endif
630106163Sroberto
631106163Sroberto	pp->polls ++ ;
632106163Sroberto
633106163Sroberto	up->linecount = 0 ;
634106163Sroberto	up->lineerror = 0 ;
635106163Sroberto	up->charcount = 0 ;
636106163Sroberto
637106163Sroberto	switch ( up->unittype ) {
638106163Sroberto
639106163Sroberto	case UNITTYPE_TRISTATE_JJY01 :
640106163Sroberto		jjy_poll_tristate_jjy01  ( unit, peer ) ;
641106163Sroberto		break ;
642106163Sroberto
643106163Sroberto	case UNITTYPE_CDEX_JST2000 :
644106163Sroberto		jjy_poll_cdex_jst2000 ( unit, peer ) ;
645106163Sroberto		break ;
646106163Sroberto
647106163Sroberto	default :
648106163Sroberto		break ;
649106163Sroberto
650106163Sroberto	}
651106163Sroberto
652106163Sroberto}
653106163Sroberto
654106163Sroberto/**************************************************************************************************/
655106163Sroberto
656106163Srobertostatic void
657106163Srobertojjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
658106163Sroberto{
659106163Sroberto
660106163Sroberto	struct jjyunit      *up;
661106163Sroberto	struct refclockproc *pp;
662106163Sroberto
663106163Sroberto	pp = peer->procptr;
664106163Sroberto	up = (struct jjyunit *) pp->unitptr ;
665106163Sroberto
666106163Sroberto	/*
667106163Sroberto	 * Send "date<CR><LF>" command
668106163Sroberto	 */
669106163Sroberto
670106163Sroberto	if ( write ( pp->io.fd, "date\r\n",6 ) != 6  ) {
671106163Sroberto		refclock_report ( peer, CEVNT_FAULT ) ;
672106163Sroberto	}
673106163Sroberto
674106163Sroberto	/*
675106163Sroberto	 * Send "stim<CR><LF>" or "time<CR><LF>" command
676106163Sroberto	 */
677106163Sroberto
678106163Sroberto	if ( up->version >= 100 ) {
679106163Sroberto		if ( write ( pp->io.fd, "stim\r\n",6 ) != 6  ) {
680106163Sroberto			refclock_report ( peer, CEVNT_FAULT ) ;
681106163Sroberto		}
682106163Sroberto	} else {
683106163Sroberto		if ( write ( pp->io.fd, "time\r\n",6 ) != 6  ) {
684106163Sroberto			refclock_report ( peer, CEVNT_FAULT ) ;
685106163Sroberto		}
686106163Sroberto	}
687106163Sroberto
688106163Sroberto}
689106163Sroberto
690106163Sroberto/**************************************************************************************************/
691106163Sroberto
692106163Srobertostatic void
693106163Srobertojjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
694106163Sroberto{
695106163Sroberto
696106163Sroberto	struct refclockproc *pp;
697106163Sroberto
698106163Sroberto	pp = peer->procptr;
699106163Sroberto
700106163Sroberto	/*
701106163Sroberto	 * Send "<ENQ>1J<ETX>" command
702106163Sroberto	 */
703106163Sroberto
704106163Sroberto	if ( write ( pp->io.fd, "\x051J\x03", 4 ) != 4  ) {
705106163Sroberto		refclock_report ( peer, CEVNT_FAULT ) ;
706106163Sroberto	}
707106163Sroberto
708106163Sroberto}
709106163Sroberto
710106163Sroberto#else
711106163Srobertoint refclock_jjy_bs ;
712106163Sroberto#endif /* REFCLOCK */
713