reading time-of-day from an HP/Symmetricom Z3805A GPS Disciplined Oscillator/Clock

http://i.ebayimg.com/00/s/NjU4WDgwMA==/z/w1YAAOxyc2pTbXcU/$_1.JPG

Port2 of this GPS clock is specific to just this model and gives a 16 byte pulse once every other second with Time-of-Day in a binary format.

The data is shown in Hex:

00 09 01 07 03 01 04 04 00 02 03 01 03 00 00 0D

All numerical data is transmitted as a single byte per digit, i.e. digit 9 is transmitted as 09 Hex.

Bytes 1-2 are two least significant digits of the Year (00 09) 2009.

Bytes 3-5 are the numerical Day of the Year (01 07 03) or day 173 (June 22). Zero starts as Jan 1

Bytes 6-7 are the Hour (01 04), hour 14 or 2PM.

Bytes 8-9 are the Minute (04 00), minute 40.

Bytes 10-11 are the Second (02 03), second 23.

Bytes 12-13 are the Accumulated Leap Seconds (01 03), 13 leap seconds.

Bytes 14-15 SmartClock Mode or Status: 01 00: Power-Up Mode, 10 00: Holdover Mode, 00 00: GPS Lock Mode

Byte 16 is a Carriage Return (0D).

Under the example above, the Date and Time is June 22, 2009 (day 173) at 14:40:23, and no Holdover. On the Port2 serial interface, the serial port parameters are fixed at 9600, N, 8, 1 and cannot be changed. Although the Port2 connector is wired for Receive Data (pin 3) it does not appear that the GPS Receiver will accept any commands. All SCPI [L1 ] commands must be issued over the Port1 serial interface connector.

When the last byte (0D) is received, sync should happen then which lines-up with Tcl's trigger for a readable event quite well. This point in time is 37mS after the PPS pulse it represents.

The test script prints this every 2 seconds

Wed Sep 30 07:51:33 PDT 2015: GPS Locked
Wed Sep 30 07:51:35 PDT 2015: GPS Locked
Wed Sep 30 07:51:37 PDT 2015: GPS Locked
Wed Sep 30 07:51:39 PDT 2015: GPS Locked
Wed Sep 30 07:51:41 PDT 2015: GPS Locked
Wed Sep 30 07:51:43 PDT 2015: GPS Locked
Wed Sep 30 07:51:45 PDT 2015: GPS Locked
Wed Sep 30 07:51:47 PDT 2015: GPS Locked
set serial [open /dev/ttyUSB0 r+]
fconfigure $serial -mode "9600,n,8,1" -handshake none -blocking 0 \
        -buffering line -translation cr
fileevent $serial readable [list serial_receiver $serial]

proc serial_receiver { chan } {
    set data [gets $chan]
    if {![string length $data]} {
        if {[eof $chan]} {
            # get everything left
            set data [read $chan]
            puts stderr "Closing $chan"
            catch {close $chan}
        } else {
            return
        }
    }
    puts [translate $data]
 }


proc translate {bytes} {
    # decode the 15 byte packet
    binary scan $bytes {c2c3c2c2c2c2c2} year doy hr min sec lsec mode

    # collapse the lists into integers
    foreach var {year doy hr min sec lsec mode} {
        set $var [expr {[join [set $var] ""]}]
    }

    # day-of-year starts at zero, but Tcl wants one
    set doy [expr {$doy + 1}]

    # convert to UNIX time seconds.  Make sure the radio is set
    # not to convert timezone using :PTIME:TZONE 0,0 on port1
    set seconds [clock scan \
        "$year $doy $hr $min $sec" -format {%y %j %H %M %S} -gmt 1]

    # subtract leap seconds
    set seconds [expr {$seconds - $lsec}]

    switch -- $mode {
        0 {set state "GPS Locked"}
        10 {set state "Power-Up"}
        100 {set state "Holdover"}
    }

    return "[clock format $seconds]: $state"
}