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