mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 10:33:47 +00:00
180 lines
5.1 KiB
C++
180 lines
5.1 KiB
C++
/*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
* LoRa radio base class — all shared state and algorithms.
|
|
*
|
|
* Subclasses (SX126xRadio, LR1110Radio, …) only implement the hw*()
|
|
* primitives that talk to real hardware. Everything else lives here.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <mesh/Radio.h>
|
|
#include <mesh/Board.h>
|
|
#include <NodePrefs.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/device.h>
|
|
#include "radio_common.h"
|
|
|
|
namespace mesh {
|
|
|
|
class LoRaRadioBase : public Radio {
|
|
public:
|
|
LoRaRadioBase(const struct device *lora_dev, MainBoard &board,
|
|
NodePrefs *prefs = nullptr);
|
|
|
|
void setPrefs(NodePrefs *prefs) { _prefs = prefs; }
|
|
|
|
/* Callbacks */
|
|
void setRxCallback(RadioRxCallback cb, void *user_data) {
|
|
_rx_cb = cb;
|
|
_rx_cb_user_data = user_data;
|
|
}
|
|
void setTxDoneCallback(RadioTxDoneCallback cb, void *user_data) {
|
|
_tx_done_cb = cb;
|
|
_tx_done_cb_user_data = user_data;
|
|
}
|
|
|
|
/* Radio interface (all implemented in base) */
|
|
void begin() override;
|
|
void reconfigure();
|
|
void reconfigureWithParams(float freq, float bw, uint8_t sf, uint8_t cr);
|
|
int recvRaw(uint8_t *bytes, int sz) override;
|
|
uint32_t getEstAirtimeFor(int len_bytes) override;
|
|
float packetScore(float snr, int packet_len) override;
|
|
bool startSendRaw(const uint8_t *bytes, int len) override;
|
|
bool isSendComplete() override;
|
|
void onSendFinished() override;
|
|
bool isInRecvMode() const override;
|
|
float getLastRSSI() const override;
|
|
float getLastSNR() const override;
|
|
|
|
/* Packet statistics */
|
|
uint32_t getPacketsRecv() const override { return _packets_recv; }
|
|
uint32_t getPacketsSent() const override { return _packets_sent; }
|
|
uint32_t getPacketsRecvErrors() const override { return _packets_recv_errors; }
|
|
void resetStats() {
|
|
_packets_recv = 0;
|
|
_packets_sent = 0;
|
|
_packets_recv_errors = 0;
|
|
}
|
|
|
|
/* Advanced radio features */
|
|
int getNoiseFloor() const override;
|
|
void triggerNoiseFloorCalibrate(int threshold) override;
|
|
void resetAGC() override;
|
|
bool isReceiving() override;
|
|
|
|
/* Extended API */
|
|
bool isChannelActive(int threshold = 0);
|
|
|
|
/* Power saving */
|
|
void enableRxDutyCycle(bool enable);
|
|
bool isRxDutyCycleEnabled() const { return _rx_duty_cycle_enabled; }
|
|
void setRxBoost(bool enable);
|
|
bool isRxBoostEnabled() const { return _rx_boost_enabled; }
|
|
|
|
protected:
|
|
/* ── Hardware primitives — subclass MUST implement ─────────── */
|
|
|
|
/** Apply lora_modem_config + any chip-specific extras (image cal, etc.) */
|
|
virtual void hwConfigure(const struct lora_modem_config &cfg) = 0;
|
|
|
|
/** Start async receive (lora_recv_async + boost/duty-cycle setup) */
|
|
virtual void hwStartReceive() = 0;
|
|
|
|
/** Cancel current async receive */
|
|
virtual void hwCancelReceive() = 0;
|
|
|
|
/** Start async send — returns 0 on success */
|
|
virtual int hwSendAsync(uint8_t *buf, uint32_t len,
|
|
struct k_poll_signal *sig) = 0;
|
|
|
|
/** Read instantaneous RSSI from hardware */
|
|
virtual int16_t hwGetCurrentRSSI() = 0;
|
|
|
|
/** Check IRQ flags for preamble/header detection */
|
|
virtual bool hwIsPreambleDetected() = 0;
|
|
|
|
/** Set RX LNA boost on/off */
|
|
virtual void hwSetRxBoost(bool enable) = 0;
|
|
|
|
/** Set RX duty cycle on/off (hardware level) */
|
|
virtual void hwSetRxDutyCycle(bool enable) = 0;
|
|
|
|
/** Reset AGC (chip-specific, may be no-op) */
|
|
virtual void hwResetAGC() = 0;
|
|
|
|
/* ── Shared helpers available to subclasses ────────────────── */
|
|
|
|
void buildModemConfig(struct lora_modem_config &cfg, bool tx);
|
|
void configureRx();
|
|
void configureTx();
|
|
void startReceive();
|
|
|
|
/* Subclass begin() should call this to start TX wait thread */
|
|
void startTxThread(k_thread_stack_t *stack, size_t stack_size);
|
|
|
|
const struct device *_dev;
|
|
NodePrefs *_prefs;
|
|
MainBoard *_board;
|
|
volatile bool _in_recv_mode;
|
|
volatile bool _tx_active;
|
|
volatile float _last_rssi;
|
|
volatile float _last_snr;
|
|
|
|
/* RX ring buffer */
|
|
struct RxPacket {
|
|
uint8_t data[256];
|
|
uint16_t len;
|
|
int16_t rssi;
|
|
int8_t snr;
|
|
};
|
|
RxPacket _rx_ring[RX_RING_SIZE];
|
|
volatile uint8_t _rx_head;
|
|
volatile uint8_t _rx_tail;
|
|
|
|
/* TX buffer + signal */
|
|
uint8_t _tx_buf[256];
|
|
struct k_poll_signal _tx_signal;
|
|
|
|
/* Noise floor calibration state */
|
|
int _noise_floor;
|
|
int _calibration_threshold;
|
|
uint8_t _ema_unguarded; /* ticks until next unfiltered sample */
|
|
|
|
/* Power saving */
|
|
bool _rx_duty_cycle_enabled;
|
|
bool _rx_boost_enabled;
|
|
|
|
/* Config cache — skip redundant hwConfigure() on TX↔RX transitions */
|
|
struct lora_modem_config _last_cfg;
|
|
bool _config_cached;
|
|
|
|
/* Static RX callback — passed to lora_recv_async() by subclass hwStartReceive() */
|
|
static void rxCallbackStatic(const struct device *dev, uint8_t *data,
|
|
uint16_t size, int16_t rssi, int8_t snr,
|
|
void *user_data);
|
|
|
|
private:
|
|
/* RX notification callback */
|
|
RadioRxCallback _rx_cb;
|
|
void *_rx_cb_user_data;
|
|
|
|
/* TX done callback */
|
|
RadioTxDoneCallback _tx_done_cb;
|
|
void *_tx_done_cb_user_data;
|
|
|
|
/* TX completion thread */
|
|
static void txWaitThreadFn(void *p1, void *p2, void *p3);
|
|
struct k_thread _tx_wait_thread;
|
|
struct k_sem _tx_start_sem;
|
|
bool _tx_thread_running;
|
|
|
|
/* Packet statistics */
|
|
volatile uint32_t _packets_recv;
|
|
volatile uint32_t _packets_sent;
|
|
volatile uint32_t _packets_recv_errors;
|
|
};
|
|
|
|
} /* namespace mesh */
|