summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/nmea
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
commitea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch)
tree6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/modules/nmea
parentb5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff)
parent7c621da28f07e449ad90c387344f07a453927569 (diff)
downloadblt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.zip
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.gz
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.bz2
Merge commit '7c621da28f07e449ad90c387344f07a453927569' as 'tcllib'
Diffstat (limited to 'tcllib/modules/nmea')
-rw-r--r--tcllib/modules/nmea/ChangeLog101
-rw-r--r--tcllib/modules/nmea/nmea.man102
-rwxr-xr-xtcllib/modules/nmea/nmea.tcl197
-rw-r--r--tcllib/modules/nmea/pkgIndex.tcl2
4 files changed, 402 insertions, 0 deletions
diff --git a/tcllib/modules/nmea/ChangeLog b/tcllib/modules/nmea/ChangeLog
new file mode 100644
index 0000000..2b93864
--- /dev/null
+++ b/tcllib/modules/nmea/ChangeLog
@@ -0,0 +1,101 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2009-02-11 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * nmea.man: Added category information to manpage, put into
+ 'Networking'. Regenerated support/devel/sak/doc/toc.txt.
+
+2009-01-09 Andreas Kupries <andreask@activestate.com>
+
+ * nmea.man: Fixed manpage problems reported by 'sak.tcl doc
+ validate nmea'.
+
+2009-01-08 Aaron Faupell <afaupell@users.sourceforge.net>
+
+ nmea.tcl: lots of changes, bumped major ver to 1.0.0
+ - close_port and close_file become close
+ - fixed some problems with automatic file reading
+ - switched to registered events instead of specially named procs
+ - added default and eof events
+ - added configure command
+ nmea.man: updated for new commands and clarity
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2007-11-15 Aaron Faupell <afaupell@users.sourceforge.net>
+
+ * nmea.tcl: added return values to do_line, new input command
+ bumped minor rev
+ * nmea.man: updated for do_line, input, new intro paragraph
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-08-20 Andreas Kupries <andreask@activestate.com>
+
+ * nmea.man: Bumped package version to 0.1.1.
+ * nmea/tcl:
+ * pkgIndex.tcl:
+
+2007-08-16 Aaron Faupell <afaupell@users.sourceforge.net>
+
+ * nmea.tcl fixed bug in read_port when using logging,
+ bug id 1765388
+
+2007-05-28 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * nmea.man: Added title, extended set of keywords.
+
+2007-03-21 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * nmea.man: Fixed all warnings due to use of now deprecated
+ commands. Added a section about how to give feedback.
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-06-30 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * nmea.man: Fixed syntax errors in the documentation.
+
+2006-06-30 Aaron Faupell <afaupell@users.sourceforge.net>
+
+ * New module for handling NMEA protocol
diff --git a/tcllib/modules/nmea/nmea.man b/tcllib/modules/nmea/nmea.man
new file mode 100644
index 0000000..cba215b
--- /dev/null
+++ b/tcllib/modules/nmea/nmea.man
@@ -0,0 +1,102 @@
+[manpage_begin nmea n 1.0.0]
+[keywords gps]
+[keywords nmea]
+[copyright {2006-2009, Aaron Faupell <afaupell@users.sourceforge.net>}]
+[moddesc {NMEA protocol implementation}]
+[titledesc {Process NMEA data}]
+[category Networking]
+[require Tcl 8.4]
+[require nmea [opt 1.0.0]]
+[description]
+[para]
+
+This package provides a standard interface for writing software which recieves
+NMEA standard input data. It allows for reading data from COM ports, files,
+or programmatic input. It also supports the checksumming and logging of incoming data.
+After parsing, input is dispatched to user defined handler commands for processing.
+To define a handler, see the [cmd event] command. There are no GPS specific functions
+in this package. NMEA data consists of a sentence type, followed by a list of data.
+
+[section COMMANDS]
+[list_begin definitions]
+
+[call [cmd ::nmea::input] [arg sentence]]
+Processes and dispatches the supplied sentence. If [arg sentence] contains no commas it is treated as a Tcl list, otherwise it must be standard comma delimited NMEA data, with an optional checksum and leading [const \$].
+
+[example {
+nmea::input {$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39}
+nmea::input [list GPGSA A 3 04 05 09 12 "" "" 24 "" "" "" 2.5 1.3 2.1]
+}]
+
+[call [cmd ::nmea::open_port] [arg port] [opt speed]]
+Open the specified COM port and read NMEA sentences when available. Port speed is set to
+4800bps by default or to [arg speed].
+
+[call [cmd ::nmea::close_port]]
+Close the com port connection if one is open.
+
+[call [cmd ::nmea::configure_port] [arg settings]]
+Changes the current port settings. [arg settings] has the same format as fconfigure -mode.
+
+[call [cmd ::nmea::open_file] [arg file] [opt rate]]
+Open file [arg file] and read NMEA sentences, one per line, at the rate specified by [opt rate] in milliseconds.
+The file format may omit the leading [const \$] and/or the checksum. If rate is <= 0 (the default) then lines
+will only be processed when a call to [cmd do_line] is made.
+
+[call [cmd ::nmea::close_file]]
+Close the open file if one exists.
+
+[call [cmd ::nmea::do_line]]
+If there is a currently open file, this command will read and process a single line from it.
+Returns the number of lines read.
+
+[call [cmd ::nmea::rate]]
+Sets the rate at which lines are processed from the open file, in milliseconds. The rate remains
+consistant across files, there does not need to be a file currently open to use this command.
+Set to 0 to disable automatic line processing.
+
+[call [cmd ::nmea::log] [opt file]]
+Starts or stops input logging. If a file name is specified then all NMEA data recieved on
+the open port will be logged to the [opt file] in append mode. If file is an empty string then
+any logging will be stopped. If no file is specified then returns a boolean value indicating
+if logging is currently enabled. Data written to the port by [cmd write],
+ data read from files, or input made using [cmd input], is not logged.
+
+[call [cmd ::nmea::checksum] [arg data]]
+Returns the checksum of the supplied data.
+
+[call [cmd ::nmea::write] [arg sentence] [arg data]]
+If there is a currently open port, this command will write the specified sentence and data to the port
+in proper NMEA checksummed format.
+
+[call [cmd ::nmea::event] [arg setence] [opt command]]
+Registers a handler proc for a given NMEA [arg sentence]. There may be at most one handler per
+sentence, any existing handler is replaced.
+If no command is specified, returns the name of the current handler for the given [arg setence]
+or an empty string if none exists. In addition to the incoming sentences there are 2 builtin types,
+EOF and DEFAULT. The handler for the DEFAULT setence is invoked if there is not a specific handler
+for that sentence. The EOF handler is invoked when End Of File is reached on the open file or port.
+[para]
+The handler procedures, with the exception of the builtin types,must take exactly one argument,
+which is a list of the data values.
+The DEFAULT handler should have two arguments, the sentence type and the data values.
+The EOF handler has no arguments.
+
+[example {
+nmea::event gpgsa parse_sat_detail
+nmea::event default handle_unknown
+
+proc parse_sat_detail {data} {
+ puts [lindex $data 1]
+}
+
+proc handle_unknown {name data} {
+ puts "unknown data type $name"
+}
+}]
+
+[list_end]
+
+[vset CATEGORY nmea]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/nmea/nmea.tcl b/tcllib/modules/nmea/nmea.tcl
new file mode 100755
index 0000000..884b4a5
--- /dev/null
+++ b/tcllib/modules/nmea/nmea.tcl
@@ -0,0 +1,197 @@
+# nmea.tcl --
+#
+# NMEA protocol implementation
+#
+# Copyright (c) 2006-2009 Aaron Faupell
+#
+# RCS: @(#) $Id: nmea.tcl,v 1.5 2009/01/09 06:49:25 afaupell Exp $
+
+package require Tcl 8.4
+package provide nmea 1.0.0
+
+namespace eval ::nmea {
+ array set ::nmea::nmea [list checksum 1 log {} rate 0]
+ array set ::nmea::dispatch ""
+}
+
+proc ::nmea::open_port {port {speed 4800}} {
+ variable nmea
+ if {[info exists nmea(fh)]} { ::nmea::close }
+ set nmea(fh) [open $port]
+ fconfigure $nmea(fh) -mode $speed,n,8,1 -handshake xonxoff -buffering line -translation crlf
+ fileevent $nmea(fh) readable [list ::nmea::read_port $nmea(fh)]
+ return $port
+}
+
+proc ::nmea::open_file {file {rate {}}} {
+ variable nmea
+ if {[info exists nmea(fh)]} { ::nmea::close }
+ set nmea(fh) [open $file]
+ if {[string is integer -strict $rate]} {
+ if {$rate < 0} { set rate 0 }
+ set nmea(rate) $rate
+ }
+ fconfigure $nmea(fh) -buffering line -blocking 0 -translation auto
+ if {$nmea(rate) > 0} {
+ after $nmea(rate) [list ::nmea::read_file $nmea(fh)]
+ }
+ return $file
+}
+
+proc ::nmea::configure_port {settings} {
+ variable nmea
+ fconfigure $nmea(fh) -mode $settings
+}
+
+proc ::nmea::close {} {
+ variable nmea
+ catch {::close $nmea(fh)}
+ unset -nocomplain nmea(fh)
+ foreach x [after info] {
+ if {[lindex [after info $x] 0 0] == "::nmea::read_file"} {
+ after cancel $x
+ }
+ }
+}
+
+proc ::nmea::read_port {f} {
+ if {[catch {gets $f} line] || [eof $f]} {
+ if {[info exists ::nmea::dispatch(EOF)]} {
+ $::nmea::dispatch(EOF)
+ }
+ nmea::close
+ }
+ if {$::nmea::nmea(log) != ""} {
+ puts $::nmea::nmea(log) $line
+ }
+ ::nmea::parse_nmea $line
+}
+
+proc ::nmea::read_file {f {auto 1}} {
+ variable nmea
+ set line [gets $f]
+ if {[eof $f]} {
+ if {[info exists ::nmea::dispatch(EOF)]} {
+ $::nmea::dispatch(EOF)
+ }
+ nmea::close
+ return 0
+ }
+ if {[string match {$*} $line]} {
+ ::nmea::parse_nmea $line
+ } else {
+ ::nmea::parse_nmea \$$line
+ }
+ if {$auto} {
+ after $nmea(rate) [list ::nmea::read_file $f]
+ }
+ return 1
+}
+
+proc ::nmea::do_line {} {
+ variable nmea
+ if {![info exists nmea(fh)]} { return -code error "there is no currently open file" }
+ return [::nmea::read_file $nmea(fh) 0]
+}
+
+proc ::nmea::configure {opt {val {}}} {
+ variable nmea
+ switch -exact -- $opt {
+ rate {
+ if {$val == ""} { return $nmea(rate) }
+ if {![string is integer $val]} { return -code error "rate must be an integer value" }
+ if {$val <= 0} {
+ foreach x [after info] {
+ if {[lindex [after info $x] 0 0] == "::nmea::read_file"} {
+ after cancel $x
+ }
+ }
+ set val 0
+ }
+ if {$nmea(rate) == 0 && $val > 0} {
+ after $val [list ::nmea::read_file $nmea(fh)]
+ }
+ set nmea(rate) $val
+ return $val
+ }
+ checksum {
+ if {$val == ""} { return $nmea(checksum) }
+ if {![string is bool $val]} { return -code error "checksum must be a boolean value" }
+ set nmea(checksum) $val
+ return $val
+ }
+ default {
+ return -code error "unknown option $opt"
+ }
+ }
+}
+
+proc ::nmea::input {sentence} {
+ if {![string match "*,*" $sentence]} { set sentence [join $sentence ,] }
+ if {[string match {$*} $sentence]} {
+ ::nmea::parse_nmea $sentence
+ } else {
+ ::nmea::parse_nmea \$$sentence
+ }
+}
+
+proc ::nmea::log {{file _X}} {
+ variable nmea
+ if {$file == "_X"} { return [expr {$nmea(log) != ""}] }
+ if {$file != ""} {
+ if {$nmea(log) != ""} { ::nmea::log {} }
+ set nmea(log) [open $file a]
+ } else {
+ catch {::close $nmea(log)}
+ set nmea(log) ""
+ }
+ return $file
+}
+
+proc ::nmea::parse_nmea {line} {
+ set line [split $line \$*]
+ set cksum [lindex $line 2]
+ set line [lindex $line 1]
+ if {$cksum == "" || !$::nmea::nmea(checksum) || [checksum $line] == $cksum} {
+ set line [split $line ,]
+ set sentence [lindex $line 0]
+ set line [lrange $line 1 end]
+ if {[info exists ::nmea::dispatch($sentence)]} {
+ $::nmea::dispatch($sentence) $line
+ } elseif {[info exists ::nmea::dispatch(DEFAULT)]} {
+ $::nmea::dispatch(DEFAULT) $sentence $line
+ }
+ }
+}
+
+proc ::nmea::checksum {line} {
+ set sum 0
+ binary scan $line c* line
+ foreach char $line {
+ set sum [expr {$sum ^ ($char % 128)}]
+ }
+ return [format %02X [expr {$sum % 256}]]
+}
+
+proc ::nmea::write {type args} {
+ variable nmea
+ set data $type,[join $args ,]
+ puts $nmea(fh) \$$data*[checksum $data]
+}
+
+proc ::nmea::event {sentence {command _X}} {
+ variable dispatch
+ set sentence [string toupper $sentence]
+ if {$command == "_X"} {
+ if {[info exists dispatch($sentence)]} {
+ return $dispatch($sentence)
+ }
+ return {}
+ }
+ if {$command == ""} {
+ unset -nocomplain dispatch($sentence)
+ return {}
+ }
+ set dispatch($sentence) $command
+ return $command
+}
diff --git a/tcllib/modules/nmea/pkgIndex.tcl b/tcllib/modules/nmea/pkgIndex.tcl
new file mode 100644
index 0000000..200dd5d
--- /dev/null
+++ b/tcllib/modules/nmea/pkgIndex.tcl
@@ -0,0 +1,2 @@
+if {![package vsatisfies [package provide Tcl] 8.2]} {return}
+package ifneeded nmea 1.0.0 [list source [file join $dir nmea.tcl]]