Minimal C++ SLIP encoder operating on buffers
The following encoder can be used to encode frames into a byte stream. It operates on complete buffers (i.e. this is not a streaming encoder) but is fast and easy to use.
/*
* Author: Uli Köhler - techoverflow.net
* License: CC0 1.0 Universal
*
* Description:
* This is a C++ implementation of a buffer-based SLIP encoder.
* It can be used to encode frames unambiguously into a stream of bytes.
* The encoder does not use any memory allocation, but instead requires
* the caller to provide a buffer for the encoded data - hence being
* ideally suited for use in embedded systems
*/
#pragma once
#include <cstdint>
#include <cstddef>
#define SLIP_END ((uint8_t)0300) // SLIP end of packet character
#define SLIP_ESC ((uint8_t)0333) // SLIP escape character
#define SLIP_ESCEND ((uint8_t)0334) // Escaped END data byte
#define SLIP_ESCESC ((uint8_t)0335) // Escaped ESC data byte
// Return value of slip_encode_packet if the output buffer is not large enough
#define SLIP_ENCODE_ERROR SIZE_MAX // Maximum value of size_t
/**
* Determine the packet length when sending the given buffer [p] using SLIP.
* This DOES NOT ENCODE ANYTHING, it just determines the length
* which an encoded version of the data would have
* @return The number of bytes a SLIP encoded version of [in] would consume
*/
size_t slip_packet_length(const uint8_t* in, size_t inlen);
/**
* Encode given input data using SLIP, saving it into the given output buffer.
* WARNING! The output buffer MUST have a length of at least the return value of
* slip_packet_len(in, inlen)
* In case the output buffer is not large enough, this function will return SLIP_ENCODE_ERROR and
* the output buffer will be left in an undefined space.
* Take special care that the input data does not change between the calls to
* slip_packet_len() and slip_encode_packet()
* @return The number of bytes in [out], or SLIP_ENCODE_ERROR
*/
size_t slip_encode_packet(const uint8_t* in, size_t inlen, uint8_t* out, size_t outlen);
/*
* Author: Uli Köhler - techoverflow.net
* License: CC0 1.0 Universal
*
* Description:
* This is a C++ implementation of a buffer-based SLIP encoder.
* It can be used to encode frames unambiguously into a stream of bytes.
* The encoder does not use any memory allocation, but instead requires
* the caller to provide a buffer for the encoded data - hence being
* ideally suited for use in embedded systems
*/
#include "SLIPEncoder.hpp"
size_t slip_packet_length(const uint8_t* in, size_t inlen) {
// This variable contains the length of the data
size_t outlen = 0;
const uint8_t* inend = in + inlen; // First character AFTER the
for (; in < inend ; in++) {
switch (*in) {
case SLIP_END: // Need to escape END character to avoid RX seeing end of frame
// Same as "case SLIP_ESC" so just continue.
case SLIP_ESC: // Need to escape ESC character, we'll send
outlen += 2; // Will send ESC + ESCESC
break;
default: // Any other character => will just copy
outlen++; // Will only send the given character
}
}
// + 1: SLIP END bytes
return outlen + 1;
}
size_t slip_encode_packet(const uint8_t* in, size_t inlen, uint8_t* out, size_t outlen) {
// This variable contains the length of the data
uint8_t* out_start = out; // We will increment [out], hence copy the original value.
// Output buffer must be AT LEAST as long as input data (sanity check)
if(outlen < inlen) {
return SLIP_ENCODE_ERROR;
}
uint8_t* outend = out + outlen; // First character AFTER the
const uint8_t* inend = in + inlen; // First character AFTER the
for (; in < inend ; in++) {
switch (*in) {
case SLIP_END: // Need to escape END character to avoid RX seeing end of frame
// Check out of bounds memory acces
if(out + 2 >= outend) {
return SLIP_ENCODE_ERROR;
}
// Copy escaped END character
*out++ = SLIP_ESC;
*out++ = SLIP_ESCEND;
break;
case SLIP_ESC: // Need to escape ESC character, we'll send
// Check out of bounds memory access
if(out + 2 >= outend) {
return SLIP_ENCODE_ERROR;
}
// Copy escaped END character
*out++ = SLIP_ESC;
*out++ = SLIP_ESCESC;
break;
default: // Any other character => just copy the character
if(out + 1 >= outend) {
return SLIP_ENCODE_ERROR;
}
*out++ = *in;
}
}
// Check out of bounds access for END byte
if(out + 1 > outend) { // NOTE: > instead of >= since there is only ONE character to be written
return SLIP_ENCODE_ERROR;
}
// Insert END byte
*out++ = SLIP_END;
// Return number of bytes
return (out - out_start);
}