Skip to content

bakerkj/kplex

 
 

Repository files navigation

kplex: A multiplexer for various nmea 0183 interfaces
Copyright Keith Young 2012-2015 <stripydog7@gmail.com>
Blurb:
Details of the GPLv3 under which this software is distributed can be found in
the file COPYING in this directory.

This software almost certainly contains bugs and should not be relied on as
part of a safety critical system, ie as a sole source of marine navigational
information.

Installation From Source
------------------------
You've got this far so you've unpacked it.  So "make" should be the obvious
next step.  If you're using FreeBSD or some other system where GNU make is not
default, you make have to type "gmake" instead.  There's only one executable
("kplex").

"make install" will install kplex into /usr/bin on Linux systems, /usr/local/bin
on other systems. You can change this by setting BINDIR. ie to install to
/usr/sw/bin use:
make -D BINDIR=/usr/sw/bin install
alternatively if using sh/ksh/bash:
BINDIR=/usr/sw/bin make install

The "install" target does not install a start script. Tihs must be done manually
if required. It does not create a configuration file.  The file "kplex.conf.ex"
can be used as a starting point to create your own configuration file using the
information contained in this README file.

"make uninstall" will remove the kplex binary.  If you specified a non-standard
installation location using BINDIR, specify it again for the uninstall target.

If you want to have kplex start on boot, kplex.init is an example init script
for debian-derived systems. It expects kplex to be installed in /usr/bin
and a configuration file in /etc/kplex.conf. Change these as
necessary, install by copying kplex.init to /etc/init.d/kplex and run:
update-rc.d kplex defaults
to create symlinks in the appropriate rc.d directories.

kplex.init will run kplex as root, but this is neither required nor recommended.
To automatically run kplex as a different user, change RUN_AS_USER as
appropriate.  The user kplex runs as does require permissions to read
/write serial interfaces as necessary.  Typically this will mean being a member
of the group which owns serial devices. On debian-based systems like ubuntu this
means adding the user to the "dialout" group.

From .deb file
--------------
If you've installed from a debian binary package, the startup script and binary
are installed for you. The default start script is not configured to run at
boot time but can be made to do so using update-rc.d(8). The start script runs
kplex as root but this is not recommended.  Instead create a user (e.g.
"kplex") and change the RUN_AS_USER definition in /etc/init.d/kplex to specify
that kplex run as that user. Be sure to add this user to the group which owns
the serial ports (normally "dialout" on modern debian-based systems).

The configuration file the .deb installation installs in /etc/kplex.conf
actually does nothing (all directives are commented out).  Read the instructions
in this README file for how to create a confiuration file.  A quick start
example which bridges between a tcp server and a 38400 baud serial-to-usb
connection is commented out in this example file.

Invocation:
-----------

kplex [-V] | [-d 1..9] [-f <filename>] [-o <option>] <interface> <interface> [<interface> ...]

Where
The "-d" flag, if specified, will cause kplex to print debugging information,
the verbosity of which is controlled by the flag's argument with "1" producing
minimal additional debugging information and "9" producing verbose debug
information.

<filename> is the path of a configuration file to use where default options and
interfaces are defined. If not specified, kplex will look for a configuration
file in your home directory (~/.kplex.conf on GNU/Linux,
~/Library/Preferences/kplex.ini on Mac), then /etc/kplex.conf and if nothing is
found will use only command line directives.  Specifying filename as "-"
disables looking for the default configuration files.

<option> is an option specifier for the form:
    <varable>=<value>
These correspond to configuration options which may otherwise be specified in
"global" section of the configuration file (discussed in the "Configuration
File" secction below).  Command line configuration options always override
options given in the configuration file.

<interface> is an interface specifier which takes the form:
<interface_type>:<option>[,<option> ...]
where:
    <interface_type> is one of:
        "serial": serial nmea 0183 data
        "file": file (or standard in/out)
        "tcp": nmea over TCP
        "udp": nmea over UDP (unicast/broadcast/multicast)
        "broadcast": nmea over UDP broadcast (DEPRECATED)
        "bcast": synonym for "broadcast" (DEPRECATED)
        "multicast": nmea over UDP multicast (DEPRECATED)
        "mcast": synonym for "multicast" (DEPRECATED)
        "pty": serial nmea data over a pseudo terminal
        "gofree": nmea over TCP announced by Navico's "GoFree" protocol
    <option> is one or more options of the form <var>=<val>. Some options are
        not optional. Options applicable to all interface types are:
        "direction":  May normally be one of "in" specifying an input, "out"
            specifying an output, or "both" specifying a bi-directional
            interface. Not all directions are applicable to all interface types.
            The default is "both" if an interface type permits bi-directional
            commnuication. It is more efficient to specify "in" or "out" if that
            is all an interface needs to do.
        "qsize": Size of the interface's output queue. Not used for input only
            interfaces.  Defaults should be fine. This should only need to be
            increased from default in the case of a bursty high-speed input
            feeding a slow ouput.
        "checksum": May be "yes" to enable checksumming of incoming sentences on
            an interface or "no" to disable it. This option overrides the global
            checksum option.
        "strict": May be "yes" to enable strict parsing of incoming sentences on
            an interface or "no" to disable it. This option overrides the global
            strict parsing option.
        "loopback": May be "yes" to enable sentences read from an interface to
            be written back to it when communication is bi-directional or "no"
            (the default) to ensure sentences are not looped back to the
            interface they were read from.  This option should be used with
            extreme caution and generally not at all with broadcast or
            multicast interfaces.  This option has no effect on unidirectional
            interfaces.
        "ifilter": Specifies an input filter (see below)
        "ofilter": Specifies an output filter (see below)
        "name": Attaches a symbolic name to an interface.  This is only required
        if you intend to use the interface for failover (see below).  The value
        associated with "name" can be any string consisting of letters and or
        numbers which is not used as the "name" for another interface.  Names
        are NOT case sensitive, so do not call one interface "Serial" and
        another "serial".
        "srctag": Specifies that an NMEA-0183v4 TAG block containing a source
        identifier be prepended to sentences output on the interface if the
        value is "yes" or "input".  The src identification string is the
        interface name (see the "name" option above) truncated to 15 characters
        or the string "kplex" if no "name" is specified for the interface. A TAG
        block prepended by the "srctag=yes" option looks like:
        \s:kplex*23\
        If "srctag=no" is specified, no source identifier is prepended.  This is
        the default.
        If "srctag=input" is specified, the src identification string is the
        name of the interface on which the sentence arrived truncated to 15
        characters or the string "kplex" if no "name" is specified for the input
        interface.
        "timestamp": Specifies that an NMEA-0183v4 TAG block containing UNIX
        time (for example "\c:1423133110*5C\" should be prepended to sentences
        output on the interface.  The timestamp is in seconds if the value is
        "s" or milliseconds if the value is "ms".  Note that NMEA-0183v4
        timestamps do not take account of leap seconds.
        "optional": If "optional=no" is specified or this option is not given,
        kplex will exit if it cannot initialize the interface. If "optional=yes"
        is specified, failure of the interface to initialize will only cause
        kplex to exit if, as a result of it failing, kplex has no inputs or no
        outputs.

If source identifier and timestamps are both requested for an interface, they
are combined into a single TAG block, source identifier first, e.g.:
\s:kplex,c:1423133048*5F\

The -V flag instructs kplex to print its version number and exit. It should not
be used with any other options.

Interface Types:
----------------

Serial Interfaces
-----------------

This is the traditional way of getting nmea data into your computer.  kplex
doesn't care whether your device is connected to via a traditional serial
port or via a USB to serial converter so long as the device on which data are
presented looks like a character special device and it can be configured with
baud rate and a minimal set of other parameters. Note that you can't normally
just plug your nmea tx/rx into a serial port. NMEA is RS422 whereas serial ports
normally want RS232 input.

    Interface-specific options:
        filename=<device>
        baud=<baud>
        Where
            <device> is the serial device (e.g. /dev/ttyS0)
            <baud> is the baud rate.  Defaults to 4800 if unspecified
            Supported baud rates are: 4800, 9600, 19200, 38400, 57600, 115200

You must minimally specify a device name for a serial interface.  usb to serial
converters often use /dev/ttyUSB0. Check your /var/adm/messages file and/or udev
rules.  Note that normal users are often not permitted to open serial devices.  This may mean adding your user to a group which *is* allowed to read the device
(e.g. "dialout", "uucp" or whatever).


"File" interfaces
-----------------

This specification covers both regular files, FIFOs and terminal i/o via
standard input and standard output.

    Interface-specific options:
        filename=<file>
        persist=[yes|no]
        append=[yes|no]
        eol=[rn|n]
        owner=<user>
        group=<group>
        perm=<permissions>
        Where
            <file> is either the file name to read from or write to or "-".
                In the latter case, standard input is used for inputs, standard
                out for outputs, and standard in and standard out for "BOTH".
                If not specified deafults to "-".
            <user> is the user to set ownership of a created output file to.
            <group> is the group to set a created output file to.
            <permissions> are the file access permissions, in octal form, to set
                a created output file to.

"File" interfaces are slightly different from other interfaces in that
by default sentences are terminated by <LF> rather than <CR><LF>. Because this
is *nix and we don't want to muck about with redundant '\r's.  Sentences input
with just a terminating '\n' (ie <LF>) are converted to <CR><LF> translation for
output to other interface types (i.e. serial, tcp, broadcast etc.).

If the option "eol=rn" is specified, file interfaces will output sentences
terminated by <CR><LF>. Input sentences will be discarded if they are terminated
with <LF> not preceded by <CR> and will not have additional <CR>s added.

"eol=n" specifies that the default behaviour for file interfaces (<LF> only as
sentence delimiter) should be used.

"BOTH" is not supported as an I/O direction for the "file" type except for
standard in / standard out.

If no "filename" option is given, standard in/out are used.  Standard input and
output may not be used in "background" mode (ie when kplex is run as a daemon)
unless they are redirected to a file or a pipe.

If "append=yes" is specified for an interface outputting to a regular file,
output is appended to the file.  If "append=no" (the default) is specified, the
file will be truncated before output is written.  This option may not be
specified for input files, FIFOs or terminals.

"persist=yes" may only be specified on an interface connected to a FIFO. If
specified it will re-open a FIFO when the reader or writer at the other end
closes the pipe.  If "persist=no" (the default) is specified, an input interface
will exit on receipt of EOF. An output interface will exit when the reader at
the other end of the pipe exits.

FIFOs block on open for read until something opens the FIFO for writing, and
block on open for write until something opens them for reading.  To avoid
hanging kplex's initialization thread, opening of FIFOs is delayed until
individual reader and writer threads have been created.

Output to file interfaces is line buffered.

For output to regular files, if the specified filename does not exist it will be
created if permissions allow.  If kplex creates an output file, it will be
owned by the user of the kplex process unless the "owner=" option is specified,
in which case the file's ownership will be set to the specified username.  On
most systems, kplex can only set username to something other than the owner of
the kplex process when run as root.  The group of an output file created by
kplex will be set to the kplex process's primary group unless the "group="
option is specified in which case the file's group will be set to the specified
group.  The group must exist and the kplex process must have permission to
set a file to that group. Normally this requires the kplex process's owner to
be a member of the specified group.  An output file created by kplex is normally
readable and writable by user and group and readable by "other", modified by the
user's umask.  If "perm=" is specified, the permissions on a file created by
kplex are set to the option's argument in octal *unmodified* by the processes's
umask.  Thus "perm=0666" will make the file readable and writable by user, group
and other regardless of the kplex process's umask.

For output files which pre-exist and for all input files, the user,group and
perm options are ignored.

TCP Interfaces
--------------

kplex can act either as a tcp server (allowing other programs on the same or
other machines to connect to it) or as a tcp client, connecting to servers
on the same or other systems. In "client" mode, kplex will attempt to
connect to the server running on the port and address you specify.  This may be
a kplex tcp server interface or a commercial product, such as an nmea to wifi
interface box.  You must specify an ip address (IPv4 and IPv6 supported) for
a tcp client connection.  You may specify a port. If not specified, the port
used will be the one your system associates with "nmea-0183", or the IANA
assigned 10110 if your system doesn't know about "nmea-0183".  If using kplex,
the server port defaults to 10110. Consult manufacturer's documentation for
the port to use for other products.

In Server mode, kplex listens for incoming connections. These may be from
programs like iNavX or other instances of kplex.  No data flows until a
connection is made.  kplex can accept many client connections simultaneously.
The exact number will be system dependent but it will certainly be "enough".

    Interface-specific options:
    mode=<mode>
    address=<address>
    port=<port>
    persist=[yes|no|fromstart]
    retry=<seconds>
    preamble=<preamble>
    timeout=<timeout>
    sndbuf=<bufsize>
    nodelay=[yes|no]
    keepalive=[yes|no]
    keepidle=<keepidle>
    keepintvl=<keepinterval>    * Not Mac OS X < 10.9
    keepcnt=<count>             * Not Mac OS X < 10.9
        Where:
            <mode> is either "server" or "client". If not specified, defaults to
            "client".
            <address> is the server address to bind to for output interfaces
                and the remote tcp server to connect to for inputs.  This can
                be:
                * A symbolic hostname (which must be resolvable on the host)
                * An IPv4 address in dotted decimal format
                * An IPv6 address
            For input interfaces, a remote host MUST be specified.  For outputs,
            if address is not specified, or specified as "-" a wildcard address
            will be used and the server run on all available interfaces.
            Whether this is IPv4 only or IPv4 and IPv6 will depend on system
            configuration.  IPv6 can be forced (if your systenm supports it)
            using a wildcard address of "0::0".  An IPv6 server can accept IPv4
            connections on a dual stacked host. You can happily ignore all
            mention of IPv6 if you want to.
            The address, if specified for an output, must correspond to one
            assigned to a interface on the host
            <port> is the tcp port to run the server on.  If not specified,
            defaults to the tcp port returned by a lookup of the service
            "nmea-0183" and if that fails the IANA assigned port for nmea-0183
            10110 is used.
            <seconds> is the number of seconds to wait before each attempt at
            reconnecting a lost tcp connection.  The "retry" option is only
            valid in conjunction with "persist=yes" or "persist=fromstart"
            <preamble> is a string of characters to send after connecting to a
            remote server and before sending data, as described below.
            <timeout> is the number of seconds to wait for an output operation
            to complete before assuming a connection has died, abandoning the
            data send operation and attempting to reconnect the interface.  Only
            valid with output or bi-directional interfaces and only in
            conjunction with "persist=yes" or "persist=fromstart". Note that
            timeouts will not occur while data can still be passed to TCP, so
            the size of TCP buffers has an impact on how quickly a hung
            connection will be timed out.
            <bufsize> is the size in bytes to set the TCP output buffer to.
            This option is valid only with "persist=yes" or "persist=fromstart"
            and defaults to 2048.  Without "persist=yes" or "persist=fromstart"
            system default TCP buffer size is used. A buffer size of 2k should
            not negatively impact performance in this application.  A smaller
            output buffer size generally results in hung output connections
            being detected faster.
            <keepidle> is the number of seconds of inactivity on a tcp
            connection to wait before sending the first keepalive probe (see
            below).  Only valid with "keepalive=yes".
            <keepinterval> is the number of seconds to wait between
            each keepalive probe after the first (see below).  Only valid with
            "keepalive=yes" and not available for Mac OS X prior to Mavericks.
            <count> is the number of un-replied to keepalive probes  (see
            below) before a tcp connection is considered lost.  Only valid with
            "keepalive=yes" and not available for Mac OS X prior to Mavericks.

For most purposes you can just specify "tcp:direction=both,mode=server" to
create a bi-directional tcp server.

If a client ("mode=client", the default) tcp connection is lost for any reason,
kplex will not attempt to reconnect if "persist=no" (the default) is specified.
The interface will shut down, but other interfaces will continue to operate.  If
"persist=yes" is specified for a client connection, kplex will attempt to
reconnect when the connection is lost.  When attempting to reconnect an outbound
or bi-directional connection, kplex will discard all data in its queue to
minimise the amount of potentially stale data arriving at the server.
The delay in seconds between successive attempt at reconnection may be specified
using the "retry" option.  "persist=yes" only tells kplex to reconnect a lost
connection.  If the first connection attempt fails it will not be re-tried and
initialisation of that interface will fail.  If persistent attempts to connect
an initially failed connection are desired, "persist=fromstart" should be
specified.  Note that this option should be used with care to avoid repeated
attempts to conenct to a mis-typed hostname or address.

kplex will detect a dropped connection if the other end closes down "cleanly",
i.e. the program it is connecting to shuts down or the machine it is running on
is gracefully shut down.  If the "timeout" option is specified, kplex will
consider a connection dropped if it receives no acknowledgment to data it is
attempting to send within the number of seconds specified in the argument.
It may not so easily be able to detect a failed endpoint if it is purely reading
from the other end and it is not notified that the data source has gone away.
This may frequently happen if connecting from behind NAT (NAT mappings are lost)
or if the other computer crashes or has power removed.  In these cases it is
useful to specify the "keepalive=yes" option (the default is "no").  This will
cause tcp to send probes to the remote end point to check that it is still
"alive".  The first probe is sent after <keepidle> seconds of inactivity.  The
default value will be system dependent but is usually 2 hours.  If no reply is
received to this probe, further probes are sent <keepinterval> seconds apart.
If <count> probes are sent without reply, kplex considers the connection dropped
and will attempt to reconnect.  The default values for the interval between
keepalive probes and the number sent before the connection is considered lost
are system dependent, but invariably higher than desirable for kplex's purposes.
On Mac OS X versions prior to Mavericks, only the delay before the initial probe
is configurable from within kplex, but the other two values are configurable on
a system-wide basis with sysctl(8).

If "persist=yes" is specified for a tcp client connection but no "keepalive="
option is given, keepalives will default to "on" and unless explicitly specified
otherwise, the following values will be set:
keepidle=30
keepintvl=10 (Not Mac OS X prior to 10.9)
keepcnt=3 (Not Mac OS X prior to 10.9)

If "nodelay=yes" is specified or the nodelay option is not used, kplex will
disable the nagle algorithm on an outbound tcp connection. This results in
fractionally faster delivery of data to clients at the expense of slightly more
network traffic and is generalyl desirable on a local area network.  Where
minimising network use is a priority (such as sending data over a mobile data
connection with a per-megabyte charge) specifying "nodelay=no" can reduce
network traffic at the expense of a slight increase in latency.
 
The "preamble" option is used to send a set of characters to a remote server to
identify a sending station before transmitting data.  It is not part of the
NMEA-0183 specification (for standards-compliant source identification, use
source TAGs instead) but is used by some AIS aggregation sites as an alternative
to per-station dedicated TCP ports.  If specified with the "persist" option, the
preamble string will be sent after each reconnection following connection loss.
Non-ASCII characters may be specified either by a backslash followed by the
(exactly) 3-digit octal representation of the character or the sequence "\x"
followed by the (exactly) 2-digit hexadecimal representation of the character.
The NULL character must be specified as "\000" or "\x00" and may not be
abreviated to "\0" or "\x0".  Standard escape sequences (\a,\b,\f,\r,\n,\t,\v)
are recognised.  Other escaped characters are sent literally without the leading
backslash.  Any string termination must be explicitly stated, so a NULL-
terminated string must end with "\000" or "\x00".  Care must be taken when using
this option on the command line due to shell interpretation of escape
characters.

UDP Interfaces
--------------
NOTE: As of kplex 1.3 UDP interfaces are now preferred over the existing
"broadcast" and "multicast" interface types.  However the "udp" interface is
new in this version. If you encounter problems, please report the issue and
consider reverting to the older "broadcast" or "multicast" interface types
while your problem is under investigation.

This method encapsulates nmea sentences within UDP datagrams which are sent via
unicast, multicast or broadcast.
    Interface-specific options:
    address=<address>
    port=<port>
    device=<interface>
    type=[unicast|broadcast|multicast]
    coalesce=[yes|no]
        Where:
            <address> is the interface address to bind to for inbound kplex
            interfaces or the address to send to for outbound interfaces. If
            not specified for an input interface, kplex will receive broadcast
            and unicast traffic sent to the desired port on a given interface if
            one is specified, or all interfaces if non is specified.  If no
            address is specified for an output or bi-directional interface, a
            system interface must be specified, in which case the broadcast or
            point-to-point destination address is assumed for outbound datagrams
            with inbound datagrams received for the address of the specified
            interface in the case of point-to-point system interfaces or the
            interface's broadcast address where the system interface is
            broadcast-capable.  For sending and receiving of multicast datagrams
            an address must be specified.  kplex should work out whether any
            provided address is unicast, multicast or broadcast and act
            accordingly. "group=" is a synonym for "address=" for backwards
            compatibility with deprecated mcast interfaces.
            <device> specifies the system interface (e.g. "wlan1", "eth0")
            to use.  If the kplex interface is inbound and an interface is
            specified, kplex will attempt to bind to an address if one is
            specified which belongs to that system interface, or the first
            address found associated with that system interface if no address
            is specified. For bi-directional and outbound multicast and
            broadcast interfaces all traffic is sent and received using a
            specified system interface.  For bi-directional and outbound unicast
            interfaces any received traffic will be on the interface specified.
            For outbound datagrams the source address will be set to an address
            associated with the specified interface.  If no device is specified
            for inbound or outbound multicast interfaces, the routing table is
            used to determine which system interface to use.
            For broadcast and unicast interfaces inbound traffic will be
            received on the system interface corresponding to a specified
            broadcast or unicast address where no system interface is specified
            or any system address if no device or address is specified.
            <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.

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 <address> 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=<interface>
    address=<address>
    port=<port>
        Where:
            <device> 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 <address>
            specifier (see below). If interface is not specified (or given as
            "-"), kplex will listen on all interfaces unless an <address> is
            specified (see below).
            <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.
            <address> 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 <interface> 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 <address>.

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.

<file> must be specified in slave mode.  In master mode, kplex creates a
master/ slave pty pair. If you give kplex a <file> 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=<user>" is specified, the owner of the slave side of a master pty will
be set to <user> if <user> 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=<group>" is specified, the group of the slave side of a master pty
will be set to <group> if <group> 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=<permissions>" is specified where <permissions> 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=<filter>:<delay>:<interface>[:<delay>:<interface>]...
Where:
    <filter> is a filter specifier as described in "Filtering" above
    <delay> is the number of seconds without seeing data which matches the
    filter on a higher priority interface before the datum is passed
    <interface> is the name of the interface to which the <delay> specifier
    applies.  An interface must be given a "name=" option to be usable with
    failover.
Any number of :<delay>:<interface> 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 <delay> 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=<qsize>
    Where:
    <qsize> is the size (in sentences) of kplex's central multiplexing queue
    This should not normally need changing.
mode=<mode>
    Where:
    <mode> 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" (the default if "strict=" is not specified) 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.
logto=<facility>
    Where <facility> is the syslog facility to use for logging.  The default is
    "daemon", telling kplex to use the LOG_DAEMON syslog facility. <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=<failover specification>
    Where <failover specification> is described in the "Failover" section
    above.
graceperiod=<secs>
    Where <secs> 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:
* A set of commands to allow modifying kplex on the fly, for example to add,
  subtract and modify the current interface list.  The structure of kplex means
  this would be a relatively straightforward addition
* A nice GUI.  Obviously.

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

About

kplex marine data multiplexer

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C 98.1%
  • Other 1.9%