Просмотр исходного кода

Extract serial bridge into dedicated classes

This commit refactors the serial bridge functionality out of the `simple_repeater` example and into a more reusable, object-oriented structure.

An `AbstractBridge` interface has been introduced, along with a concrete `SerialBridge` implementation. This encapsulates all the logic for packet framing, checksum calculation, and serial communication, cleaning up the main example file significantly.

The `simple_repeater` example now instantiates and uses the `SerialBridge` class, resulting in better separation of concerns and improved code organization.
João Brázio 11 месяцев назад
Родитель
Сommit
1948d284a0
4 измененных файлов с 171 добавлено и 98 удалено
  1. 11 98
      examples/simple_repeater/main.cpp
  2. 32 0
      src/helpers/AbstractBridge.h
  3. 98 0
      src/helpers/SerialBridge.cpp
  4. 30 0
      src/helpers/SerialBridge.h

+ 11 - 98
examples/simple_repeater/main.cpp

@@ -79,7 +79,7 @@
 /* ------------------------------ Code -------------------------------- */
 /* ------------------------------ Code -------------------------------- */
 
 
 #ifdef BRIDGE_OVER_SERIAL
 #ifdef BRIDGE_OVER_SERIAL
-#define SERIAL_PKT_MAGIC 0xcafe
+#include "helpers/SerialBridge.h"
 #endif
 #endif
 
 
 #define REQ_TYPE_GET_STATUS          0x01   // same as _GET_STATS
 #define REQ_TYPE_GET_STATUS          0x01   // same as _GET_STATS
@@ -118,6 +118,10 @@ struct ClientInfo {
   #define MAX_CLIENTS           32
   #define MAX_CLIENTS           32
 #endif
 #endif
 
 
+#ifdef BRIDGE_OVER_SERIAL
+AbstractBridge* bridge;
+#endif
+
 struct NeighbourInfo {
 struct NeighbourInfo {
   mesh::Identity id;
   mesh::Identity id;
   uint32_t advert_timestamp;
   uint32_t advert_timestamp;
@@ -256,89 +260,6 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
   #endif
   #endif
   }
   }
 
 
-#ifdef BRIDGE_OVER_SERIAL
-  struct SerialPacket {
-    uint16_t magic, len, crc;
-    uint8_t payload[MAX_TRANS_UNIT];
-    SerialPacket() : magic(SERIAL_PKT_MAGIC), len(0), crc(0) {}
-  };
-
-  // Fletcher-16
-  // https://en.wikipedia.org/wiki/Fletcher%27s_checksum
-  inline static uint16_t fletcher16(const uint8_t *bytes, const size_t len) {
-    uint8_t sum1 = 0, sum2 = 0;
-
-    for (size_t i = 0; i < len; i++) {
-      sum1 = (sum1 + bytes[i]) % 255;
-      sum2 = (sum2 + sum1) % 255;
-    }
-
-    return (sum2 << 8) | sum1;
-  };
-
-  inline void serialBridgeSendPkt(const mesh::Packet *pkt) {
-    SerialPacket spkt;
-    spkt.len = pkt->writeTo(spkt.payload);
-    spkt.crc = fletcher16(spkt.payload, spkt.len);
-    BRIDGE_OVER_SERIAL.write((uint8_t *)&spkt, sizeof(SerialPacket));
-
-#if MESH_PACKET_LOGGING
-    Serial.printf("%s: BRIDGE: TX, len=%d crc=0x%04x\n", getLogDateTime(), spkt.len, spkt.crc);
-#endif
-  }
-
-  inline void serialBridgeReceivePkt() {
-    static constexpr uint16_t size = sizeof(SerialPacket) + 1;
-    static uint8_t buffer[size];
-    static uint16_t tail = 0;
-
-    while (BRIDGE_OVER_SERIAL.available()) {
-      buffer[tail] = (uint8_t)BRIDGE_OVER_SERIAL.read();
-      MESH_DEBUG_PRINT("%02x ", buffer[tail]);
-      tail = (tail + 1) % size;
-
-      // Check for complete packet by looking back to where the magic number should be
-      const uint16_t head = (tail - sizeof(SerialPacket) + size) % size;
-      if ((buffer[head] | (buffer[(head + 1) % size] << 8)) != SERIAL_PKT_MAGIC) {
-        return;
-      }
-
-      uint8_t bytes[MAX_TRANS_UNIT];
-      const uint16_t len = buffer[(head + 2) % size] | (buffer[(head + 3) % size] << 8);
-
-      if (len == 0 || len > sizeof(bytes)) {
-        MESH_DEBUG_PRINTLN("%s: BRIDGE: RX, invalid packet len", getLogDateTime());
-        return;
-      }
-
-      for (size_t i = 0; i < len; i++) {
-        bytes[i] = buffer[(head + 6 + i) % size];
-      }
-
-      const uint16_t crc = buffer[(head + 4) % size] | (buffer[(head + 5) % size] << 8);
-      const uint16_t f16 = fletcher16(bytes, len);
-
-#if MESH_PACKET_LOGGING
-      Serial.printf("%s: BRIDGE: RX, len=%d crc=0x%04x\n", getLogDateTime(), len, crc);
-#endif
-
-      if ((f16 != crc)) {
-        MESH_DEBUG_PRINTLN("%s: BRIDGE: RX, invalid packet checksum", getLogDateTime());
-        return;
-      }
-
-      mesh::Packet *pkt = _mgr->allocNew();
-      if (pkt == NULL) {
-        MESH_DEBUG_PRINTLN("%s: BRIDGE: RX, no unused packets available", getLogDateTime());
-        return;
-      }
-
-      pkt->readFrom(bytes, len);
-      _mgr->queueInbound(pkt, futureMillis(0));
-    }
-  }
-#endif
-
 protected:
 protected:
   float getAirtimeBudgetFactor() const override {
   float getAirtimeBudgetFactor() const override {
     return _prefs.airtime_factor;
     return _prefs.airtime_factor;
@@ -389,7 +310,7 @@ protected:
   void logTx(mesh::Packet* pkt, int len) override {
   void logTx(mesh::Packet* pkt, int len) override {
 #ifdef BRIDGE_OVER_SERIAL
 #ifdef BRIDGE_OVER_SERIAL
     if (!pkt->isMarkedDoNotRetransmit()) {
     if (!pkt->isMarkedDoNotRetransmit()) {
-      serialBridgeSendPkt(pkt);
+      bridge->onPacketTransmitted(pkt);
     }
     }
 #endif
 #endif
     if (_logging) {
     if (_logging) {
@@ -657,6 +578,9 @@ public:
      : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
      : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
       _cli(board, rtc, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4)
       _cli(board, rtc, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4)
   {
   {
+#ifdef BRIDGE_OVER_SERIAL
+    bridge = new SerialBridge(BRIDGE_OVER_SERIAL, _mgr);
+#endif
     memset(known_clients, 0, sizeof(known_clients));
     memset(known_clients, 0, sizeof(known_clients));
     next_local_advert = next_flood_advert = 0;
     next_local_advert = next_flood_advert = 0;
     set_radio_at = revert_radio_at = 0;
     set_radio_at = revert_radio_at = 0;
@@ -858,7 +782,7 @@ public:
 
 
   void loop() {
   void loop() {
 #ifdef BRIDGE_OVER_SERIAL
 #ifdef BRIDGE_OVER_SERIAL
-    serialBridgeReceivePkt();
+    bridge->loop();
 #endif
 #endif
 
 
     mesh::Mesh::loop();
     mesh::Mesh::loop();
@@ -910,18 +834,7 @@ void setup() {
   delay(1000);
   delay(1000);
 
 
 #ifdef BRIDGE_OVER_SERIAL
 #ifdef BRIDGE_OVER_SERIAL
-#if defined(ESP32)
-  BRIDGE_OVER_SERIAL.setPins(BRIDGE_OVER_SERIAL_RX, BRIDGE_OVER_SERIAL_TX);
-#elif defined(RP2040_PLATFORM)
-  BRIDGE_OVER_SERIAL.setRX(BRIDGE_OVER_SERIAL_RX);
-  BRIDGE_OVER_SERIAL.setTX(BRIDGE_OVER_SERIAL_TX);
-#elif defined(STM32_PLATFORM)
-  BRIDGE_OVER_SERIAL.setRx(BRIDGE_OVER_SERIAL_RX);
-  BRIDGE_OVER_SERIAL.setTx(BRIDGE_OVER_SERIAL_TX);
-#else
-#error SerialBridge was not tested on the current platform
-#endif
-  BRIDGE_OVER_SERIAL.begin(115200);
+  bridge->begin();
 #endif
 #endif
 
 
   board.begin();
   board.begin();

+ 32 - 0
src/helpers/AbstractBridge.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include <Mesh.h>
+
+class AbstractBridge {
+public:
+  virtual ~AbstractBridge() {}
+
+  /**
+   * @brief Initializes the bridge.
+   */
+  virtual void begin() = 0;
+
+  /**
+   * @brief A method to be called on every main loop iteration.
+   *        Used for tasks like checking for incoming data.
+   */
+  virtual void loop() = 0;
+
+  /**
+   * @brief A callback that is triggered when the mesh transmits a packet.
+   *        The bridge can use this to forward the packet.
+   * 
+   * @param packet The packet that was transmitted.
+   */
+  virtual void onPacketTransmitted(mesh::Packet* packet) = 0;
+
+  /**
+   * @brief Processes a received packet from the bridge's medium.
+   */
+  virtual void onPacketReceived() = 0;
+};

+ 98 - 0
src/helpers/SerialBridge.cpp

@@ -0,0 +1,98 @@
+#include "SerialBridge.h"
+#include <HardwareSerial.h>
+
+#ifdef BRIDGE_OVER_SERIAL
+
+#define SERIAL_PKT_MAGIC 0xcafe
+
+struct SerialPacket {
+  uint16_t magic, len, crc;
+  uint8_t payload[MAX_TRANS_UNIT];
+  SerialPacket() : magic(SERIAL_PKT_MAGIC), len(0), crc(0) {}
+};
+
+// Fletcher-16
+// https://en.wikipedia.org/wiki/Fletcher%27s_checksum
+inline static uint16_t fletcher16(const uint8_t *bytes, const size_t len) {
+  uint8_t sum1 = 0, sum2 = 0;
+
+  for (size_t i = 0; i < len; i++) {
+    sum1 = (sum1 + bytes[i]) % 255;
+    sum2 = (sum2 + sum1) % 255;
+  }
+
+  return (sum2 << 8) | sum1;
+};
+
+SerialBridge::SerialBridge(Stream& serial, mesh::PacketManager* mgr) : _serial(&serial), _mgr(mgr) {}
+
+void SerialBridge::begin() {
+#if defined(ESP32)
+  ((HardwareSerial*)_serial)->setPins(BRIDGE_OVER_SERIAL_RX, BRIDGE_OVER_SERIAL_TX);
+#elif defined(RP2040_PLATFORM)
+  ((HardwareSerial*)_serial)->setRX(BRIDGE_OVER_SERIAL_RX);
+  ((HardwareSerial*)_serial)->setTX(BRIDGE_OVER_SERIAL_TX);
+#elif defined(STM32_PLATFORM)
+  ((HardwareSerial*)_serial)->setRx(BRIDGE_OVER_SERIAL_RX);
+  ((HardwareSerial*)_serial)->setTx(BRIDGE_OVER_SERIAL_TX);
+#else
+#error SerialBridge was not tested on the current platform
+#endif
+  ((HardwareSerial*)_serial)->begin(115200);
+}
+
+void SerialBridge::onPacketTransmitted(mesh::Packet* packet) {
+  SerialPacket spkt;
+  spkt.len = packet->writeTo(spkt.payload);
+  spkt.crc = fletcher16(spkt.payload, spkt.len);
+  _serial->write((uint8_t *)&spkt, sizeof(SerialPacket));
+}
+
+void SerialBridge::loop() {
+  while (_serial->available()) {
+    onPacketReceived();
+  }
+}
+
+void SerialBridge::onPacketReceived() {
+  static constexpr uint16_t size = sizeof(SerialPacket) + 1;
+  static uint8_t buffer[size];
+  static uint16_t tail = 0;
+
+  buffer[tail] = (uint8_t)_serial->read();
+  tail = (tail + 1) % size;
+
+  // Check for complete packet by looking back to where the magic number should be
+  const uint16_t head = (tail - sizeof(SerialPacket) + size) % size;
+  if ((buffer[head] | (buffer[(head + 1) % size] << 8)) != SERIAL_PKT_MAGIC) {
+    return;
+  }
+
+  uint8_t bytes[MAX_TRANS_UNIT];
+  const uint16_t len = buffer[(head + 2) % size] | (buffer[(head + 3) % size] << 8);
+
+  if (len == 0 || len > sizeof(bytes)) {
+    return;
+  }
+
+  for (size_t i = 0; i < len; i++) {
+    bytes[i] = buffer[(head + 6 + i) % size];
+  }
+
+  const uint16_t crc = buffer[(head + 4) % size] | (buffer[(head + 5) % size] << 8);
+  const uint16_t f16 = fletcher16(bytes, len);
+
+  if ((f16 != crc)) {
+    return;
+  }
+
+  mesh::Packet *new_pkt = _mgr->allocNew();
+  if (new_pkt == NULL) {
+    return;
+  }
+
+  new_pkt->readFrom(bytes, len);
+  _mgr->queueInbound(new_pkt, 0);
+}
+
+#endif

+ 30 - 0
src/helpers/SerialBridge.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "helpers/AbstractBridge.h"
+#include <Stream.h>
+
+#ifdef BRIDGE_OVER_SERIAL
+
+/**
+ * @brief A bridge implementation that uses a serial port to connect two mesh networks.
+ */
+class SerialBridge : public AbstractBridge {
+public:
+  /**
+   * @brief Construct a new Serial Bridge object
+   * 
+   * @param serial The serial port to use for the bridge.
+   * @param mgr A pointer to the packet manager.
+   */
+  SerialBridge(Stream& serial, mesh::PacketManager* mgr);
+  void begin() override;
+  void loop() override;
+  void onPacketTransmitted(mesh::Packet* packet) override;
+  void onPacketReceived() override;
+
+private:
+  Stream* _serial;
+  mesh::PacketManager* _mgr;
+};
+
+#endif