From 7f78dfb70e1be8bdc92e9da9f78fc4810d1c2bc8 Mon Sep 17 00:00:00 2001 From: John Poole Date: Thu, 28 May 2026 21:23:10 -0700 Subject: [PATCH] Change frame to have prefix showing origin. Tested and all units received from the other tree. I should have committed then, but forgot. Here, the blocking has been activated, but not tested. --- .../204_established_identities/platformio.ini | 2 + .../src/TBeamSupremeLoRaInterface.cpp | 93 ++++++++++++++++--- .../src/TBeamSupremeLoRaInterface.h | 15 ++- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/exercises/204_established_identities/platformio.ini b/exercises/204_established_identities/platformio.ini index 1d5e9d4..4fd19f3 100644 --- a/exercises/204_established_identities/platformio.ini +++ b/exercises/204_established_identities/platformio.ini @@ -50,6 +50,8 @@ build_flags = -D LORA_SYNC_WORD=0x12 -D LORA_TX_POWER_DBM=14 -D USTORE_MAX_VALUE_LEN=1200 + -D SIM_PHY_ENVELOPE=1 + -D SIM_PHY_BLOCK_BOB_CY=1 ; Live announces are enough for this single-hop field exercise. Do not define ; RNS_PERSIST_PATHS here: the LittleFS-backed path_store compactor can leave an ; active segment FD open while unlinking /path_store_*.dat on ESP32. diff --git a/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.cpp b/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.cpp index 80359a2..1f47075 100644 --- a/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.cpp +++ b/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.cpp @@ -17,6 +17,15 @@ #ifndef LORA_BUSY #error "LORA_BUSY not defined" #endif +#ifndef NODE_SLOT_INDEX +#define NODE_SLOT_INDEX 255 +#endif +#ifndef SIM_PHY_ENVELOPE +#define SIM_PHY_ENVELOPE 0 +#endif +#ifndef SIM_PHY_BLOCK_BOB_CY +#define SIM_PHY_BLOCK_BOB_CY 0 +#endif using namespace RNS; @@ -24,7 +33,7 @@ TBeamSupremeLoRaInterface::TBeamSupremeLoRaInterface(const char* name) : Interfa _IN = true; _OUT = true; _bitrate = (double)LORA_SF * ((4.0 / LORA_CR) / (pow(2, LORA_SF) / LORA_BW_KHZ)) * 1000.0; - _HW_MTU = 508; + _HW_MTU = (uint16_t)(LORA_MAX_PAYLOAD * 2); } TBeamSupremeLoRaInterface::~TBeamSupremeLoRaInterface() { @@ -82,13 +91,23 @@ void TBeamSupremeLoRaInterface::loop() { } int len = _radio->getPacketLength(); - uint8_t rx_buf[255]; + uint8_t rx_buf[RADIO_MAX_PAYLOAD]; int state = _radio->readData(rx_buf, len); - if (state == RADIOLIB_ERR_NONE && len > 1) { + if (state == RADIOLIB_ERR_NONE) { _last_rssi = _radio->getRSSI(); _last_snr = _radio->getSNR(); + uint8_t physical_tx = 255; + if (!unpack_frame(rx_buf, len, physical_tx)) { + _radio->startReceive(); + return; + } + if (len <= 1) { + _radio->startReceive(); + return; + } + uint8_t header = rx_buf[0]; uint8_t seq = packet_sequence(header); @@ -118,19 +137,71 @@ void TBeamSupremeLoRaInterface::loop() { _radio->startReceive(); } +int TBeamSupremeLoRaInterface::transmit_frame(uint8_t header, const uint8_t* payload, size_t payload_len) { + uint8_t tx_buf[RADIO_MAX_PAYLOAD]; +#if SIM_PHY_ENVELOPE + tx_buf[0] = PHY_MAGIC_0; + tx_buf[1] = PHY_MAGIC_1; + tx_buf[2] = PHY_VERSION; + tx_buf[3] = (uint8_t)NODE_SLOT_INDEX; + tx_buf[PHY_ENVELOPE_LEN] = header; + memcpy(tx_buf + PHY_ENVELOPE_LEN + 1, payload, payload_len); + return _radio->transmit(tx_buf, PHY_ENVELOPE_LEN + 1 + payload_len); +#else + tx_buf[0] = header; + memcpy(tx_buf + 1, payload, payload_len); + return _radio->transmit(tx_buf, 1 + payload_len); +#endif +} + +bool TBeamSupremeLoRaInterface::unpack_frame(uint8_t* frame, int& len, uint8_t& physical_tx) { +#if SIM_PHY_ENVELOPE + if (len < PHY_ENVELOPE_LEN + 1) { + DEBUGF("SIM PHY malformed: short frame len=%d", len); + return false; + } + if (frame[0] != PHY_MAGIC_0 || frame[1] != PHY_MAGIC_1 || frame[2] != PHY_VERSION) { + DEBUGF("SIM PHY malformed: bad envelope len=%d", len); + return false; + } + physical_tx = frame[3]; + if (should_drop_physical_tx(physical_tx)) { + DEBUGF("SIM PHY DROP: rx=%u tx=%u len=%d", + (unsigned)NODE_SLOT_INDEX, + (unsigned)physical_tx, + len); + return false; + } + len -= PHY_ENVELOPE_LEN; + memmove(frame, frame + PHY_ENVELOPE_LEN, len); + return true; +#else + (void)frame; + physical_tx = 255; + return true; +#endif +} + +bool TBeamSupremeLoRaInterface::should_drop_physical_tx(uint8_t physical_tx) { +#if SIM_PHY_BLOCK_BOB_CY + const uint8_t local = (uint8_t)NODE_SLOT_INDEX; + return (local == 1U && physical_tx == 2U) || (local == 2U && physical_tx == 1U); +#else + (void)physical_tx; + return false; +#endif +} + void TBeamSupremeLoRaInterface::send_outgoing(const Bytes& data) { if (!_online || !_radio) { return; } try { - uint8_t tx_buf[255]; uint8_t rand_nibble = (uint8_t)(Cryptography::randomnum(256)) & 0xF0; if ((int)data.size() <= LORA_MAX_PAYLOAD) { - tx_buf[0] = rand_nibble; - memcpy(tx_buf + 1, data.data(), data.size()); - int state = _radio->transmit(tx_buf, 1 + data.size()); + int state = transmit_frame(rand_nibble, data.data(), data.size()); if (state != RADIOLIB_ERR_NONE) { ERRORF("LoRa transmit failed, code %d", state); } @@ -138,17 +209,13 @@ void TBeamSupremeLoRaInterface::send_outgoing(const Bytes& data) { uint8_t seq = (_tx_seq_ctr++) & HEADER_SEQ_MASK; uint8_t split_header = rand_nibble | HEADER_SPLIT | seq; - tx_buf[0] = split_header; - memcpy(tx_buf + 1, data.data(), LORA_MAX_PAYLOAD); - int state = _radio->transmit(tx_buf, 1 + LORA_MAX_PAYLOAD); + int state = transmit_frame(split_header, data.data(), LORA_MAX_PAYLOAD); if (state != RADIOLIB_ERR_NONE) { ERRORF("LoRa transmit part 1 failed, code %d", state); } size_t remainder = data.size() - LORA_MAX_PAYLOAD; - tx_buf[0] = split_header; - memcpy(tx_buf + 1, data.data() + LORA_MAX_PAYLOAD, remainder); - state = _radio->transmit(tx_buf, 1 + remainder); + state = transmit_frame(split_header, data.data() + LORA_MAX_PAYLOAD, remainder); if (state != RADIOLIB_ERR_NONE) { ERRORF("LoRa transmit part 2 failed, code %d", state); } diff --git a/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.h b/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.h index 701de8a..9b751d6 100644 --- a/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.h +++ b/exercises/204_established_identities/src/TBeamSupremeLoRaInterface.h @@ -22,11 +22,24 @@ public: private: void send_outgoing(const RNS::Bytes& data) override; void on_incoming(const RNS::Bytes& data); + int transmit_frame(uint8_t header, const uint8_t* payload, size_t payload_len); + bool unpack_frame(uint8_t* frame, int& len, uint8_t& physical_tx); + static bool should_drop_physical_tx(uint8_t physical_tx); static constexpr uint8_t HEADER_SPLIT = 0x08; static constexpr uint8_t HEADER_SEQ_MASK = 0x07; static constexpr uint8_t SEQ_UNSET = 0xFF; - static constexpr int LORA_MAX_PAYLOAD = 254; + static constexpr int RADIO_MAX_PAYLOAD = 255; +#if defined(SIM_PHY_ENVELOPE) && SIM_PHY_ENVELOPE + static constexpr uint8_t PHY_MAGIC_0 = 0xC2; + static constexpr uint8_t PHY_MAGIC_1 = 0x04; + static constexpr uint8_t PHY_VERSION = 0x01; + static constexpr int PHY_ENVELOPE_LEN = 4; + static constexpr int LORA_MAX_PAYLOAD = RADIO_MAX_PAYLOAD - PHY_ENVELOPE_LEN - 1; +#else + static constexpr int PHY_ENVELOPE_LEN = 0; + static constexpr int LORA_MAX_PAYLOAD = RADIO_MAX_PAYLOAD - 1; +#endif static bool is_split_packet(uint8_t header) { return (header & HEADER_SPLIT) != 0; } static uint8_t packet_sequence(uint8_t header) { return header & HEADER_SEQ_MASK; }