NTP ( the timekeeping daemon ) does not like devices that are not present at startup or go away on occasion like a detachable GPS device.
This is unix / _linux_ centric.
Your ntp configuration should contain something like:
# basic nmea source, mode: listen to GPRMC sentence, 9600baud ( in my case a sure electronics gps eval board ) : server 127.127.20.1 mode 17 fudge 127.127.20.1 flag1 0 flag2 0 flag3 0 flag4 0 time1 0.7800
with time1 being an adjustable value depending on what sentences the GPS outputs and your application specific delays.
All examples create a pty and link it to the expected gps device entry ( /dev/gps1 ) and handle disconnects / reconnects on that side gracefully.
The first script then just connects to a usb tty device and pushes selected sentences to the pty side, start this in boot up before rcntp runs:
#!/usr/bin/tclsh
package require Expect
package require udp
set ::Stat(pty,spid) {}
set ::Stat(gps,path) "/dev/gps1"
proc respawn_pty {} {
set spid $::Stat(pty,spid)
if {$spid != "" } {
close -i $spid -slave
wait
}
catch { puts stderr exist:[file exists $::Stat(gps,path)] }
catch { puts stderr type_:[file type $::Stat(gps,path)] }
# if { [file exists $::Stat(gps,path)] }
catch {
if {[file type $::Stat(gps,path)] == "link" } {
puts stderr "deleting existing link: $::Stat(gps,path)"
file delete $::Stat(gps,path)
}
} cerr; puts stderr cerr:$cerr
spawn -pty
set ::Stat(pty,spid) [ set spid $spawn_id ]
set ::Stat(pty,slave,name) $spawn_out(slave,name)
set ::Stat(pty,slave,fd) $spawn_out(slave,fd)
file link -symbolic $::Stat(gps,path) $::Stat(pty,slave,name)
expect_background -i $::Stat(pty,spid) \
-re "AT.*?\[\r\n\]{1,2}" {
exp_send -i $::Stat(pty,spid) "OK\r"
puts stderr "AT sentence, OK sent"
} \004 {
puts stderr "$::Stat(pty,slave,name) ^D, reopen"
# respawn_pty
} eof {
puts stderr "$::Stat(pty,slave,name) EOF, reopen"
# respawn_pty
}
puts stderr "$::Stat(pty,slave,name) linked to $$::Stat(gps,path), open"
parray ::Stat
return $::Stat(pty,slave,name)
}
respawn_pty
set fd [ open /dev/ttyUSB0 {RDWR NONBLOCK} ]
fconfigure $fd \
-encoding binary -translation binary \
-mode 9600,n,8,1 -handshake none
spawn -open $fd
set gps_spid $spawn_id
log_user 0
expect -i $gps_spid \
-re {(\$GPGGA.*?)\[\r\]} {
set sentence $expect_out(1,string)
exp_send -i $::Stat(pty,spid) $sentence\r
puts stderr 1:$sentence
exp_continue
} -re {(\$GPGGA.*?\*[[:xdigit:]]{2})[\r]} {
set sentence $expect_out(1,string)
exp_send -i $::Stat(pty,spid) $sentence\r
puts stderr 2:$sentence
exp_continue
} timeout {
puts stderr timeout
exp_continue
} eof {
puts stderr "EOF on GPSside"
}
puts end
# vwait forever
The second example sets up a udp gateway to ntp, receiving udp packets on a select port and piping that down into the pty/tty device opened by ntpd, start this in boot up before rcntp runs:
#!/usr/bin/tclsh
# $Id: gpsplug.tcl,v 1.3 2011/05/16 07:05:45 uwe Exp uwe $
# cprt: C2011 Uwe Klein Habertwedt
# what: plugin for ntpd to allow a nmea source to
# what: be remote or intermittently available.
# what: provides a tty(pty) for ntp to attach to
# what: while listening on udp:61161 for incoming
# what: nmea GPRMC messages ( intp:mode:0=1 ~= listen to RMC )
# what: ntp.conf: # basic nmea source, mode: listen to GPRMC sentence, 9600baud:
# what: ntp.conf: server 127.127.20.1 mode 17
# what: ntp.conf: fudge 127.127.20.1 flag1 0 flag2 0 flag3 0 flag4 0 time1 0.7800
# use_: start before ntpd at boot time.
package require Expect
package require udp
set ::Stat(pty,spid) {}
set ::Stat(gps,path) "/dev/gps1"
set ::Stat(udp,port) 61161
proc respawn_pty {} {
set spid $::Stat(pty,spid)
if {$spid != "" } {
close -i $spid -slave
wait
}
catch { puts stderr exist:[file exists $::Stat(gps,path)] }
catch { puts stderr type_:[file type $::Stat(gps,path)] }
catch {
if {[file type $::Stat(gps,path)] == "link" } {
puts stderr "deleting existing link: $::Stat(gps,path)"
file delete $::Stat(gps,path)
}
} cerr; puts stderr cerr:$cerr
spawn -pty
set ::Stat(pty,spid) [ set spid $spawn_id ]
set ::Stat(pty,slave,name) $spawn_out(slave,name)
set ::Stat(pty,slave,fd) $spawn_out(slave,fd)
file link -symbolic $::Stat(gps,path) $::Stat(pty,slave,name)
expect_background -i $::Stat(pty,spid) \
-re "AT.*?\[\r\n\]{1,2}" {
exp_send -i $::Stat(pty,spid) "OK\r"
puts stderr "AT sentence, OK sent"
} \004 {
puts stderr "$::Stat(pty,slave,name) ^D, reopen"
# respawn_pty
} eof {
puts stderr "$::Stat(pty,slave,name) EOF, reopen"
# respawn_pty
}
puts stderr "$::Stat(pty,slave,name) linked to $$::Stat(gps,path), open"
parray ::Stat
return $::Stat(pty,slave,name)
}
respawn_pty
proc udpEventHandler {sock} {
set sentence [read $sock]
set peer [fconfigure $sock -peer]
puts stderr "$peer: [string length $sentence] {$sentence}"
exp_send -i $::Stat(pty,spid) $sentence\r
return
}
proc udp_listen {port} {
set srv [udp_open $port]
fconfigure $srv -buffering none -translation binary
fileevent $srv readable [list ::udpEventHandler $srv]
puts "Listening on udp port: [fconfigure $srv -myport]"
return $srv
}
set gpssock [ udp_listen $::Stat(udp,port) ]
vwait forever
#end
The next script provides the nmea server:
#!/usr/bin/tclsh
package require Expect
package require udp
set ::Stat(pty,spid) {}
set ::Stat(gps,path) "/dev/gps1"
set ::Stat(udp,sock) [ udp_open 616162 ]
udp_conf $::Stat(udp,sock) localhost 616161
set fd [ open /dev/ttyUSB0 {RDWR NONBLOCK} ]
fconfigure $fd \
-encoding binary -translation binary \
-mode 9600,n,8,1 -handshake none
spawn -open $fd
set gps_spid $spawn_id
log_user 0
expect -i $gps_spid \
-re {(\$GPRMC.*?\*[[:xdigit:]]{2})[\r]} {
set sentence $expect_out(1,string)
puts -nonewline $::Stat(udp,sock) $sentence
flush $::Stat(udp,sock)
puts stderr 1:$sentence
exp_continue
} -re {(\$GPGGA.*?\*[[:xdigit:]]{2})[\r]} {
set sentence $expect_out(1,string)
# puts -nonewline $::Stat(udp,sock) $sentence
# flush $::Stat(udp,sock)
puts stderr 2:$sentence
exp_continue
} timeout {
puts stderr timeout
exp_continue
} eof {
puts stderr "EOF on GPSside"
}
puts end
# vwait forever