Annotation of embedaddon/ntp/ntpd/refclock_jjy.c, revision 1.1.1.1

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

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