Note that broadcast is inherently IPv4 (it does not exist in IPv6) and
inefficient, forcing all nodes on a network to process data which they are
potentially uninterested in. Multicast is the superior technique but not
as widely supported by other marine applications.
Bi-directional unicast interfaces do not necessarily mean what you think they
mean. Outbound packets will be sent from an ephemeral port and will be
received from any sender of UDP packets containing valid NMEA-0183 data on
that port. This is invariably not what you want and it is normally better to use
separate send and receive interfaces for bi-directional communication over UDP
between two instances of kplex.
Generally kplex can work out whether an interface should use unicast, multicast
or broadcast traffic from the supplied
so the "type" option should not
normally be given and doing so to force an mode not consistent with the supplied
address will result in an error. One use for the "type" option is when
supplying a "device" but no "address" option to an inbound interface. In this
case the receiving interface will expect unicast traffic unless "type=broadcast"
is explicitly requested.
By default or if "coalesce=no" is specified, input sentences are always
transmitted one per packet as soon as they can be. If "coalesce=yes" is
specified, kplex will buffer parts of a multi-part AIS message so long as
enough space is available (512 bytes, a minimum of 7 sentences depending ons
size, can be buffered). Buffered data will be transmitted if the last part of
the message is received (even if all the intervening parts have not been),
there is insufficient space to store another sentence, or a sentence arrives
which is not part of the buffered message. In the latter cases the newly arrived
sentence is buffered if it is part (but not the last fragment) of a multi-part
AIS sentence, otherwise it is transmitted immediately. kplex does not re-order
out of order fragments of a multi-part AIS message.
Broadcast Interfaces
Broadcast interfaces are now deprecated and will be removed from a future
version of kplex. Use udp interfaces instead if possible.
This method involves nmea sentences encapsulated within UDP datagrams sent to a
broadcast address.
Interface-specific options:
device=
address=
port=
Where:
specifies the system interface (e.g. "wlan1", "eth0")
to use. This must be specified for outbound or bi-directional
interfaces. kplex will only broadcast out through one interface.
If the kplex interface is inbound and an interface is specified,
kplex will attempt to bind to that interface and only accept packets
received on that interface. Unfortunately this is a privileged
operation on most GNU/Linux systems and kplex will often silently
fail to do this without root privileges. You can possibly achieve a
similar effect without root privileges by use of the
specifier (see below). If interface is not specified (or given as
"-"), kplex will listen on all interfaces unless an is
specified (see below).
if specified is the udp port or service name. If not
specified defaults to the udp port returned by a lookup of the
service "nmea-0183" and if that fails the IANA assigned port for
nmea-0183 10110 is used.
is the IPv4 interface address to bind to for inbound kplex
interfaces or the address to send to for outbound interfaces. If
unspecified for an input, kplex will receive broadcast and unicast
udp to the relevant port on any specified, or all system
interfaces if none was specified or the user as insufficient
privileges to bind to a specific system interface. If an address is
specified for an inbound broadcast interface, kplex will receive
only packets to that address. Note that if you specify the IP
address of a system interface, you will NOT receive broadcast
traffic. If you specify a broadcast address (either the subnet
broadcast address or the "all hosts" broadcast address
255.255.255.255 you will ONLY receive that type of broadcast
(ie subnet OR all hosts). For this reason, this parameter is best
left unspecified by most users. For outbound connections, this
parameter specifies the broadcast address to use. It must be a
broadcast address appropriate for the system interface you have
specified and will default to the subnet broadcast address
associated with the first address found for the specified system
interface. If your client programs are particularly stupid they
may be expecting the all hosts broadcast address of 255.255.255.255.
If things don't work with the default, try this in the .
Note that broadcast is inherently IPv4 (it does not exist in IPv6) and highly
inefficient, forcing all nodes on a network to process data which they are
potentially uninterested in. Multicast is the superior technique but not
supported by many (if any) marine navigation applications at present.
Multicast Interfaces
Multicast interfaces are now deprecated and will be removed in a future version
of kplex. Use udp interfaces instead if possible.
Multicast interfaces are similar to broadcast interfaces, but available with
IPv6 as well as IPv4 and more efficient. In an ethernet network, a broadcast
packet will require all nodes on a network to pass the packet to their
IP stacks to determine whether or not it is of interest to them. IP multicast
addresses map to ethernet multicast addresses. An operating system tells its
network interface to accept only multicast packets with hardware addresses
it is interested in. The mapping is not 1:1 (many IP multicast addresses map
to one ethernet multicast address) but on a busy network, use of multicast
instead of broadcast can dramatically cut down the number of packets a given
node's network stack needs to process.
Interface-specific options:
group=<multicast address>
device=<interface>
port=<port>
Where:
<multicast address> is the multicast group address. This must be
specified.
<interface> is the network interface to use (e.g., "eth0", "wlan1"
etc.). If unspecified, if a bind address is specified, the system
interface assigned that address will be used, otherwise the choice
of interface will be left to the system and normally based on the
routing table.
<port> if specified is the udp port or service name. If not
specified defaults to the udp port returned by a lookup of the
service "nmea-0183" and if that fails the IANA assigned port for
nmea-0183 (10110) is used.
A multicast group address to used must be specified for a "multicast:"
interface. For link local IPv6 multicast addresses, an interface device must
be specified.
This may be done in one of two ways:
1) by appending the multicast group address with "%" followed by the
interface name, for example:
group=ff02::a0:200%wlan0
2) by specifying the interface with the "device" option, e.g.:
device=wlan0
If a device is not specified in one of the above ways for multicast addresses
other than IPv6 link and interface local groups, the routing table will be used
to select the outgoing interface for multicast packets.
GoFree Interfaces
GoFree is Navico's service discovery protocol which allows applications to
connect to a network services without knowing details of its address. A
kplex gofree interfaces listens on the IPv4 multicast address (239.2.1.1) and
port (2052) which Navico have specified for announcements of the "nmea-0183"
service. If not currently connected to an announced "nmea-0183" service, a
kplex gofree interface will attempt to initiate a connection to the unicast TCP
IPv4 address/port found in the first appropriate service announcement it sees.
If a gofree interface is currently connected to an nmea-0183 service, On receipt
of an announcement for an alternate service location (i.e. the IPv4 address/port
of an nmea-0183 service on another multifunction display ("MFD"), if the last
announcement for the currently connected service was more than 2 seconds prior,
the gofree interface will terminate the current service connection and reconnect
to the newly announced service. If the last announcement for the current
service was less than 2 seconds prior, kplex will only initiate a connection to
the alternate service if the current connection has terminated.
Interface-specific options:
device=<interface>
Where
<interface> specifies the system interface (e.g. "wlan1", "eth0") to
use. If unspecified the system will select the interface to listen
for service announcements on, normally defaulting to the first
multicast-capable non-loopback device.
GoFree does not support bi-directional nmea-0183 connections so all gofree
interfaces have an implicit "direction=in" option. It is an error to specify
"direction=out" for a gofree interface. Any output filters specified for a
gofree interface are ignored.
Pseudo Terminal (pty) interfaces
Pty interfaces are pretty much the same as serial interfaces except that the
devices concerned do not correspond to physical input and output devices on
your system. Actually, in the case of inputs it makes no difference whether you
specify "serial:" "pty:": The code ends up going down the same path.
Where ptys come in handy with kplex is if you want to split a serial input
between one or more programs running on a computer and possibly some outputs
too.
Interface-specific options:
mode=<mode>
filename=<file>
baud=<baud>
owner=<user>
group=<group>
perm=<permissions>
Where
<mode> is either "master" or "slave"
<file> is either the pty to connect to in "slave" mode or, in
"master" mode, a path name specifying a symbolic link that will be
created pointing to the slave side of a master pty
<baud> is the baud rate. Defaults to 4800 if unspecified
Supported baud rates are: 4800, 9600, 19200, 38400, 57600, 115200
<user> is the username for the slave side of a master pty to be set
to.
<group> is the group to set the slave side of a master pty to.
<permissions> are the permissions in octal form to set the slave
side of a master pty to.
must be specified in slave mode. In master mode, kplex creates a
master/ slave pty pair. If you give kplex a it will attempt to
create a symbolic link with that pathname pointing to the slave side of the
pty it creates. If the path given currently exists as a symbolic link it will
be replaced. If it exists but is not a symbolic link (e.g. it's a regular file
or device) kplex will exit with an error. If no pty name is given, or if it is
given as "-", kplex just prints the name of the slave pty created without
creating a symlink.
Specifying a pathname (and creating a symlink) is useful for providing a
persistent interface.
Where kplex is directed to create a master pty interface with "mode=master",
the slave side of the pty (which other processes will use to communicate with
kplex) will be created using system default ownership and permissions. On
many systems this will mean the owner of the device will be the owner of the
kplex process, the group will be set to "tty" and the permissions will be 0620
(i.e. read/write by owner, write only by group and inaccessible to others).
if "owner=" is specified, the owner of the slave side of a master pty will
be set to if is a valid system user and the owner of the kplex
process is permitted to change the file's ownership in this way. Normally this
may only be used by a kplex process running as root.
If "group=" is specified, the group of the slave side of a master pty
will be set to if is a valid system group and the owner of the
kplex process is permitted to change the file's group in this way. Normally
only root or a member of the specified group is able to make this change.
If "perm=" is specified where are the desired
permissions of the slave side of a master pty in octal format, permissions are
set accordingly. Only file access bits are settable. Attempts to set
setuid/setgid/sticky bits will be ignored. A leading "0" is allowed but not
required for permissions. Note that "000" is neither a useful nor, in this
case, permitted access mode.
As an example, Assume you wish to take AIS input from a serial
port, make it available to opencpn but also create a tcp server to make the
data available to inavX on an ipad. The user of OpenCPN is a member of the
dialout group but not tty. You might invoke kplex like this:
kplex serial:direction=in,filename=/dev/ttyUSB0,baud=38400
pty:direction=out,mode=master,filename=/home/fred/.opencpn/ais,baud=38400,group=dialout,perm=640
tcp:direction=out,mode=server
And add the following to /home/fred/.opencpn/opencpn.conf:
[Settings/AISPort]
Port=Serial:/home/fred/.opencpn/ais
This creates the /home/fred/.opencpn/ais, which opencpn will use for its AIS
input, as a symlink to the slave of a pty which kplex opens at 38400 baud in
addition to a tcp server.
Filtering
kplex allows you specify two types of filter: Input and Output
Input Filters dictate what sentences an input interface forwards
Output filters dictate which sentences get passed out of an output interface.
An input filter is used by input and bi-directional interfaces but ignored by
output interfaces. Likewise, an output filter is used by output and
bi-directional interfaces and ignored by input interfaces.
Connections spawned by servers inherit their parent's filters, so connections to
a tcp server will be filtered according to the server's filters.
A filter consists of a series of filter rules. Each filter rule
consists of a "+", "-" or "~" (to specify an "ALLOW", "DENY" or "LIMIT" rule,
respectively) followed by a "match string" which is either the word "all" or 5
characters. The match string may optionally be followed by the "%" character
and the name of an interface (which must have been given to an interface using
the "name=" option). A "LIMIT" rule must additionally have a "/" character
followed by a whole number (i.e. without a decimal point) representing the
minimum number of seconds which must pass between successive sentences matching
that rule being permitted to pass. Filter rules are separated by a colon (":"
character). Filter rules are applied in the order they are specified to a
sentence being filtered.
A filter rule which specifies the word "all" matches all sentences. If a filter
rule specifies a 5 character match string, these are compared with the 5
character NMEA 0183 talker/message type of the sentence being filtered. The
filter rule matches if each character is the same as the corresponding character
in the sentence being filtered. A "" in a filter matches any character. Thus a
filter rule specifying:
GP**
would match any sentences produced by a GPS talker (excluding any proprietary
sentences not specifying talker as "GP").
If a source interface has been specified for a rule, a given sentence must
additionally have entered kplex from an interface with the specified "name" for
the rule to "match". Thus a filter specified as
GP***%Serial1
would match sentences with a talker id of "GP" only if received on the
interface with the name "Serial1".
When a filter rule "matches" a sentence, it "fires". If the rule was an "allow"
rule (ie prepended by a "+", the sentence is allowed. If the rule was a "deny"
rule (ie prepended by a "-"), the sentence is dropped. If the rule was a
"limit" rule, the sentence is passed if and only if time in seconds since the
last time a sentence matching this that rule was allowed to pass was equal to
or greater than the number of seconds following the "/" in the rule
specification.
If no rules are matched the sentence is allowed. Thus a filter
such as:
ifilter=+GP***:+AI***:+SDDBT
is pointless. It allows all sentences as it denies none. To only allow AIS,
GPS and Depth below transducer sentences, you need to deny what is not
explicitly allowed by adding "-all" to the end of the filter specification:
ifilter=+GP***:+AI***:+SDDBT:-all
Obviously order is important. Putting "-all" at the beginning would simply deny
all sentences.
Specifying an interface in a rule applied to an ifilter is generally pointless.
IMPORTANT NOTE:
proprietary sentences start with "$P" followed by a three character vendor code,
followed by a vendor-specified string which may be, and often is, more than one
character in length. kplex can only filter on the 5 characters following the
"$" and thus cannot precisely filter all proprietary sentences.
Similarly kplex cannot completely filter Query sentences which consist of "$"
followed by the two letter talker id of the requester, the two letter talker id
of the target talker, the character "Q", a comman and the three character
sentence mnemonic. Only the 5 characters after the "$" (ie requester/target
pair) can be filtered on.
Failover
kplex allows you to specify special filters which are intended to allow you to
use a particular source for one type of data if it is available, but allowing
that type of data to be passed from another interface if it hasn't been seen
on the preferred input interface for a specified period of time. This behaviour
is specified using the "failover=" directive in the [global] section of the
configuration file or as a -o option on the command line. The format is:
failover=::[::]...
Where:
is a filter specifier as described in "Filtering" above
is the number of seconds without seeing data which matches the
filter on a higher priority interface before the datum is passed
is the name of the interface to which the specifier
applies. An interface must be given a "name=" option to be usable with
failover.
Any number of :: specifiers may be added. Any interface not
specified on a "failover" line will never pass sentences matching the filter.
"Primary" interfaces (ie those where the data should "normally" come from)
should be specified with a of 0.
Example:
You have 3 GPS sources available. The main GPS is fed via a serial connection
you have named "serial1". A second is available from a USB GPS you have
named "USBpuck". As a last resort you have your phone transmitting nmea over
tcp on an input you have named "phone". You might specify:
failover=GP***:0:serial1:30:USBpuck:60:phone
This will always pass sentences with a talker id of "GP" from the interface
named "serial1". If no "GP" sentences are seen on serial1 for 30 seconds,
kplex will pass sentences matching "GP***" from USBpuck until a "GP***" sentence
is next seen on serial1. If no "GP***" sentences are seen on either serial1 or
USBpuck for 60 seconds, kplex will start passing such sentences from the "phone"
connection until such point as those sentences are seen on either of the higher
priority interfaces.
Note that failover declarations when made in a configuration file need to be
put in the "global" section. For configuration file syntax see below.
Stopping
kplex closes down if it has no more outputs. If kplex has no more inputs,
it closes down after all outputs have transmitted any buffered data. Interfaces
shut down when the end of data input is reached (e.g. on end of file for file
inputs or a network peer terminates its end of the connection) or on error.
Outputs terminate when they are unable to write due to a network peer
terminating or some error condition.
If the process receives a SIGTERM (e.g. from the kill command) or SIGINT (e.g.
from ctrl-C pressed at the terminal kplex is running in), kplex will shut all
its interfaces down, allowing any buffered data to be transmitted, before
exiting.
To stop an instance of kplex which is running in the foreground, hold down the
"Ctrl" key and hit "c".
To stop an instance of kplex running in daemon mode, send it the termination
signal, e.g. "pkill kplex".
kplex should always clean up all of its interfaces, including restoring serial
line settings to what they were when kplex started. If this doesn't happen
it's a bug: Please report it.
NMEA-0183v4 TAG block handling
kplex will strip all NMEA-0183v4 TAG blocks from the input stream and discard
them. Correctly formatted following sentences will be multiplexed. kplex
does not conform to NMEA-0183v4 and will ignore all query and control messages.
Timestamps and source identifiers conform, as far as can be determined from
publicly available sources, to the NMEA-0183v4 TAG specification. Note
however that at this time implementation of TAG block handling in various
programs and devices is variable and other programs may discard sentences with
correctly formatted TAG blocks prepended
Example usage
Inputs from ais data on one serial port, other nmea data on a serial to usb
interface. Output to broadcast udp and one usb to serial interface:
kplex serial:direction=in,filename=/dev/ttyS0,baud=38400
serial:direction=in,filename=/dev/ttyUSB0
tcp:direction=out,mode=server
serial:direction=out,filename=/dev/ttyUSB1,baud=38400
Bi-directional communication with tcp server on 192.168.1.50, port 2200. Output
to pseudo terminal, creating link for opencpn to read and write at /tmp/nmea,
38400 baud
kplex tcp:direction=both,mode=client,address=192.168.1.50,port=2200
pty:direction=both,mode=master,filename=/tmp/nmea,baud=38400
Input from GPS on usb to serial interface, outputting to tcp server, IPv6
multicast group ff05::10:110 on the default port and a data log file which
appends an RMC sentence once per hour:
kplex serial:direction=in,filename=/dev/ttyUSB0
tcp:mode=server,direction=out
multicast:group=ff05::10:110,direction=out
file:filename=/var/tmp/datalog,direction=out,append=yes,ofilter=~GPRMC/3600:-all
Configuration File syntax
The configuration file syntax is similar to the command line sytax, but
new lines are used to separate options instead of commas and the start of an
interface specification is signalled by the interface type enclosed by square
brackets as the only non-white space on a line. Everything that follows the
start of an interface section is considered an option relating to that interface
until the beginning of the next interface section or the end of the file.
Everything after a '#' character on a line is ignored.
A special "interface" type, "global", may be used to specify options not
specific to a particular interface. "global" options currently suppotred are:
qsize=
Where:
is the size (in sentences) of kplex's central multiplexing queue
This should not normally need changing.
mode=
Where:
is either "foreground" (the default) or "background", the former
is the default. The latter tells kplex to detach form its controlling
terminal and run as a daemon process.
checksum=[yes|no]
Where:
"checksum=yes" tells kplex to check the checksum all incoming nmea sentences
(except for interfaces where per-interface configuration overrides this).
Sentences which do not match their calculated checksums are discarded. The
default is not to calculate checksums as it is assumed that this will be
done by end consumer applications.
strict=[yes|no]
Where:
"strict=yes" tells kplex to require all sentences received to be correctly
terminated with a <CR><LF> sequence unless overridden on a per-interface
"strict" option or a per-interface "eol=n". If "strict=no" is specified all
interfaces will default to a looser parsing strategy which will allow input
sentences to be terminated by a <CR>, <LF> or NULL (0x00). This option
applies to input sentences only and has no effect on interface output.
However terminated on input when loose parsing ("strict=no") is in effect,
sentences output from interfaces other than file interfaces will be <CR><LF>
terminated. If this value is not specified and no per-interface "strict="
specification is given, processing will default to "strict=yes" for all
interface types except file interfaces. For "file" interfaces the default
is loose ("strict=no") processing.
logto=
Where is the syslog facility to use for logging. The default is
"daemon", telling kplex to use the LOG_DAEMON syslog facility. is
the same string as would be used in a syslog.conf(5) file, so to log to
LOG_LOCAL7, specify "logto=local7".
failover=
Where is described in the "Failover" section
above.
graceperiod=
Where is the number of seconds to wait for output to be cleanly sent
before termination when kplex shuts down (default 3).
As an example, the first example from the "example usage" section above could
be specified in a configuration file:
This is a comment and will be ignored
[serial]
direction=in
filename=/dev/ttyS0
baud=38400 # baud will be read, but this comment ignored
whitespace is ignored
[serial]
direction=in
filename=/dev/ttyUSB0
[tcp]
direction=out
mode=server
[serial]
direction=out
filename=/dev/ttyUSB1
baud=38400
This is the end of the example file
This second example shows a configuration in which kplex has a GPS puck
connected via the serial port on a raspberry pi and connects to a TCP data
source for other information. The TCP data source also provides GPS information
but is only used if the directly attached GPS device fails for 15 seconds. Data
are then broadcast out of eth0 on the default port 10110. Checksum checking is
enabled and all sentences which fail their checksum checks are discarded. The
"persist=fromstart" option on the TCP interface ensures that kplex will keep
trying to connect to the remote device even if it is not available when kplex
starts up.
Begin example 2
[global]
checksum=yes
failover=GP***:0:puck:15:plotter
[serial]
filename=/dev/AMA0
baud=9600
direction=in
name=puck
[tcp]
address=192.168.1.2
direction=in
name=plotter
persist=fromstart
[broadcast]
device=eth0
direction=out
End example 2
To Do
Possible future enhancements include:
Q&A
"FAQ" would be inappropriate as some of the questions have never been asked.
Q: Is this free software?
A: Yes. As in "Beer" and as in "Speech". It is released under the terms of
GPLv3 (see the COPYING file which should be included with this software)
Q: Does this run on a raspberry pi?
A: Yes. Note the 3.3v weirdness of the serial interface though if not using
serial to usb adaptors.
Q: Can I use this to bridge to an ipad using just my laptop?
A: Not exactly. kplex does not create a wireless access point, it just uses
a linux computer's existing wireless interfaces. If you want to create a
wireless access point using a linux system, check out hostapd. An
Alternative may be to use ad hoc networking to connect to your wireless
device (The comar box does this).
Q: Why "kplex"?
A: Originally it was called "mplex", but that's the name of an mpeg stream
multiplexer for linux. changing only one letter of the name simplified
changing the file names. And "kplex" scores loads in french scrabble.
Q: Is this available for windows/plan9/haiku/solaris
A: It shouldn't be much work to port to another POSIX-compliant system. If
anyone genuinely wants such a thing let me know. For windows a better plan
would be to port it all to java (on the to do list). It has been ported to
Solaris but the ifdefs make the code uglier and Larry has turned my previous
OS of choice to the darkside so support is not included in the mainstream
codebase.
Q: I am a venture capitalist with $20m dollars to employ someone who can write
multithreaded IPv6 network code and also look after my infrequently used
superyacht. May I hire you?
A: I'll check my diary...
Thanks to / Tak til / Tack til / Takk til/ Dank Aan / Merci à
everyone who has provided feedback and suggestions and helped with testing