Expand description
Slipmux: Using an UART interface for diagnostics, configuration, and packet transfer
Pure Rust implementation of draft-bormann-t2trg-slipmux-03.
§What is Slipmux
Slipmux is a very simple framing and multiplexing protocol. It uses RFC1055,
commonly known as serial line ip (slip),
as a basis for encoding / decoding data streams into frames but extends it with
multiplexing. Slipmux defines three frame types: traditional IP packets,
diagnostic frames and configuration messages.
Diagnostic frames are UTF-8 encoded strings intended as human-readable messages.
Configuration messages are serialized CoAP messages.
§Examples
Slipmux can be used to both encode and decode streams of bytes:
§Encoding
Encoding can be done in a single pass.
First wrap your data in the matching type of the Slipmux enum. Then
feed it into the encode_buffered() function. You can also use the encode() function and
provide the FrameType and buffers manually, intended for no_std usage.
Alternatively, use the helper functions encode_diagnostic(), encode_configuration(),
encode_packet().
use slipmux::ChunkedEncoder;
use slipmux::FrameType;
use slipmux::Slipmux;
use slipmux::encode;
use slipmux::encode_buffered;
use slipmux::encode_configuration;
use coap_lite::Packet;
/* Typical use with std-feature: */
let input = Slipmux::Diagnostic("Hello World!".to_owned());
let buffer = encode_buffered(input);
assert_eq!(buffer, *b"\xc0\x0aHello World!\xc0");
/* Typical use on no_std */
let mut own_buffer: [u8; 256] = [0; 256];
let length = encode(FrameType::Diagnostic, "Hello World!".as_bytes(), &mut own_buffer);
assert_eq!(buffer, own_buffer[..length]);
/* Also no_std, when buffer space is limited, the chunked encoder can be used iteratively */
let mut encoder = ChunkedEncoder::new(FrameType::Diagnostic, "Hello World!".as_bytes());
let mut output = Vec::new();
while !encoder.is_exhausted() {
let mut buf = [0; 4];
let length = encoder.encode_chunk(&mut buf);
output.extend_from_slice(&buf[..length]);
}
assert_eq!(output, *b"\xc0\x0aHello World!\xc0");
/* Example with configuration */
let length = encode_configuration(&Packet::new().to_bytes().unwrap(), &mut own_buffer);
assert_eq!(own_buffer[..length], [0xc0, 0xa9, 0x40, 0x01, 0x00, 0x00, 0xbc, 0x38, 0xc0]);§Decoding
Since the length and number of frames in a data stream (byte slice) is unknown upfront, the decoder retains a state even after finishing decoding the input. This enables to repeatedly call the decoder with new input data and if a frame is split between two or more calls, the decoder will correctly concat the frame.
The decoded bytes of a frame are passed to a FrameHandler. The user has to provide a handler either
by implementing one themselves or use one of the provided generic implementations. This example uses
the BufferedFrameHandler which is characterized by collecting all frames and errors in to a result
vector of type Vec<Result<Slipmux, Error>>.
use slipmux::Slipmux;
use slipmux::Decoder;
use slipmux::BufferedFrameHandler;
const SLIPMUX_ENCODED: [u8; 15] = [
0xc0, 0x0a,
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21,
0xc0
];
let mut slipmux = Decoder::new();
let mut handler = BufferedFrameHandler::new();
for byte in &SLIPMUX_ENCODED {
let _: Result<slipmux::DecodeStatus, slipmux::Error> = slipmux.decode(*byte, &mut handler);
}
let mut results = handler.results;
assert_eq!(results.len(), 1);
let frame = results.pop().unwrap();
assert!(frame.is_ok());
match frame.unwrap() {
Slipmux::Diagnostic(s) => assert_eq!(s, "Hello World!"),
_ => panic!(),
}This crate is #[no_std] friendly. If you disable the default feature std, you will have to use the
ReferencedLatestFrame as a FrameHandler or implement your own.
use slipmux::Decoder;
use slipmux::DecodeStatus;
use slipmux::ReferencedLatestFrame;
const SLIPMUX_ENCODED: [u8; 15] = [
0xc0, 0x0a,
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21,
0xc0
];
/* In no_std, we have to provide the buffer -> we choose where and how much memory we reserve */
let mut diagnostic_buffer: [u8; 64] = [0; 64];
let mut configuration_buffer: [u8; 64] = [0; 64];
let mut packet_buffer: [u8; 64] = [0; 64];
let mut slipmux = Decoder::new();
let mut handler = ReferencedLatestFrame::new(
&mut diagnostic_buffer,
&mut configuration_buffer,
&mut packet_buffer
);
for byte in SLIPMUX_ENCODED {
match slipmux.decode(byte, &mut handler) {
Ok(DecodeStatus::Incomplete) => {}
Ok(DecodeStatus::FrameCompleteDiagnostic) => {
/* Once we are informed that a frame is ready, we can process it as we please */
assert_eq!(handler.diagnostic_buffer[..handler.index], *b"Hello World!");
/* Since we own the memory, we are responsible for (de-)allocation and reset */
handler.diagnostic_buffer.fill(0);
}
Ok(DecodeStatus::FrameCompleteConfiguration) => {
/* ... do the same or something else for the other frame types */
}
Ok(DecodeStatus::FrameCompleteIp) => {
/* ... */
}
Err(_) => {
/* ... we decide what to do when something goes wrong */
}
}
}
Structs§
- Buffered
Frame Handler - A buffered handler for the
Decoder::decode()function. - Chunked
Encoder - Encoder for a frame.
- Constants
- Magic byte constants used in Slipmux
- Decoder
- Slipmux decoder context
- Owned
Latest Frame - A simple handler for the
Decoder::decode()function. - Referenced
Latest Frame - A simple
no_stdhandler for theDecoder::decode()function.
Enums§
- Decode
Status - The resulting state of the last decoding step
- Error
- Errors encountered in Slipmux.
- Frame
Type - The frame types that Slipmux offers
- Slipmux
- A Slipmux frame and its data
Traits§
- Frame
Handler - Callback handler for the decoder
Functions§
- encode
- Encodes data based on the
FrameTypeinto a frame - encode_
buffered - Encodes
Slipmuxdata into a frame - encode_
configuration - Short hand for
encode(FrameType::Configuration, &packet, buffer) - encode_
diagnostic - Short hand for
encode(FrameType::Diagnostic, text.as_bytes(), buffer) - encode_
packet - Short hand for
encode(FrameType::Ip, &packet, buffer)