NAME
Device::Serial::SLuRM - communicate the SL�RM protocol over a serial
port
SYNOPSIS
use v5.36;
use Device::Serial::SLuRM;
my $slurm = Device::Serial::SLuRM->new(
dev => "/dev/ttyUSB0",
baud => 19200,
);
$slurm->run(
on_notify => sub ($payload) {
printf "NOTIFY: %v02X\n", $payload;
}
)->await;
DESCRIPTION
This module provides a Future::IO-based interface for communicating
with a peer device on a serial port (or similar device handle) which
talks the SL�RM messaging protocol. It supports sending and receiving
of NOTIFY packets, and sending of REQUEST packets that receive a
RESPONSE.
It currently does not support receiving REQUESTs, though this could be
added relatively easily.
Optionally, this module supports being the controller for a multi-drop
("MSL�RM") bus. See the Device::Serial::MSLuRM subclass.
SL�RM
SL�RM ("Serial Link Microcontroller Reliable Messaging") is a simple
bidirectional communication protocol for adding reliable message
framing and request/response semantics to byte-based data links (such
as asynchronous serial ports), which may themselves be somewhat
unreliable. SL�RM can tolerate bytes arriving corrupted or going
missing altogether, or additional noise bytes being received, while
still maintaining a reliable bidirectional flow of messages. There are
two main kinds of message flows - NOTIFYs and REQUESTs. In all cases,
packet payloads can be of a variable length (including zero bytes), and
the protocol itself does not put semantic meaning on those bytes - they
are free for the application to use as required.
A NOTIFY message is a simple notification from one peer to the other,
that does not yield a response.
A REQUEST message carries typically some sort of command instruction,
to which the peer should respond with a RESPONSE or ERR packet. Replies
to a REQUEST message do not have to be sent sequentially.
The doc/ directory of this distribution contains more detailed protocol
documentation which may be useful for writing other implementations.
The contrib/ directory of this distribution contains a reference
implementation in C for 8-bit microcontrollers, such as AVR ATtiny and
ATmega chips.
Metrics
If Metrics::Any is available, this module additionally provides metrics
under the namespace prefix of slurm. The following metrics are
provided:
discards
An unlabelled counter tracking the number of times a received packet
is discarded due to failing CRC check.
packets
A counter, labelled by direction and packet type, tracking the number
of packets sent and received of each type.
request_success_attempts
A distribution that tracks how many attempts it took to get a
response to each request.
request_duration
A timer that tracks how long it took to get a response to each
request.
retransmits
An unlabelled counter tracking the number of times a (REQUEST) packet
had to be retransmitted after the initial one timed out.
serial_bytes
A counter, labelled by direction, tracking the number of bytes sent
and received directly over the serial port. The rate of this can be
used to calculate overall serial link utilisation.
timeouts
An unlabelled counter tracking the number of times a request
transaction was abandoned entirely due to a timeout. This does not
count transactions that eventually succeeded after intermediate
timeouts and retransmissions.
PARAMETERS
dev
dev => PATH
Path to the /dev/... device node representing the serial port used for
this communication. This will be opened via IO::Termios and configured
into the appropriate mode and baud rate.
baud
baud => NUM
Optional baud rate to set for communication when opening a device node.
SL�RM does not specify a particular rate, but a default value of 115.2k
will apply if left unspecified.
fh
fh => IO
An IO handle directly to the the serial port device to be used for
reading and writing. It will be assumed to be set up correctly; no
further setup will be performed.
Either dev or fh are required.
retransmit_delay
retransmit_delay => NUM
Optional delay in seconds to wait after a non-response of a REQUEST
packet before sending it again.
A default value will be calculated if not specified. This is based on
the serial link baud rate. At the default 115.2k baud it will be 50msec
(0.05); the delay will be scaled appropriately for other baud rates, to
maintain a timeout of the time it would take to send 576 bytes.
Applications that transfer large amounts of data over slow links, or
for which responding to a command may take a long time, should increase
this value.
retransmit_count
retransmit_count => NUM
Optional number of additional attempts to try sending REQUEST packets
before giving up entirely. A default of 2 will apply if not specified
(thus each request method will make up to 3 attempts).
METHODS
recv_packet
( $pktctrl, $payload ) = await $slurm->recv_packet;
Waits for and returns the next packet to be received from the serial
port.
run
$run_f = $slurm->run( %args );
Starts the receiver run-loop, which can be used to wait for incoming
NOTIFY packets. This method returns a future, but the returned future
will not complete in normal circumstances. It will remain pending while
the run-loop is running. If an unrecoverable error happens (such as an
IO error on the underlying serial port device) then this future will
fail.
Takes the following named arguments:
on_notify => CODE
$on_notify->( $payload )
Optional. Invoked on receipt of a NOTIFY packet.
Will automatically "reset" first if required.
stop
$slurm->stop;
Stops the receiver run-loop, if running, causing its future to be
cancelled.
It is not an error to call this method if the run loop is not running.
send_packet
await $slurm->send_packet( $pktctrl, $payload );
Sends a packet to the serial port.
reset
$slurm->reset;
Resets the transmitter sequence number and sends a META-RESET packet.
It is not normally required to explicitly call this, as the first call
to "run", "send_notify" or "request" will do it if required.
send_notify
await $slurm->send_notify( $payload );
Sends a NOTIFY packet.
Will automatically "reset" first if required.
request
$data_in = await $slurm->request( $data_out );
Sends a REQUEST packet, and waits for a response to it.
If the peer responds with an ERR packet, the returned future will fail
with an error message, the category of slurm, and the payload body of
the ERR packet in the message details:
$f->fail( $message, slurm => $payload );
If the peer does not respond at all and all retransmit attempts end in
a timeout, the returned future will fail the same way but with undef as
the message details:
$f->fail( $message, slurm => undef );
Will automatically "reset" first if required.
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>