Transport Layer

Provides the TransportLayer class that exposes methods for sending and receiving serialized data over the USB and UART interfaces.

Description:

The TransportLayer class provides the user-facing API that enables receiving and sending data over the USB or UART serial interfaces. It conducts all necessary operations to properly encode and decode payloads, verify their integrity, and move them to and from the appropriate communication interface buffers.

Packet Anatomy:

This class sends and receives data in the form of packets. Each packet adheres to the following general layout: [START BYTE] [PAYLOAD SIZE] [OVERHEAD BYTE] [PAYLOAD] [DELIMITER BYTE] [CRC CHECKSUM]

Note

All user-facing methods only work with the payload portion of the data packet. The rest of the packet anatomy is controlled internally by the TransportLayer instance.

Warning

This class permanently reserves up to 524 bytes of RAM for the staging buffers and up to 1024 bytes for storing the CRC lookup table. The number of bytes reserved for the staging buffers can be reduced by adjusting the maximum transmission / reception buffer sizes. The number of bytes reserved for the CRC lookup table can be reduced by adjusting the type of the polynomial used for the CRC checksum calculation.

Variables

static uint16_t kSerialBufferSize = 64

Stores the size of the Serial class reception buffer, in bytes, based on the target microcontroller architecture.

template<typename PolynomialType = uint8_t, const uint8_t kMaximumTransmittedPayloadSize = min(kSerialBufferSize - 8, 254), const uint8_t kMaximumReceivedPayloadSize = min(kSerialBufferSize - 8, 254)>
class TransportLayer
#include <transport_layer.h>

Exposes methods for sending and receiving serialized data over the USB and UART communication interfaces.

This class instantiates and manages all library assets used to transcode, validate, and bidirectionally transfer serial data over the target communication interface.

Template Parameters:
  • PolynomialType – The datatype of the polynomial to use for Cyclic Redundancy Check (CRC) checksum computations. This parameter indirectly controls the size of the instance’s CRC lookup table. Valid types are uint8_t, uint16_t, and uint32_t.

  • kMaximumTransmittedPayloadSize – The maximum size of the payload that is expected to be transmitted during runtime. This parameter indirectly controls the size of the instance’s transmission buffer. Must be a value between 1 and 254.

  • kMaximumReceivedPayloadSize – The maximum size of the payload that is expected to be received during runtime. This parameter indirectly controls the size of the instance’s reception buffer. Must be a value between 1 and 254.

Public Functions

inline explicit TransportLayer(Stream &communication_port, const PolynomialType crc_polynomial = 0x07, const PolynomialType crc_initial_value = 0x00, const PolynomialType crc_final_xor_value = 0x00)

Initializes all runtime assets that facilitate data transmission and reception.

Parameters:
  • communication_port – The initialized communication interface instance, such as Serial or USB Serial.

  • crc_polynomial – The polynomial to use for the generation of the CRC lookup table. The polynomial must be standard (non-reflected / non-reversed).

  • crc_initial_value – The value to which the CRC checksum is initialized before calculation.

  • crc_final_xor_value – The value with which the CRC checksum is XORed after calculation.

inline bool Available() const

Evaluates whether the communication interface has received enough bytes to justify reading the incoming packet.

Returns:

true if the communication interface has received enough bytes to likely contain an incoming data packet and false otherwise.

inline void ResetTransmissionBuffer()

Resets the instance’s transmission buffer.

inline void ResetReceptionBuffer()

Resets the instance’s reception buffer.

template<size_t DestinationSize>
inline void CopyTransmissionData(uint8_t (&destination)[DestinationSize])

Copies the contents of the instance’s transmission buffer into the specified destination buffer.

Warning

This method is intended for testing and debugging purposes and should not be used in production runtimes.

Template Parameters:

DestinationSize – The size of the destination buffer, in bytes.

Parameters:

destination – The buffer where to copy the contents of the transmission buffer.

template<size_t DestinationSize>
inline void CopyReceptionData(uint8_t (&destination)[DestinationSize])

Copies the contents of the instance’s reception buffer into the specified destination buffer.

Warning

This method is intended for testing and debugging purposes and should not be used in production runtimes.

Template Parameters:

DestinationSize – The size of the destination buffer, in bytes.

Parameters:

destination – The buffer where to copy the contents of the reception buffer.

inline bool CopyTxBufferPayloadToRxBuffer()

Copies the payload from the instance’s transmission buffer to its reception buffer.

This method only copies the payload. It does not copy the metadata (start byte) or the CRC checksum postamble.

Warning

This method is intended for testing and debugging purposes and should not be used in production runtimes.

Returns:

true if the payload was copied to the reception buffer and false otherwise.

inline uint8_t get_bytes_in_transmission_buffer() const

Returns the size of the payload currently stored in the instance’s transmission buffer, in bytes.

inline uint8_t get_bytes_in_reception_buffer() const

Returns the size of the payload currently stored in the instance’s reception buffer, in bytes.

inline uint8_t get_runtime_status() const

Returns the runtime status of the most recently called method.

inline void SendData()

Packages the data inside the instance’s transmission buffer into a serialized packet and transmits it over the communication interface.

Warning

This method resets the instance’s transmission buffer after transmitting the data, discarding any data stored inside the buffer.

inline bool ReceiveData()

Receives a data packet from the communication interface, verifies its integrity, and decodes its payload into the instance’s reception buffer.

Before attempting to receive the packet, the method uses the Available() method to check whether the communication interface is likely to store a well-formed packet. It is safe to call this method cyclically (as part of a loop) until a packet is received.

Note

The size of the received payload can be queried using the get_bytes_in_reception_buffer() method.

Warning

Calling this method resets the instance’s reception buffer, discarding any unprocessed data.

Returns:

true if the packet was successfully received and unpacked and false otherwise.

template<typename ObjectType>
inline bool WriteData(const ObjectType &object, const uint16_t object_size = sizeof(ObjectType))

Serializes and writes the input object’s data to the end of the payload stored in the instance’s transmission buffer.

Template Parameters:

ObjectType – The datatype of the object to write to the transmission buffer.

Parameters:
  • object – The object to write to the transmission buffer.

  • object_size – The size of the object, in bytes.

Returns:

true if the method successfully writes the object’s data to the transmission buffer and false otherwise.

template<typename ObjectType>
inline bool ReadData(ObjectType &object, const uint16_t object_size = sizeof(ObjectType))

Overwrites the input object’s data with the data from the instance’s reception buffer, consuming (discarding) all read bytes.

This method deserializes the objects stored in the reception buffer as a sequence of bytes. Calling this method consumes the read bytes, making it impossible to retrieve the same data from the reception buffer again.

Template Parameters:

ObjectType – The datatype of the object to read from the reception buffer.

Parameters:
  • object – The object to read from the reception buffer.

  • object_size – The size of the object, in bytes.

Returns:

true if the method successfully reads the object’s data from the reception buffer and false otherwise.

Public Static Functions

static inline uint8_t get_maximum_transmitted_payload_size()

Returns the maximum size of the payload, in bytes, that fits into the instance’s transmission buffer.

static inline uint8_t get_maximum_received_payload_size()

Returns the maximum size of the payload, in bytes, that fits into the instance’s reception buffer.

static inline uint16_t get_transmission_buffer_size()

Returns the size of the instance’s transmission buffer, in bytes.

static inline uint16_t get_reception_buffer_size()

Returns the size of the instance’s reception buffer, in bytes.

Private Functions

inline uint16_t ConstructPacket()

Constructs the serialized packet using the payload stored inside the instance’s transmission buffer.

Returns:

the combined size of the constructed data packet to be transmitted.

inline bool ParsePacket()

Parses the bytes stored in the reception buffer of the communication interface as a serialized packet and stores it in the instance’s reception buffer.

Returns:

true if the packet was successfully parsed into the instance’s reception buffer and false otherwise.

inline bool ValidatePacket()

Validates the packet parsed by the ParsePacket() method and decodes its payload using the COBS scheme.

Returns:

true if the packet’s integrity was verified and its payload was decoded and false otherwise.

Private Members

Stream &_port

The reference to the Stream class instance that works with the communication interface.

COBSProcessor _cobs_processor

The COBSProcessor instance used to encode and decode packets using the COBS scheme.

CRCProcessor<PolynomialType> _crc_processor

The CRCProcessor instance used to calculate CRC checksums for the incoming and outgoing data packets.

uint8_t _transmission_buffer[kTransmissionBufferSize]

The buffer that stages the payload data before it is transmitted.

uint8_t _reception_buffer[kReceptionBufferSize]

The buffer that stores the received data before it is consumed.

uint16_t _consumed_payload_bytes = 0

Tracks the number of received payload bytes that have been consumed via ReadData().

uint8_t _runtime_status = static_cast<uint8_t>(kTransportStatusCodes::kStandby)

Stores the runtime status of the most recently called method.

Private Static Attributes

static uint32_t kTimeout = 10000

The maximum number of microseconds (us) to wait between receiving any two consecutive bytes of the packet before declaring the packet stale. This prevents the runtime from getting stuck in the reception cycle.

static uint8_t kPostambleSize = sizeof(PolynomialType)

Stores the size of the CRC checksum postamble, in bytes.

static uint16_t kMinimumPacketSize = = kBufferLayout::kMinimumPayloadSize + kBufferLayout::kOverheadByteIndex + kPostambleSize

Stores the size of the smallest packet expected to be received at runtime, in bytes.

static uint16_t kTransmissionBufferSize = kMaximumTransmittedPayloadSize + kBufferLayout::kOverheadByteIndex + 2 + kPostambleSize

Stores the size of the instance’s transmission staging buffer, in bytes.

static uint16_t kReceptionBufferSize = kMaximumReceivedPayloadSize + kBufferLayout::kOverheadByteIndex + 2 + kPostambleSize

Stores the size of the instance’s reception staging buffer, in bytes.

COBS Processor

Provides the COBSProcessor class used to encode and decode data payloads during transmission using the Consistent Overhead Byte Stuffing (COBS) scheme.

Reference Implementation:

The implementation in this file is based on the implementation described in the original paper: S. Cheshire and M. Baker, “Consistent overhead byte stuffing,” in IEEE/ACM Transactions on Networking, vol. 7, no. 2, pp. 159-172, April 1999, doi: 10.1109/90.769765.

class COBSProcessor
#include <cobs_processor.h>

Provides methods for encoding and decoding payloads using the Consistent Overhead Byte Stuffing (COBS) scheme.

Warning

This class is intended to be used by the TransportLayer class and should not be used directly by the end-users. It makes specific assumptions about the layout and contents of the processed data buffers that are not verified during runtime and must be enforced through the use of the TransportLayer class.

Public Static Functions

template<const size_t kBufferSize>
static inline uint16_t EncodePayload(uint8_t (&buffer)[kBufferSize])

Uses the COBS scheme to encode the input payload into a packet in-place.

Template Parameters:

kBufferSize – the size of the input buffer array, in bytes.

Parameters:

buffer – the buffer that stores the payload data to be encoded.

Returns:

the size of the encoded packet, in bytes.

template<const size_t kBufferSize>
static inline uint16_t DecodePayload(uint8_t (&buffer)[kBufferSize])

Uses the COBS scheme to decode the payload from the input packet in-place.

Template Parameters:

kBufferSize – the size of the input buffer, in bytes.

Parameters:

buffer – the buffer that stores the packet data from which to decode the payload.

Returns:

the size of the decoded payload in bytes, or 0 if the method fails to decode the payload.

CRC Processor

Provides the CRCProcessor class used to verify transmitted data integrity by calculating the Cyclic Redundancy Check (CRC) checksums for the outgoing and incoming data packets.

Reference Implementation:

The implementation in this file is based on the implementation described in the original paper: W. W. Peterson and D. T. Brown, “Cyclic Codes for Error Detection,” in Proceedings of the IRE, vol. 49, no. 1, pp. 228-235, Jan. 1961, doi: 10.1109/JRPROC.1961.287814.

template<typename PolynomialType>
class CRCProcessor
#include <crc_processor.h>

Provides methods for calculating Cyclic Redundancy Check (CRC) checksums and using them to verify the integrity of the incoming and outgoing data packets.

Note

Each class instance computes a CRC lookup table at initialization. The table reserves 256, 512, or 1024 bytes of memory depending on the type of the CRC polynomial for the entire lifetime of the instance.

Warning

This class is intended to be used by the TransportLayer class and should not be used directly by the end-users. It makes specific assumptions about the layout and contents of the processed data buffers that are not verified during runtime and must be enforced through the use of the TransportLayer class.

Template Parameters:

PolynomialType – The datatype of the CRC polynomial used by the class instance. Valid types are uint8_t, uint16_t, and uint32_t.

Public Functions

inline CRCProcessor(const PolynomialType polynomial, const PolynomialType initial_value, const PolynomialType final_xor_value)

Generates the lookup table used by the instance to speed up future CRC checksum calculations.

Parameters:
  • polynomial – The polynomial to use for the generation of the CRC lookup table. The polynomial must be standard (non-reflected / non-reversed).

  • initial_value – The value to which the CRC checksum is initialized before calculation.

  • final_xor_value – The value with which the CRC checksum is XORed after calculation.

template<const bool kCheck, const size_t kBufferSize>
inline uint16_t CalculateChecksum(uint8_t (&buffer)[kBufferSize])

Calculates the checksum for the data stored in the input buffer.

Depending on configuration, this method either verifies the data’s integrity based on the checksum included with the data or generates and writes the new checksum value to the end of the data’s region.

Template Parameters:
  • kCheck – Determines whether the method is called to verify the incoming packet’s data integrity or to generate and write the CRC checksum to the outgoing packet’s postamble section.

  • kBufferSize – The size of the input buffer.

Parameters:

buffer – The buffer that stores the COBS-encoded packet for which to calculate the checksum.

Returns:

the size of the buffer occupied by the packet’s data and the appended CRC checksum if the method is called to calculate the new CRC checksum. Returns ‘1’ if the method is configured to verify the packet’s data integrity and the data is intact, and ‘0’ otherwise.

inline const PolynomialType *get_crc_table() const

Returns a const pointer to the CRC lookup table used by the instance.

Private Functions

inline void GenerateCRCTable(const PolynomialType polynomial)

Computes the CRC lookup table for the given polynomial and saves it to the _crc_table member.

Parameters:

polynomial – The CRC polynomial to use for table generation.

Private Members

const PolynomialType _initial_value

Stores the initial value used for the CRC checksum calculation.

const PolynomialType _final_xor_value

Stores the final XOR value used for the CRC checksum calculation.

PolynomialType _crc_table[256]

Stores the lookup table used to speed up CRC computation at runtime.

Private Static Attributes

static uint8_t kCRCByteLength = sizeof(PolynomialType)

Stores the size of the CRC polynomial in bytes.

Stream Mock

Provides the StreamMock class used to simulate a Serial Stream interface for testing the TransportLayer class.

template<const uint16_t kBufferSize = 300>
class StreamMock : public Stream
#include <stream_mock.h>

Simulates a Serial Stream interface by publicly exposing reception and transmission buffers for testing.

Note

The instance buffers use int16_t datatype, but consider any value outside the uint8_t range (0 through 255) as invalid.

Template Parameters:

kBufferSize – the size, in elements, to use for the transmission and reception buffers.

Public Functions

inline StreamMock()

Initializes the instance with zeroed transmission and reception buffers.

inline int read() override

Reads one value (‘byte’) from the reception buffer.

Returns:

the read value as a byte-range integer, or -1 if no valid values are available.

inline size_t readBytes(uint8_t *buffer, const size_t length)

Transfers the specified number of values (bytes) from the reception buffer to the input buffer.

Note

Unlike the readBytes() Stream class method, this method does not use a timeout timer and instead runs either until it processes the requested number of elements, an ‘invalid’ value is encountered, or there is no more data to process.

Parameters:
  • buffer – the buffer where to transfer the read bytes.

  • length – the number of bytes to read.

Returns:

the number of bytes read and written to the input buffer or 0 if no valid data was read.

inline size_t write(const uint8_t *buffer, const size_t bytes_to_write) override

Writes the requested number of bytes from the input buffer array to the transmission buffer.

Note

Each writing cycle starts at index 0 of the transmission buffer, overwriting as many indices as necessary to fully consume the input buffer.

Parameters:
  • buffer – the buffer containing the bytes to write.

  • bytes_to_write – the number of bytes to write to the transmission buffer.

Returns:

the number of bytes written to the transmission buffer.

inline size_t write(const uint8_t value) override

Writes the input byte value to the transmission buffer.

Parameters:

value – the value to write.

Returns:

1 if the value was written to the transmission buffer, 0 otherwise.

inline int available() override

Returns the number of elements in the reception buffer available for reading.

Returns:

the number of valid byte-range elements remaining in the reception buffer.

inline int peek() override

Reads a value from the reception buffer without consuming the data.

Returns:

the peeked ‘byte’ value between 0 and 255, or -1 if there are no valid byte-values to read.

inline void flush() override

Simulates the data being sent to the PC (flushed) by resetting the instance’s transmission buffer.

inline void reset()

Resets the instance’s transmission and reception buffers.

virtual ~StreamMock() = default

Defaults the destructor.

Public Members

int16_t rx_buffer[kStreamBufferSize] = {}

Stores the reception buffer data.

int16_t tx_buffer[kStreamBufferSize] = {}

Stores the transmission buffer data.

size_t rx_buffer_index = 0

Tracks the currently evaluated reception buffer index.

size_t tx_buffer_index = 0

Tracks the currently evaluated transmission buffer index.

Public Static Attributes

static uint16_t kStreamBufferSize = kBufferSize

Stores the size of the instance’s reception and transmission buffers, in elements.

Shared Assets

Provides the assets shared between all library components.

Defines

PACKED_STRUCT

Defines the type for a structure that uses the packed memory layout.

Applies to all library structures used in receiving or transmitting data.

namespace axtlmc_shared_assets

Provides all assets (structures, enumerations, functions) that are intended to be shared between library components.

Enums

enum class kTransportStatusCodes : uint8_t

Defines the codes used by the TransportLayer class to indicate the status of all supported data manipulations.

Values:

enumerator kStandby

The value used to initialize the status tracker variable.

enumerator kDecodingFailed

Unable to decode the payload from the received packet.

enumerator kPacketSent

Packet was successfully transmitted.

enumerator kPayloadSizeByteNotFound

Payload size byte was not found in the incoming stream.

enumerator kInvalidPayloadSize

Received payload size is not valid.

enumerator kPacketTimeoutError

Packet parsing failed due to stalling (reception timeout).

enumerator kNoBytesToParse

Stream class reception buffer had no packet bytes to parse.

enumerator kPacketParsed

Packet was successfully parsed.

enumerator kCRCCheckFailed

CRC check failed, the incoming packet is corrupted.

enumerator kPacketReceived

Packet was successfully received.

enumerator kWriteObjectBufferError

Not enough space in the buffer payload region to write the object.

enumerator kObjectWrittenToBuffer

The object has been written to the buffer.

enumerator kReadObjectBufferError

Not enough bytes in the buffer payload region to read the object from.

enumerator kObjectReadFromBuffer

The object has been read from the buffer.

enumerator kDelimiterNotFoundError

Delimiter byte was not found at the end of the packet.

enumerator kDelimiterFoundTooEarlyError

Delimiter byte was found before reaching the end of the packet.

enumerator kPostambleTimeoutError

The Postamble was not received within the specified time frame.

Variables

template<typename T, typename U>
bool is_same_v = is_same<T, U>::value

Provides convenient access to the value of the ‘is_same’ structure.

Enables compile-time type equality checks without explicitly accessing the value member of the is_same struct.

Template Parameters:
  • T – The first type.

  • U – The second type.

struct kBufferLayout
#include <axtlmc_shared_assets.h>

Stores the parameters that jointly define the layout and constraints for the data buffers processed by this library.

The parameters from this structure are used by all classes exposed by the library to determine how to interact with the input data buffers.

Public Static Attributes

static uint8_t kMinimumPayloadSize = 1

Prevents sending or receiving empty payloads.

static uint8_t kMaximumPayloadSize = 254

Caps the maximum size per COBS specification.

static uint8_t kMinimumPacketSize = 3

The smallest valid packet in the protocol.

static uint16_t kMaximumPacketSize = 256

The largest valid packet in the protocol.

static uint8_t kDelimiterByte = 0

The value used as the encoded packet delimiter.

static uint8_t kStartByte = 129

The value used as the packet start byte.

static uint8_t kStartByteIndex = 0

The index of the start byte value.

static uint8_t kPayloadSizeIndex = 1

The index of the payload size value.

static uint8_t kOverheadByteIndex = 2

The index of the overhead byte value.

static uint8_t kPayloadStartIndex = 3

The index of the first payload’s data byte.

template<typename T, typename U>
struct is_same
#include <axtlmc_shared_assets.h>

Determines whether two types are the same.

Compares two types at compile-time.

Template Parameters:
  • T – The first type.

  • U – The second type.

Public Static Attributes

static bool value = false

Determines whether the two template type parameters are identical.

template<typename T>
struct is_same<T, T>
#include <axtlmc_shared_assets.h>

Specializes the ‘is_same’ structure for identical types.

Activates when both type parameters resolve to the same type.

Template Parameters:

T – The type to compare.

Public Static Attributes

static bool value = true

Determines whether the two template type parameters are identical.