mirror of
https://github.com/liberatedsystems/RNode_Firmware_CE.git
synced 2025-02-23 16:30:09 -05:00
783 lines
25 KiB
C++
783 lines
25 KiB
C++
// Copyright (c) Sandeep Mistry. All rights reserved.
|
|
// Licensed under the MIT license.
|
|
|
|
// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva
|
|
// Obviously still under the MIT license.
|
|
|
|
#ifndef RADIO_H
|
|
#define RADIO_H
|
|
|
|
#include <Arduino.h>
|
|
#include <SPI.h>
|
|
#include "Interfaces.h"
|
|
#include "Boards.h"
|
|
#include "src/misc/FIFOBuffer.h"
|
|
|
|
#define MAX_PKT_LENGTH 255
|
|
|
|
// TX
|
|
#define PA_OUTPUT_RFO_PIN 0
|
|
#define PA_OUTPUT_PA_BOOST_PIN 1
|
|
|
|
// Default LoRa settings
|
|
#define PHY_HEADER_LORA_SYMBOLS 20
|
|
#define PHY_CRC_LORA_BITS 16
|
|
#define LORA_PREAMBLE_SYMBOLS_MIN 18
|
|
#define LORA_PREAMBLE_TARGET_MS 24
|
|
#define LORA_PREAMBLE_FAST_DELTA 18
|
|
#define LORA_FAST_THRESHOLD_BPS 30E3
|
|
#define LORA_LIMIT_THRESHOLD_BPS 60E3
|
|
|
|
// DCD
|
|
#define STATUS_INTERVAL_MS 3
|
|
#define DCD_SAMPLES 2500
|
|
#define UTIL_UPDATE_INTERVAL_MS 1000
|
|
#define UTIL_UPDATE_INTERVAL (UTIL_UPDATE_INTERVAL_MS/STATUS_INTERVAL_MS)
|
|
#define AIRTIME_LONGTERM 3600
|
|
#define AIRTIME_LONGTERM_MS (AIRTIME_LONGTERM*1000)
|
|
#define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES)
|
|
#define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS)
|
|
#define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS
|
|
|
|
|
|
// CSMA Parameters
|
|
#define CSMA_SIFS_MS 0
|
|
#define CSMA_POST_TX_YIELD_SLOTS 3
|
|
#define CSMA_SLOT_MAX_MS 100
|
|
#define CSMA_SLOT_MIN_MS 24
|
|
#define CSMA_SLOT_MIN_FAST_DELTA 18
|
|
#define CSMA_SLOT_SYMBOLS 12
|
|
#define CSMA_CW_BANDS 4
|
|
#define CSMA_CW_MIN 0
|
|
#define CSMA_CW_PER_BAND_WINDOWS 15
|
|
#define CSMA_BAND_1_MAX_AIRTIME 7
|
|
#define CSMA_BAND_N_MIN_AIRTIME 85
|
|
#define CSMA_INFR_THRESHOLD_DB 12
|
|
|
|
#define LED_ID_TRIG 16
|
|
|
|
#define NOISE_FLOOR_SAMPLES 64
|
|
|
|
#define RSSI_OFFSET 157
|
|
|
|
#define PHY_HEADER_LORA_SYMBOLS 8
|
|
|
|
#define MODEM_TIMEOUT_MULT 1.1
|
|
|
|
// Status flags
|
|
const uint8_t SIG_DETECT = 0x01;
|
|
const uint8_t SIG_SYNCED = 0x02;
|
|
const uint8_t RX_ONGOING = 0x04;
|
|
|
|
// forward declare Utilities.h LED functions
|
|
void led_rx_on();
|
|
void led_rx_off();
|
|
void led_id_on();
|
|
void led_id_off();
|
|
void led_indicate_airtime_lock();
|
|
|
|
void kiss_indicate_channel_stats(uint8_t index);
|
|
void kiss_indicate_csma_stats(uint8_t index);
|
|
|
|
#if PLATFORM == PLATFORM_ESP32
|
|
// get update_lock for ESP32
|
|
extern portMUX_TYPE update_lock;
|
|
#endif
|
|
|
|
class RadioInterface : public Stream {
|
|
public:
|
|
// todo: in the future define _spiModem and _spiSettings from here for inheritence by child classes
|
|
RadioInterface(uint8_t index) : _index(index), _sf(0x07), _radio_locked(false),
|
|
_radio_online(false), _st_airtime_limit(0.0), _lt_airtime_limit(0.0),
|
|
_airtime_lock(false), _airtime(0.0), _longterm_airtime(0.0), _last_packet_cost(0.0),
|
|
_local_channel_util(0.0), _total_channel_util(0.0),
|
|
_longterm_channel_util(0.0), _last_status_update(0),
|
|
_stat_signal_detected(false), _stat_signal_synced(false),_stat_rx_ongoing(false), _last_dcd(0),
|
|
_dcd_count(0), _dcd(false), _dcd_led(false),
|
|
_dcd_waiting(false), _dcd_sample(0),
|
|
_csma_slot_ms(CSMA_SLOT_MIN_MS),
|
|
_preambleLength(LORA_PREAMBLE_SYMBOLS_MIN), _lora_symbol_time_ms(0.0),
|
|
_lora_preamble_time_ms(0), _lora_header_time_ms(0), _lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0),
|
|
_packet{0}, _onReceive(NULL), _txp(0), _ldro(false), _limit_rate(false), _interference_detected(false), _avoid_interference(true), _difs_ms(CSMA_SIFS_MS + 2 * _csma_slot_ms), _difs_wait_start(0), _cw_wait_start(0), _cw_wait_target(0), _cw_wait_passed(0), _csma_cw(-1), _cw_band(1), _cw_min(0), _cw_max(CSMA_CW_PER_BAND_WINDOWS), _noise_floor_sampled(false), _noise_floor_sample(0), _noise_floor_buffer({0}), _noise_floor(-292), _led_id_filter(0), _preamble_detected_at(0) {};
|
|
|
|
virtual int begin() = 0;
|
|
virtual void end() = 0;
|
|
|
|
virtual int beginPacket(int implicitHeader = false) = 0;
|
|
virtual int endPacket() = 0;
|
|
|
|
virtual int packetRssi(uint8_t pkt_snr_raw = 0xFF) = 0;
|
|
virtual int currentRssi() = 0;
|
|
virtual uint8_t packetRssiRaw() = 0;
|
|
virtual uint8_t currentRssiRaw() = 0;
|
|
virtual uint8_t packetSnrRaw() = 0;
|
|
virtual float packetSnr() = 0;
|
|
virtual long packetFrequencyError() = 0;
|
|
|
|
// from Print
|
|
virtual size_t write(uint8_t byte) = 0;
|
|
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
|
|
|
// from Stream
|
|
virtual int available() = 0;
|
|
virtual int read() = 0;
|
|
virtual int peek() = 0;
|
|
virtual void flush() = 0;
|
|
|
|
virtual void onReceive(void(*callback)(uint8_t, int)) = 0;
|
|
|
|
virtual void receive(int size = 0) = 0;
|
|
virtual void standby() = 0;
|
|
virtual void sleep() = 0;
|
|
|
|
virtual bool preInit() = 0;
|
|
virtual int8_t getTxPower() = 0;
|
|
virtual void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN) = 0;
|
|
virtual uint32_t getFrequency() = 0;
|
|
virtual void setFrequency(uint32_t frequency) = 0;
|
|
virtual void setSpreadingFactor(int sf) = 0;
|
|
virtual uint8_t getSpreadingFactor() = 0;
|
|
virtual uint32_t getSignalBandwidth() = 0;
|
|
virtual void setSignalBandwidth(uint32_t sbw) = 0;
|
|
virtual void setCodingRate4(int denominator) = 0;
|
|
virtual uint8_t getCodingRate4() = 0;
|
|
virtual void setPreambleLength(long length) = 0;
|
|
virtual bool dcd() = 0;
|
|
virtual void enableCrc() = 0;
|
|
virtual void disableCrc() = 0;
|
|
virtual void enableTCXO() = 0;
|
|
virtual void disableTCXO() = 0;
|
|
|
|
virtual uint8_t random() = 0;
|
|
|
|
virtual void setSPIFrequency(uint32_t frequency) = 0;
|
|
|
|
void updateBitrate() {
|
|
if (!_radio_online) { _bitrate = 0; }
|
|
else {
|
|
|
|
_lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf));
|
|
_lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0;
|
|
_bitrate = (uint32_t)(_sf * ( (4.0/(float)getCodingRate4()) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0);
|
|
_lora_us_per_byte = 1000000.0/((float)_bitrate/8.0);
|
|
|
|
bool fast_rate = _bitrate > LORA_FAST_THRESHOLD_BPS;
|
|
_limit_rate = _bitrate > LORA_LIMIT_THRESHOLD_BPS;
|
|
|
|
int csma_slot_min_ms = CSMA_SLOT_MIN_MS;
|
|
float lora_preamble_target_ms = LORA_PREAMBLE_TARGET_MS;
|
|
if (fast_rate) { csma_slot_min_ms -= CSMA_SLOT_MIN_FAST_DELTA;
|
|
lora_preamble_target_ms -= LORA_PREAMBLE_FAST_DELTA; }
|
|
|
|
_csma_slot_ms = _lora_symbol_time_ms*CSMA_SLOT_SYMBOLS;
|
|
if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; }
|
|
if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = csma_slot_min_ms; }
|
|
_difs_ms = CSMA_SIFS_MS + 2*_csma_slot_ms;
|
|
|
|
float target_preamble_symbols = lora_preamble_target_ms/_lora_symbol_time_ms;
|
|
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; }
|
|
else { target_preamble_symbols = (ceil)(target_preamble_symbols); }
|
|
|
|
setPreambleLength(target_preamble_symbols);
|
|
_lora_preamble_time_ms = (ceil)(_preambleLength * _lora_symbol_time_ms);
|
|
_lora_header_time_ms = (ceil)(PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms);
|
|
|
|
}
|
|
}
|
|
virtual void handleDio0Rise() = 0;
|
|
virtual bool getPacketValidity() = 0;
|
|
uint32_t getBitrate() { return _bitrate; };
|
|
uint8_t getIndex() { return _index; };
|
|
void setRadioLock(bool lock) { _radio_locked = lock; };
|
|
bool getRadioLock() { return _radio_locked; };
|
|
void setRadioOnline(bool online) { _radio_online = online; };
|
|
bool getRadioOnline() { return _radio_online; };
|
|
void setSTALock(float at) { _st_airtime_limit = at; };
|
|
float getSTALock() { return _st_airtime_limit; };
|
|
void setLTALock(float at) { _lt_airtime_limit = at; };
|
|
float getLTALock() { return _lt_airtime_limit; };
|
|
bool calculateALock() {
|
|
_airtime_lock = false;
|
|
if (_st_airtime_limit != 0.0 && _airtime >= _st_airtime_limit) {
|
|
_airtime_lock = true;
|
|
}
|
|
if (_lt_airtime_limit != 0.0 && _longterm_airtime >= _lt_airtime_limit) {
|
|
_airtime_lock = true;
|
|
}
|
|
return _airtime_lock;
|
|
};
|
|
void updateAirtime() {
|
|
uint16_t cb = current_airtime_bin();
|
|
uint16_t pb = cb-1; if (cb-1 < 0) { pb = AIRTIME_BINS-1; }
|
|
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
|
|
_airtime_bins[nb] = 0;
|
|
_airtime = (float)(_airtime_bins[cb]+_airtime_bins[pb])/(2.0*AIRTIME_BINLEN_MS);
|
|
|
|
uint32_t longterm_airtime_sum = 0;
|
|
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
|
|
longterm_airtime_sum += _airtime_bins[bin];
|
|
}
|
|
_longterm_airtime = (float)longterm_airtime_sum/(float)AIRTIME_LONGTERM_MS;
|
|
|
|
float longterm_channel_util_sum = 0.0;
|
|
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
|
|
longterm_channel_util_sum += _longterm_bins[bin];
|
|
}
|
|
_longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
|
|
|
|
updateCSMAParameters();
|
|
kiss_indicate_channel_stats(_index);
|
|
};
|
|
float getAirtime(uint16_t written) {
|
|
float lora_symbols = 0;
|
|
float packet_cost_ms = 0.0;
|
|
|
|
if (interfaces[_index] == SX1276 || interfaces[_index] == SX1278) {
|
|
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
|
|
lora_symbols /= 4*(_sf-2*_ldro);
|
|
lora_symbols *= getCodingRate4();
|
|
lora_symbols += _preambleLength + 0.25 + 8;
|
|
packet_cost_ms += lora_symbols * _lora_symbol_time_ms;
|
|
}
|
|
else if (interfaces[_index] == SX1262 || interfaces[_index] == SX1280) {
|
|
if (_sf < 7) {
|
|
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + PHY_HEADER_LORA_SYMBOLS);
|
|
lora_symbols /= 4*_sf;
|
|
lora_symbols *= getCodingRate4();
|
|
lora_symbols += _preambleLength + 2.25 + 8;
|
|
packet_cost_ms += lora_symbols * _lora_symbol_time_ms;
|
|
|
|
} else {
|
|
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
|
|
lora_symbols /= 4*(_sf-2*_ldro);
|
|
lora_symbols *= getCodingRate4();
|
|
lora_symbols += _preambleLength + 0.25 + 8;
|
|
packet_cost_ms += lora_symbols * _lora_symbol_time_ms;
|
|
}
|
|
}
|
|
_last_packet_cost = packet_cost_ms;
|
|
return packet_cost_ms;
|
|
}
|
|
void addAirtime() {
|
|
uint16_t cb = current_airtime_bin();
|
|
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
|
|
_airtime_bins[cb] += _last_packet_cost;
|
|
_airtime_bins[nb] = 0;
|
|
};
|
|
void updateModemStatus() {
|
|
#if MCU_VARIANT == MCU_ESP32
|
|
portENTER_CRITICAL(&update_lock);
|
|
#elif MCU_VARIANT == MCU_NRF52
|
|
portENTER_CRITICAL();
|
|
#endif
|
|
|
|
bool carrier_detected = dcd();
|
|
int current_rssi = currentRssi();
|
|
_last_status_update = millis();
|
|
|
|
#if MCU_VARIANT == MCU_ESP32
|
|
portEXIT_CRITICAL(&update_lock);
|
|
#elif MCU_VARIANT == MCU_NRF52
|
|
portEXIT_CRITICAL();
|
|
#endif
|
|
|
|
_interference_detected = !carrier_detected && (current_rssi > (_noise_floor+CSMA_INFR_THRESHOLD_DB));
|
|
if (_interference_detected) { if (_led_id_filter < LED_ID_TRIG) { _led_id_filter += 1; } }
|
|
else { if (_led_id_filter > 0) {_led_id_filter -= 1; } }
|
|
|
|
if (carrier_detected) { _dcd = true; } else { _dcd = false; }
|
|
|
|
_dcd_led = _dcd;
|
|
if (_dcd_led) { led_rx_on(); }
|
|
else {
|
|
if (_interference_detected) {
|
|
if (_led_id_filter >= LED_ID_TRIG && _noise_floor_sampled) { led_id_on(); }
|
|
} else {
|
|
if (_airtime_lock) { led_indicate_airtime_lock(); }
|
|
else { led_rx_off(); led_id_off(); }
|
|
}
|
|
}
|
|
}
|
|
void updateNoiseFloor() {
|
|
int current_rssi = currentRssi();
|
|
if (!_dcd) {
|
|
if (!_noise_floor_sampled || current_rssi < _noise_floor + CSMA_INFR_THRESHOLD_DB) {
|
|
_noise_floor_buffer[_noise_floor_sample] = current_rssi;
|
|
_noise_floor_sample = _noise_floor_sample+1;
|
|
if (_noise_floor_sample >= NOISE_FLOOR_SAMPLES) {
|
|
_noise_floor_sample %= NOISE_FLOOR_SAMPLES;
|
|
_noise_floor_sampled = true;
|
|
}
|
|
|
|
if (_noise_floor_sampled) {
|
|
_noise_floor = 0;
|
|
for (int ni = 0; ni < NOISE_FLOOR_SAMPLES; ni++) { _noise_floor += _noise_floor_buffer[ni]; }
|
|
_noise_floor /= NOISE_FLOOR_SAMPLES;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void checkModemStatus() {
|
|
if (millis()-_last_status_update >= STATUS_INTERVAL_MS) {
|
|
updateModemStatus();
|
|
updateNoiseFloor();
|
|
|
|
_util_samples[_dcd_sample] = _dcd;
|
|
_dcd_sample = (_dcd_sample+1)%DCD_SAMPLES;
|
|
if (_dcd_sample % UTIL_UPDATE_INTERVAL == 0) {
|
|
int util_count = 0;
|
|
for (int ui = 0; ui < DCD_SAMPLES; ui++) {
|
|
if (_util_samples[ui]) util_count++;
|
|
}
|
|
_local_channel_util = (float)util_count / (float)DCD_SAMPLES;
|
|
_total_channel_util = _local_channel_util + _airtime;
|
|
if (_total_channel_util > 1.0) _total_channel_util = 1.0;
|
|
|
|
int16_t cb = current_airtime_bin();
|
|
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
|
|
if (_total_channel_util > _longterm_bins[cb]) _longterm_bins[cb] = _total_channel_util;
|
|
_longterm_bins[nb] = 0.0;
|
|
|
|
updateAirtime();
|
|
}
|
|
}
|
|
};
|
|
void updateCSMAParameters() {
|
|
int airtime_pct = (int)(_airtime*100);
|
|
int new_cw_band = _cw_band;
|
|
|
|
if (airtime_pct <= CSMA_BAND_1_MAX_AIRTIME) { new_cw_band = 1; }
|
|
else {
|
|
int at = airtime_pct + CSMA_BAND_1_MAX_AIRTIME;
|
|
new_cw_band = map(at, CSMA_BAND_1_MAX_AIRTIME, CSMA_BAND_N_MIN_AIRTIME, 2, CSMA_CW_BANDS);
|
|
}
|
|
|
|
if (new_cw_band > CSMA_CW_BANDS) { new_cw_band = CSMA_CW_BANDS; }
|
|
if (new_cw_band != _cw_band) {
|
|
_cw_band = (uint8_t)(new_cw_band);
|
|
_cw_min = (_cw_band-1) * CSMA_CW_PER_BAND_WINDOWS;
|
|
_cw_max = (_cw_band) * CSMA_CW_PER_BAND_WINDOWS - 1;
|
|
kiss_indicate_csma_stats(_index);
|
|
}
|
|
}
|
|
void setDCD(bool dcd) { _dcd = dcd; };
|
|
bool getDCD() { return _dcd; };
|
|
void setDCDWaiting(bool dcd_waiting) { _dcd_waiting = dcd_waiting; };
|
|
bool getDCDWaiting() { return _dcd_waiting; };
|
|
float getAirtime() { return _airtime; };
|
|
float getLongtermAirtime() { return _longterm_airtime; };
|
|
float getTotalChannelUtil() { return _total_channel_util; };
|
|
float getLongtermChannelUtil() { return _longterm_channel_util; };
|
|
void setCSMASlotMS(int slot_size) { _csma_slot_ms = slot_size; };
|
|
int getCSMASlotMS() { return _csma_slot_ms; };
|
|
float getSymbolTime() { return _lora_symbol_time_ms; };
|
|
float getSymbolRate() { return _lora_symbol_rate; };
|
|
long getPreambleLength() { return _preambleLength; };
|
|
void setAvdInterference(bool cfg) { _avoid_interference = cfg; };
|
|
bool getAvdInterference() { return _avoid_interference; };
|
|
bool getInterference() { return _interference_detected; };
|
|
int getNoiseFloor() { return _noise_floor; };
|
|
unsigned long getDifsMS() { return _difs_ms; };
|
|
uint8_t getCWBand() { return _cw_band; };
|
|
uint8_t getCWMin() { return _cw_min; };
|
|
uint8_t getCWMax() { return _cw_max; };
|
|
uint8_t getCW() { return _csma_cw; };
|
|
void setCW(uint8_t cw) { _csma_cw = cw; };
|
|
void setCWWaitTarget(unsigned long target) { _cw_wait_target = target; };
|
|
unsigned long getCWWaitTarget() { return _cw_wait_target; };
|
|
unsigned long getDifsWaitStart() { return _difs_wait_start; };
|
|
void setDifsWaitStart(unsigned long start) { _difs_wait_start = start; };
|
|
unsigned long getCWWaitStart() { return _cw_wait_start; };
|
|
void setCWWaitStart(unsigned long start) { _cw_wait_start = start; };
|
|
void addCWWaitPassed(unsigned long start) { _cw_wait_passed += start; };
|
|
void resetCWWaitPassed() { _cw_wait_passed = 0; };
|
|
bool getCWWaitStatus() { return _cw_wait_passed < _cw_wait_target; };
|
|
bool getLimitRate() { return _limit_rate; };
|
|
protected:
|
|
virtual void explicitHeaderMode() = 0;
|
|
virtual void implicitHeaderMode() = 0;
|
|
|
|
uint8_t _index;
|
|
uint32_t _bitrate;
|
|
int8_t _txp;
|
|
uint8_t _sf;
|
|
bool _radio_locked;
|
|
bool _radio_online;
|
|
float _st_airtime_limit;
|
|
float _lt_airtime_limit;
|
|
bool _airtime_lock;
|
|
uint16_t _airtime_bins[AIRTIME_BINS] = {0};
|
|
uint16_t _longterm_bins[AIRTIME_BINS] = {0};
|
|
float _airtime;
|
|
float _longterm_airtime;
|
|
float _last_packet_cost;
|
|
float _local_channel_util;
|
|
float _total_channel_util;
|
|
float _longterm_channel_util;
|
|
uint32_t _last_status_update;
|
|
bool _stat_signal_detected;
|
|
bool _stat_signal_synced;
|
|
bool _stat_rx_ongoing;
|
|
uint32_t _last_dcd;
|
|
uint16_t _dcd_count;
|
|
bool _dcd;
|
|
bool _dcd_led;
|
|
bool _dcd_waiting;
|
|
bool _util_samples[DCD_SAMPLES] = {false};
|
|
int _dcd_sample;
|
|
long _preambleLength;
|
|
float _lora_symbol_time_ms;
|
|
float _lora_symbol_rate;
|
|
float _lora_us_per_byte;
|
|
long _lora_preamble_time_ms;
|
|
long _lora_header_time_ms;
|
|
bool _ldro;
|
|
bool _limit_rate;
|
|
bool _interference_detected;
|
|
bool _avoid_interference;
|
|
int _csma_slot_ms;
|
|
unsigned long _difs_ms;
|
|
unsigned long _difs_wait_start;
|
|
unsigned long _cw_wait_start;
|
|
unsigned long _cw_wait_target;
|
|
unsigned long _cw_wait_passed;
|
|
int _csma_cw;
|
|
uint8_t _cw_band;
|
|
uint8_t _cw_min;
|
|
uint8_t _cw_max;
|
|
bool _noise_floor_sampled;
|
|
int _noise_floor_sample;
|
|
int _noise_floor_buffer[NOISE_FLOOR_SAMPLES];
|
|
int _noise_floor;
|
|
uint8_t _led_id_filter;
|
|
unsigned long _preamble_detected_at;
|
|
|
|
uint8_t _packet[255];
|
|
void (*_onReceive)(uint8_t, int);
|
|
};
|
|
|
|
class sx126x : public RadioInterface {
|
|
public:
|
|
sx126x(uint8_t index, SPIClass* spi, bool tcxo, bool dio2_as_rf_switch, int ss, int sclk, int mosi, int miso, int reset, int
|
|
dio0, int busy, int rxen);
|
|
|
|
int begin();
|
|
void end();
|
|
|
|
int beginPacket(int implicitHeader = false);
|
|
int endPacket();
|
|
|
|
int packetRssi(uint8_t pkt_snr_raw = 0xFF);
|
|
int currentRssi();
|
|
uint8_t packetRssiRaw();
|
|
uint8_t currentRssiRaw();
|
|
uint8_t packetSnrRaw();
|
|
float packetSnr();
|
|
long packetFrequencyError();
|
|
|
|
// from Print
|
|
size_t write(uint8_t byte);
|
|
size_t write(const uint8_t *buffer, size_t size);
|
|
|
|
// from Stream
|
|
int available();
|
|
int read();
|
|
int peek();
|
|
void flush();
|
|
|
|
void onReceive(void(*callback)(uint8_t, int));
|
|
|
|
void receive(int size = 0);
|
|
void standby();
|
|
void sleep();
|
|
|
|
bool preInit();
|
|
int8_t getTxPower();
|
|
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
|
uint32_t getFrequency();
|
|
void setFrequency(uint32_t frequency);
|
|
void setSpreadingFactor(int sf);
|
|
uint8_t getSpreadingFactor();
|
|
uint32_t getSignalBandwidth();
|
|
void setSignalBandwidth(uint32_t sbw);
|
|
void setCodingRate4(int denominator);
|
|
uint8_t getCodingRate4();
|
|
void setPreambleLength(long length);
|
|
bool dcd();
|
|
void enableCrc();
|
|
void disableCrc();
|
|
void enableTCXO();
|
|
void disableTCXO();
|
|
|
|
|
|
byte random();
|
|
|
|
void setSPIFrequency(uint32_t frequency);
|
|
|
|
void dumpRegisters(Stream& out);
|
|
|
|
void handleDio0Rise();
|
|
private:
|
|
void writeBuffer(const uint8_t* buffer, size_t size);
|
|
void readBuffer(uint8_t* buffer, size_t size);
|
|
void loraMode();
|
|
void rxAntEnable();
|
|
void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
|
|
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
|
|
void setSyncWord(uint16_t sw);
|
|
void waitOnBusy();
|
|
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
|
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
|
void explicitHeaderMode();
|
|
void implicitHeaderMode();
|
|
|
|
|
|
uint8_t readRegister(uint16_t address);
|
|
void writeRegister(uint16_t address, uint8_t value);
|
|
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
|
|
|
static void onDio0Rise();
|
|
|
|
void handleLowDataRate();
|
|
void optimizeModemSensitivity();
|
|
|
|
void reset(void);
|
|
void calibrate(void);
|
|
void calibrate_image(uint32_t frequency);
|
|
bool getPacketValidity();
|
|
|
|
private:
|
|
SPISettings _spiSettings;
|
|
SPIClass* _spiModem;
|
|
int _ss;
|
|
int _sclk;
|
|
int _mosi;
|
|
int _miso;
|
|
int _reset;
|
|
int _dio0;
|
|
int _rxen;
|
|
int _busy;
|
|
uint32_t _frequency;
|
|
uint8_t _bw;
|
|
uint8_t _cr;
|
|
int _packetIndex;
|
|
int _implicitHeaderMode;
|
|
int _payloadLength;
|
|
int _crcMode;
|
|
int _fifo_tx_addr_ptr;
|
|
int _fifo_rx_addr_ptr;
|
|
bool _preinit_done;
|
|
bool _tcxo;
|
|
bool _dio2_as_rf_switch;
|
|
};
|
|
|
|
class sx127x : public RadioInterface {
|
|
public:
|
|
sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy);
|
|
|
|
int begin();
|
|
void end();
|
|
|
|
int beginPacket(int implicitHeader = false);
|
|
int endPacket();
|
|
|
|
int packetRssi(uint8_t pkt_snr_raw = 0xFF);
|
|
int packetRssi();
|
|
int currentRssi();
|
|
uint8_t packetRssiRaw();
|
|
uint8_t currentRssiRaw();
|
|
uint8_t packetSnrRaw();
|
|
float packetSnr();
|
|
long packetFrequencyError();
|
|
|
|
// from Print
|
|
size_t write(uint8_t byte);
|
|
size_t write(const uint8_t *buffer, size_t size);
|
|
|
|
// from Stream
|
|
int available();
|
|
int read();
|
|
int peek();
|
|
void flush();
|
|
|
|
void onReceive(void(*callback)(uint8_t, int));
|
|
|
|
void receive(int size = 0);
|
|
void standby();
|
|
void sleep();
|
|
|
|
bool preInit();
|
|
int8_t getTxPower();
|
|
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
|
uint32_t getFrequency();
|
|
void setFrequency(uint32_t frequency);
|
|
void setSpreadingFactor(int sf);
|
|
uint8_t getSpreadingFactor();
|
|
uint32_t getSignalBandwidth();
|
|
void setSignalBandwidth(uint32_t sbw);
|
|
void setCodingRate4(int denominator);
|
|
uint8_t getCodingRate4();
|
|
void setPreambleLength(long length);
|
|
bool dcd();
|
|
void enableCrc();
|
|
void disableCrc();
|
|
void enableTCXO();
|
|
void disableTCXO();
|
|
|
|
byte random();
|
|
|
|
void setSPIFrequency(uint32_t frequency);
|
|
|
|
void handleDio0Rise();
|
|
bool getPacketValidity();
|
|
private:
|
|
void setSyncWord(uint8_t sw);
|
|
void explicitHeaderMode();
|
|
void implicitHeaderMode();
|
|
|
|
|
|
uint8_t readRegister(uint8_t address);
|
|
void writeRegister(uint8_t address, uint8_t value);
|
|
uint8_t singleTransfer(uint8_t address, uint8_t value);
|
|
|
|
static void onDio0Rise();
|
|
|
|
void handleLowDataRate();
|
|
void optimizeModemSensitivity();
|
|
|
|
private:
|
|
SPISettings _spiSettings;
|
|
SPIClass* _spiModem;
|
|
int _ss;
|
|
int _sclk;
|
|
int _mosi;
|
|
int _miso;
|
|
int _reset;
|
|
int _dio0;
|
|
int _busy;
|
|
uint32_t _frequency;
|
|
int _packetIndex;
|
|
int _implicitHeaderMode;
|
|
bool _preinit_done;
|
|
uint8_t _cr;
|
|
uint32_t _bw;
|
|
};
|
|
|
|
class sx128x : public RadioInterface {
|
|
public:
|
|
sx128x(uint8_t index, SPIClass* spi, bool tcxo, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen, int txen);
|
|
|
|
int begin();
|
|
void end();
|
|
|
|
int beginPacket(int implicitHeader = false);
|
|
int endPacket();
|
|
|
|
int packetRssi(uint8_t pkt_snr_raw = 0xFF);
|
|
int currentRssi();
|
|
uint8_t packetRssiRaw();
|
|
uint8_t currentRssiRaw();
|
|
uint8_t packetSnrRaw();
|
|
float packetSnr();
|
|
long packetFrequencyError();
|
|
|
|
// from Print
|
|
size_t write(uint8_t byte);
|
|
size_t write(const uint8_t *buffer, size_t size);
|
|
|
|
// from Stream
|
|
int available();
|
|
int read();
|
|
int peek();
|
|
void flush();
|
|
|
|
void onReceive(void(*callback)(uint8_t, int));
|
|
|
|
void receive(int size = 0);
|
|
void standby();
|
|
void sleep();
|
|
|
|
bool preInit();
|
|
int8_t getTxPower();
|
|
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
|
uint32_t getFrequency();
|
|
void setFrequency(uint32_t frequency);
|
|
void setSpreadingFactor(int sf);
|
|
uint8_t getSpreadingFactor();
|
|
uint32_t getSignalBandwidth();
|
|
void setSignalBandwidth(uint32_t sbw);
|
|
void setCodingRate4(int denominator);
|
|
uint8_t getCodingRate4();
|
|
void setPreambleLength(long length);
|
|
bool dcd();
|
|
void enableCrc();
|
|
void disableCrc();
|
|
void enableTCXO();
|
|
void disableTCXO();
|
|
|
|
byte random();
|
|
|
|
void setSPIFrequency(uint32_t frequency);
|
|
|
|
void dumpRegisters(Stream& out);
|
|
|
|
void handleDio0Rise();
|
|
|
|
bool getPacketValidity();
|
|
|
|
private:
|
|
void writeBuffer(const uint8_t* buffer, size_t size);
|
|
void readBuffer(uint8_t* buffer, size_t size);
|
|
void txAntEnable();
|
|
void rxAntEnable();
|
|
void loraMode();
|
|
void waitOnBusy();
|
|
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
|
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
|
|
void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
|
|
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr);
|
|
void setSyncWord(int sw);
|
|
void explicitHeaderMode();
|
|
void implicitHeaderMode();
|
|
|
|
|
|
uint8_t readRegister(uint16_t address);
|
|
void writeRegister(uint16_t address, uint8_t value);
|
|
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
|
|
|
static void onDio0Rise();
|
|
|
|
void handleLowDataRate();
|
|
void optimizeModemSensitivity();
|
|
|
|
private:
|
|
SPISettings _spiSettings;
|
|
SPIClass* _spiModem;
|
|
int _ss;
|
|
int _sclk;
|
|
int _mosi;
|
|
int _miso;
|
|
int _reset;
|
|
int _dio0;
|
|
int _rxen;
|
|
int _txen;
|
|
int _busy;
|
|
int _modem;
|
|
uint32_t _frequency;
|
|
uint8_t _bw;
|
|
uint8_t _cr;
|
|
int _packetIndex;
|
|
int _implicitHeaderMode;
|
|
int _payloadLength;
|
|
int _crcMode;
|
|
int _fifo_tx_addr_ptr;
|
|
int _fifo_rx_addr_ptr;
|
|
bool _preinit_done;
|
|
int _rxPacketLength;
|
|
bool _tcxo;
|
|
uint8_t _preamble_e;
|
|
uint8_t _preamble_m;
|
|
uint32_t _last_preamble;
|
|
};
|
|
#endif
|