Crate slipmux

Crate slipmux 

Source
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§

BufferedFrameHandler
A buffered handler for the Decoder::decode() function.
ChunkedEncoder
Encoder for a frame.
Constants
Magic byte constants used in Slipmux
Decoder
Slipmux decoder context
OwnedLatestFrame
A simple handler for the Decoder::decode() function.
ReferencedLatestFrame
A simple no_std handler for the Decoder::decode() function.

Enums§

DecodeStatus
The resulting state of the last decoding step
Error
Errors encountered in Slipmux.
FrameType
The frame types that Slipmux offers
Slipmux
A Slipmux frame and its data

Traits§

FrameHandler
Callback handler for the decoder

Functions§

encode
Encodes data based on the FrameType into a frame
encode_buffered
Encodes Slipmux data 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)