Annotation of embedaddon/ntp/ntpd/refclock_jjy.c, revision 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>