Files
MicrOBU/microbu-esp32c5/firmware/main/serial_link.hpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

72 lines
3.3 KiB
C++

#pragma once
// Serial transport of the station-internal link over the ESP32-C5 native USB Serial/JTAG port.
// Framing is the app's Phase 03 one: [AA][55][type][len LE][payload][crc16 LE] with
// CRC-16/CCITT-FALSE over type+len+payload (implementation/station-link/README.md, "Serial").
// One writer serialises complete frames; ESP_LOG output travels as LOG frames so the byte
// stream never mixes text with a binary frame.
#include <cstddef>
#include <cstdint>
#include <functional>
#include <vector>
namespace microbu::serial {
/// @brief Byte buffer type for frame payloads.
using Bytes = std::vector<std::uint8_t>;
/// @brief The type of a frame. Either Link (link protocol), Test (test channel), or Log (ESP_LOG output).
enum class FrameType : std::uint8_t { LINK = 0x10, TEST = 0x11, LOG = 0x7F };
constexpr std::size_t maximum_payload = 1536;
/// @brief A complete frame with a type and a payload.
struct Frame { FrameType type; Bytes payload; };
/// @brief Computes the CRC-16/CCITT-FALSE checksum over a byte range.
/// @param data Pointer to the first byte to checksum.
/// @param length Number of bytes to checksum.
/// @return Checksum value.
std::uint16_t crc16_ccitt_false(const std::uint8_t* data, std::size_t length);
/// @brief Frames a payload as [AA][55][type][len LE][payload][crc16 LE].
/// @param type Frame type tag.
/// @param payload Payload bytes; must not exceed maximum_payload.
/// @return Encoded frame bytes.
Bytes encode_frame(FrameType type, const Bytes& payload);
/// Byte-at-a-time decoder, same state machine as the app's SerialFrameDecoder.
class Decoder {
public:
using Handler = std::function<void(Frame)>;
/// @brief Feeds raw bytes through the frame state machine, invoking the handler per complete frame.
/// @param data Pointer to the first byte to feed.
/// @param length Number of bytes to feed.
/// @param handler Invoked once per complete, CRC-valid frame; may be called zero or more times.
void feed(const std::uint8_t* data, std::size_t length, const Handler& handler);
/// @return Number of frames rejected for a CRC mismatch so far.
std::uint32_t crc_errors() const { return crc_errors_; }
/// @return Number of frames decoded successfully so far.
std::uint32_t frames() const { return frames_; }
private:
enum class State { SYNC0, SYNC1, TYPE, LEN_LO, LEN_HI, PAYLOAD, CRC_LO, CRC_HI } state_ = State::SYNC0;
std::uint8_t type_ = 0;
std::uint16_t length_ = 0, crc_ = 0;
Bytes payload_;
std::uint32_t crc_errors_ = 0, frames_ = 0;
};
struct Counters { std::uint32_t frames = 0, crc_errors = 0, write_failures = 0; };
/// @brief Installs the USB Serial/JTAG driver, starts the reader task and routes ESP_LOG into LOG frames.
/// @param on_frame Invoked once per complete, CRC-valid frame.
/// @note The handler runs on the reader task; it must only enqueue, never block.
void start(const Decoder::Handler& on_frame);
/// @brief Writes one complete frame (blocking, mutex-protected). Safe from any task.
/// @param type Frame type tag.
/// @param payload Payload bytes; must not exceed maximum_payload.
/// @return false on a full payload, missing driver, lock timeout, or write failure.
bool write(FrameType type, const Bytes& payload);
/// @return Current frame/error counters.
Counters counters();
} // namespace microbu::serial