Sign ITS messages on the ESP32-C5 with vanetza-idf, over USB or BLE
obu-firmware is now a port of the colleague's standalone VRU station (microbu-esp32c5/firmware, kept beside this repository and gitignored): the vanetza-idf C-ITS stack with the TS 103 097 security entity, credentials in NVS, the station-link v1 protocol over the native USB port (frame type 0x10 in the existing 0xAA55 framing) and over a BLE GATT peripheral, and its ITS-G5 radio adapter. The phone still builds CAM and VAM; the board adds GeoNetworking/BTP and signs with the provisioned authorization ticket. The private key never leaves the board. Builds with ESP-IDF 6.0.2 only, which vanetza-idf pins for the radio's private driver ABI. The previous C firmware stays on disk unbuilt; a full-flash backup of the bench board is kept in firmware-backups/ (gitignored). Changed against the colleague's firmware, marked MicrOBU: in the sources: - Reception unchanged for the app. vanetza-idf drops what it cannot verify (unsigned traffic, every RSU), so each captured frame also goes through the previous gn_unwrap.c and reaches the phone as link opcode V2X_RX (0x85), whose body is the old SERIAL_MSG_V2X_RX payload. - Unsigned transmission still possible, with the previous geonet.c header; the phone chooses per message. - Console on UART0 (CH343 port); the native USB port carries only link frames. - BLE advertising pauses while the USB link is in use: BLE and ITS-G5 share one RF front end. - NVS 80 KB (app at 0x20000). At 24 KB, with Wi-Fi settings the previous firmware left behind, the BLE bond could not be stored and the phone had to pair on every connection. - Bench fixes: the radio queue is drained before the first PoTi (no RX and ~177 queue drops before); the station loop waited pdMS_TO_TICKS(5) = 0 ticks at 100 Hz and starved the idle task; the 2.4 KB RX capture buffer is off the Wi-Fi task stack; BLE notifications longer than the MTU are dropped instead of cut short, MTU 517; serial writes are skipped with no USB host. - Manual country policy and TX-power read-back from the previous radio setup; logs for BLE encryption changes and the number of stored bonds. Verified on the bench board (COM3) with the phone over USB and BLE: CAM and VAM, signed and unsigned, go out; reception of the sim car and the RSU's CAM/SPATEM/MAPEM continues; the board survives app restarts and reconnects. See docs/06-signed-its-vam-ble.md.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
#include <vanetza_idf/access.hpp>
|
||||
#include <esp_err.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace microbu {
|
||||
|
||||
struct C5RadioConfig {
|
||||
std::uint16_t channel_number = 180;
|
||||
double transmit_power_dbm = 10.0;
|
||||
unsigned receive_queue_length = 16;
|
||||
bool laboratory_transmission = true;
|
||||
};
|
||||
|
||||
#if CONFIG_MICROBU_TEST_CHANNEL
|
||||
/// Result of polling the PHY's own (undocumented) CCA state as fast as possible for a
|
||||
/// fixed window (feasibility probe for EN 303 797 clause 4.6.2)
|
||||
/// to determine if the platform can observe channel-busy state at >=1 kHz at all.
|
||||
struct CcaSampleResult {
|
||||
std::uint32_t samples = 0;
|
||||
std::uint32_t duration_us = 0;
|
||||
std::uint32_t min_delta_us = 0;
|
||||
std::uint32_t max_delta_us = 0;
|
||||
std::uint32_t busy_count = 0;
|
||||
std::int32_t first_cca = 0;
|
||||
std::int32_t last_cca = 0;
|
||||
std::int32_t noise_floor_dbm = 0;
|
||||
std::int32_t cca_total_cycles_delta = 0; // out[0]/0x600a7c5c: 40 MHz free-running counter
|
||||
std::int32_t cca_busy_cycles_delta = 0; // out[1]/0x600a7c60: increments while channel busy
|
||||
std::int32_t cca_status = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
/// Snapshot of the ESP32-C5 27-bit hardware PHY counters for ETSI TS 102 687 / EN 303 797 DCC.
|
||||
/// total_cycles: 40 MHz FE clock cycles (register 0x600a7c5c[26:0]).
|
||||
/// busy_cycles: cycles during which received RF energy exceeded the CCA threshold (register 0x600a7c60[26:0]).
|
||||
struct CcaCounters {
|
||||
std::uint32_t total_cycles = 0;
|
||||
std::uint32_t busy_cycles = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* ITS-G5 802.11p Radio Access Adapter for ESP32-C5 (EN 303 797 Annex B.2).
|
||||
* Direct Wi-Fi promiscuous RX mode on 5.9 GHz (ITS-G5 Channel 180, 10 MHz BW)
|
||||
* and 802.11p frame transmission via esp_wifi_80211_tx_custom.
|
||||
*/
|
||||
class C5Radio final : public vanetza_idf::Access {
|
||||
public:
|
||||
using Receive = std::function<void(vanetza_idf::AlDataIndication)>;
|
||||
using Capture = std::function<void(const vanetza::ByteBuffer&, int, std::uint32_t)>;
|
||||
|
||||
/// @brief Constructs a radio adapter with the given configuration (not yet started).
|
||||
/// @param config Radio configuration; defaults to channel 180, 10 dBm, 16-deep RX queue.
|
||||
explicit C5Radio(C5RadioConfig config = {});
|
||||
/// @brief Stops the radio and releases all resources.
|
||||
~C5Radio() override;
|
||||
C5Radio(const C5Radio&) = delete;
|
||||
C5Radio& operator=(const C5Radio&) = delete;
|
||||
|
||||
/// @brief Initializes Wi-Fi in promiscuous 802.11p mode and starts the radio.
|
||||
/// @return ESP_OK on success, otherwise an ESP-IDF error code.
|
||||
esp_err_t start();
|
||||
/// @brief Stops the radio and releases all resources.
|
||||
void stop();
|
||||
|
||||
// vanetza_idf::Access
|
||||
/// @brief Encodes and transmits an ITS-G5 frame requested by the access layer.
|
||||
/// @param request Frame and transmit parameters from the access layer.
|
||||
/// @return Result of the transmit attempt.
|
||||
vanetza_idf::Result request(vanetza_idf::AlDataRequest request) override;
|
||||
|
||||
/// @brief Dispatches queued received frames to the owning task callback.
|
||||
/// @param receive Invoked once per queued frame with its decoded indication.
|
||||
/// @param capture Optional; invoked with the raw frame bytes, RSSI and timestamp for diagnostics.
|
||||
void poll(const Receive& receive, const Capture& capture = {});
|
||||
|
||||
#if CONFIG_MICROBU_TEST_CHANNEL
|
||||
/// @brief Sends a burst of raw 802.11p test frames for RF characterization.
|
||||
/// @param channel ITS-G5 channel number to transmit on.
|
||||
/// @param power_dbm Transmit power in dBm.
|
||||
/// @param mcs 802.11p modulation and coding scheme index.
|
||||
/// @param count Number of frames to send.
|
||||
/// @param interval_ms Interval between frames in milliseconds.
|
||||
/// @param payload_len Length of each frame's payload in bytes.
|
||||
/// @return ESP_OK if all frames were sent, otherwise the last transmit error.
|
||||
esp_err_t transmit_burst(std::uint16_t channel, double power_dbm, unsigned mcs,
|
||||
unsigned count, unsigned interval_ms, std::size_t payload_len);
|
||||
|
||||
/// @brief Polls the CCA state as fast as possible for a fixed window (see CcaSampleResult); requires start().
|
||||
/// @note This is a diagnostic tool/ feasibility probe for EN 303 797 clause 4.6.2 to determine if the platform can observe channel-busy state at >=1 kHz at all.
|
||||
/// @param duration_ms Duration of the sampling window in milliseconds.
|
||||
/// @return Sampling statistics and counter deltas over the window.
|
||||
CcaSampleResult sample_cca(unsigned duration_ms);
|
||||
#endif
|
||||
|
||||
/// @brief Non-blocking read of the hardware CCA counters for periodic DCC evaluation.
|
||||
/// Continuous 40 MHz hardware integration satisfies EN 303 797 Profile-1 (>=1 kHz) with zero CPU busy-wait.
|
||||
/// @return Snapshot of total and busy cycle counts.
|
||||
CcaCounters read_cca_counters() const;
|
||||
|
||||
/// @brief Calculates Channel Busy Ratio (CBR) between two counter snapshots: delta(busy) / delta(total).
|
||||
/// @param current More recent counter snapshot.
|
||||
/// @param previous Earlier counter snapshot.
|
||||
/// @return CBR in [0, 1].
|
||||
static double calculate_cbr(const CcaCounters& current, const CcaCounters& previous);
|
||||
|
||||
/// @brief Number of frames dropped since start() due to queue overflow or invalid length.
|
||||
/// @return Dropped frame count.
|
||||
std::uint32_t dropped_frames() const;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
} // namespace microbu
|
||||
Reference in New Issue
Block a user