Inital RadioLib support

This commit is contained in:
jacob.eva 2024-10-03 19:26:51 +01:00
parent 2cdf2951e6
commit f93c400eef
No known key found for this signature in database
GPG Key ID: 0B92E083BBCCAA1E
9 changed files with 886 additions and 3686 deletions

View File

@ -699,7 +699,7 @@
#define HAS_PMU true
#define HAS_NP false
#define HAS_SD false
#define CONFIG_UART_BUFFER_SIZE 40000
#define CONFIG_UART_BUFFER_SIZE 6144
#define CONFIG_QUEUE_0_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200
#define EEPROM_SIZE 296
@ -711,7 +711,7 @@
#define INTERFACE_COUNT 1
// first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
@ -738,10 +738,10 @@
#elif BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_14 || BOARD_VARIANT == MODEL_21
#define INTERFACE_COUNT 2
#define CONFIG_QUEUE_1_SIZE 40000
#define CONFIG_QUEUE_1_SIZE 37500
// first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X};
const uint8_t interfaces[INTERFACE_COUNT] = {INT_SX1262, INT_SX1280};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{

View File

@ -15,6 +15,7 @@
#include "ROM.h"
#include "Boards.h"
#include <RadioLib.h>
#ifndef CONFIG_H
#define CONFIG_H
@ -95,10 +96,6 @@
bool serial_in_frame = false;
FIFOBuffer packet_rdy_interfaces;
uint8_t packet_rdy_interfaces_buf[MAX_INTERFACES];
// Incoming packet buffer
uint8_t pbuf[MTU];
@ -141,7 +138,57 @@
// Subinterfaces
// select interface 0 by default
uint8_t interface = 0;
RadioInterface* selected_radio;
RadioInterface* interface_obj[INTERFACE_COUNT];
RadioInterface* interface_obj_sorted[INTERFACE_COUNT];
PhysicalLayer* selected_radio;
PhysicalLayer* interface_obj[INTERFACE_COUNT];
PhysicalLayer* interface_obj_sorted[INTERFACE_COUNT];
// \todo move to another file
struct radio_vars {
bool radio_locked = false;
bool radio_online = false;
float st_airtime_limit = 0.0;
float lt_airtime_limit = 0.0;
bool airtime_lock = false;
uint16_t airtime_bins[AIRTIME_BINS] = {0};
uint16_t longterm_bins[AIRTIME_BINS] = {0};
float airtime = 0.0;
float longterm_airtime = 0.0;
float local_channel_util = 0.0;
float total_channel_util = 0.0;
float longterm_channel_util = 0.0;
uint32_t last_status_update = 0;
bool stat_signal_detected = false;
bool stat_signal_synced = false;
bool stat_rx_ongoing = false;
uint32_t last_dcd = 0;
uint16_t dcd_count = 0;
bool dcd = false;
bool dcd_led = false;
bool dcd_waiting = false;
long dcd_wait_until = 0;
bool util_samples[DCD_SAMPLES] = {false};
int dcd_sample = 0;
uint32_t post_tx_yield_timeout = 0;
uint8_t csma_p = 0;
int csma_slot_ms = 50;
float csma_p_min = 0.1;
float csma_p_max = 0.8;
long preamble_length = 0;
float lora_symbol_time_ms = 0.0;
float lora_symbol_rate = 0.0;
float lora_us_per_byte = 0.0;
uint32_t bitrate = 0;
int8_t txp = 0;
uint8_t sf = 0;
uint8_t cr = 0;
float bw = 0.0;
float freq = 0.0;
};
struct radio_vars radio_details[INTERFACE_COUNT];
SX1280* sx1280_interfaces[INTERFACE_COUNT];
SX1262* sx1262_interfaces[INTERFACE_COUNT];
volatile bool tx_flag = false;
#endif

View File

@ -378,11 +378,11 @@ void draw_bt_icon(int px, int py) {
}
}
void draw_lora_icon(RadioInterface* radio, int px, int py) {
void draw_lora_icon(uint8_t index, int px, int py) {
// todo: make display show other interfaces
if (radio_online) {
#if DISPLAY == OLED
if (online_interface_list[interface_page] != radio->getIndex()) {
if (online_interface_list[interface_page] != index) {
stat_area.drawBitmap(px - 1, py-1, bm_dot_sqr, 18, 19, SSD1306_WHITE, SSD1306_BLACK);
// redraw stat area on next refresh
@ -394,13 +394,13 @@ void draw_lora_icon(RadioInterface* radio, int px, int py) {
stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
}
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
if (online_interface_list[interface_page] != radio->getIndex()) {
if (online_interface_list[interface_page] != index) {
stat_area.drawBitmap(px - 2, py - 2, bm_dot_sqr, 34, 36, GxEPD_WHITE, GxEPD_BLACK);
// redraw stat area on next refresh
stat_area_initialised = false;
}
if (radio->getRadioOnline()) {
if (radio_details[index].radio_online) {
stat_area.drawBitmap(px, py, bm_rf+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
} else {
stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK);
@ -417,7 +417,7 @@ void draw_lora_icon(RadioInterface* radio, int px, int py) {
void draw_mw_icon(int px, int py) {
if (INTERFACE_COUNT >= 2) {
if (interface_obj[1]->getRadioOnline()) {
if (radio_details[1].radio_online) {
#if DISPLAY == OLED
stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
@ -527,7 +527,7 @@ void draw_battery_bars(int px, int py) {
void draw_quality_bars(int px, int py) {
signed char t_snr = (signed int)last_snr_raw;
int snr_int = (int)t_snr;
float snr_min = Q_SNR_MIN_BASE-(int)interface_obj[interface_page]->getSpreadingFactor()*Q_SNR_STEP;
float snr_min = Q_SNR_MIN_BASE-(int)radio_details[interface_page].sf*Q_SNR_STEP;
float snr_span = (Q_SNR_MAX-snr_min);
float snr = ((int)snr_int) * 0.25;
float quality = ((snr-snr_min)/(snr_span))*100;
@ -641,7 +641,8 @@ void draw_signal_bars(int px, int py) {
#define WF_PIXEL_WIDTH 22
#endif
void draw_waterfall(int px, int py) {
int rssi_val = interface_obj[interface_page]->currentRssi();
// \todo, this may not work, check
int rssi_val = interface_obj[interface_page]->getRSSI();
if (rssi_val < WF_RSSI_MIN) rssi_val = WF_RSSI_MIN;
if (rssi_val > WF_RSSI_MAX) rssi_val = WF_RSSI_MAX;
int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH;
@ -681,9 +682,9 @@ void draw_stat_area() {
if (millis()-last_interface_page_flip >= page_interval) {
int online_interfaces_check = 0;
// todo, is there a more efficient way of doing this?
// \todo, is there a more efficient way of doing this?
for (int i = 0; i < INTERFACE_COUNT; i++) {
if (interface_obj[i]->getRadioOnline()) {
if (radio_details[i].radio_online) {
online_interfaces_check++;
}
}
@ -701,7 +702,7 @@ void draw_stat_area() {
uint8_t index = 0;
for (int i = 0; i < INTERFACE_COUNT; i++) {
if (interface_obj[i]->getRadioOnline()) {
if (radio_details[i].radio_online) {
online_interface_list[index] = i;
index++;
}
@ -716,27 +717,27 @@ void draw_stat_area() {
#if DISPLAY == OLED
draw_cable_icon(3, 8);
draw_bt_icon(3, 30);
draw_lora_icon(interface_obj[0], 45, 8);
draw_lora_icon(0, 45, 8);
// todo, expand support to show more than two interfaces on screen
if (INTERFACE_COUNT > 1) {
draw_lora_icon(interface_obj[1], 45, 30);
draw_lora_icon(1, 45, 30);
}
draw_battery_bars(4, 58);
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
draw_cable_icon(6, 18);
draw_bt_icon(6, 60);
draw_lora_icon(interface_obj[0], 86, 18);
draw_lora_icon(0, 86, 18);
// todo, expand support to show more than two interfaces on screen
if (INTERFACE_COUNT > 1) {
draw_lora_icon(interface_obj[1], 86, 60);
draw_lora_icon(1, 86, 60);
}
draw_battery_bars(8, 113);
#endif
radio_online = false;
for (int i = 0; i < INTERFACE_COUNT; i++) {
if (interface_obj[i]->getRadioOnline()) {
if (radio_details[i].radio_online) {
radio_online = true;
break;
}
@ -876,7 +877,6 @@ void draw_disp_area() {
disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, SSD1306_BLACK, SSD1306_WHITE);
#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
selected_radio = interface_obj[online_interface_list[interface_page]];
disp_area.fillRect(0,12,disp_area.width(),57, GxEPD_BLACK); disp_area.fillRect(0,69,disp_area.width(),56, GxEPD_WHITE);
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(GxEPD_WHITE);
disp_area.setTextSize(2); // scale text 2x
@ -886,25 +886,25 @@ void draw_disp_area() {
disp_area.setCursor(14*2, 22);
disp_area.print("@");
disp_area.setCursor(21*2, 22);
disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0);
disp_area.printf("%.1fKbps", (float)(radio_details[online_interface_list[interface_page]].bitrate)/1000.0);
disp_area.setCursor(2, 36);
disp_area.print("Airtime:");
disp_area.setCursor(7+12, 53);
if (selected_radio->getTotalChannelUtil() < 0.099) {
disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0);
if (radio_details[online_interface_list[interface_page]].total_channel_util < 0.099) {
disp_area.printf("%.1f%%", radio_details[online_interface_list[interface_page]].airtime*100.0);
} else {
disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0);
disp_area.printf("%.0f%%", radio_details[online_interface_list[interface_page]].airtime*100.0);
}
disp_area.drawBitmap(2, 41, bm_hg_low, 10, 18, GxEPD_WHITE, GxEPD_BLACK);
disp_area.setCursor(64+17, 53);
if (selected_radio->getLongtermChannelUtil() < 0.099) {
disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0);
if (radio_details[online_interface_list[interface_page]].longterm_channel_util < 0.099) {
disp_area.printf("%.1f%%", radio_details[online_interface_list[interface_page]].longterm_airtime*100.0);
} else {
disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0);
disp_area.printf("%.0f%%", radio_details[online_interface_list[interface_page]].longterm_airtime*100.0);
}
disp_area.drawBitmap(64, 41, bm_hg_high, 10, 18, GxEPD_WHITE, GxEPD_BLACK);
@ -916,18 +916,18 @@ void draw_disp_area() {
disp_area.print("Load:");
disp_area.setCursor(7+12, 110);
if (selected_radio->getTotalChannelUtil() < 0.099) {
disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0);
if (radio_details[online_interface_list[interface_page]].total_channel_util < 0.099) {
disp_area.printf("%.1f%%", radio_details[online_interface_list[interface_page]].total_channel_util*100.0);
} else {
disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0);
disp_area.printf("%.0f%%", radio_details[online_interface_list[interface_page]].total_channel_util*100.0);
}
disp_area.drawBitmap(2, 98, bm_hg_low, 10, 18, GxEPD_BLACK, GxEPD_WHITE);
disp_area.setCursor(64+17, 110);
if (selected_radio->getLongtermChannelUtil() < 0.099) {
disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0);
if (radio_details[online_interface_list[interface_page]].longterm_channel_util < 0.099) {
disp_area.printf("%.1f%%", radio_details[online_interface_list[interface_page]].longterm_channel_util*100.0);
} else {
disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0);
disp_area.printf("%.0f%%", radio_details[online_interface_list[interface_page]].longterm_channel_util*100.0);
}
disp_area.drawBitmap(64, 98, bm_hg_high, 10, 18, GxEPD_BLACK, GxEPD_WHITE);
#endif

View File

@ -15,7 +15,7 @@
#ifndef FRAMING_H
#define FRAMING_H
#define CMD_DEBUG 0xFD
#define FEND 0xC0
#define FESC 0xDB
#define TFEND 0xDC
@ -80,7 +80,7 @@
#define CMD_INT1_DATA 0x10
#define CMD_INT2_DATA 0x20
#define CMD_INT3_DATA 0x70
#define CMD_INT4_DATA 0x80
#define CMD_INT4_DATA 0x75
#define CMD_INT5_DATA 0x90
#define CMD_INT6_DATA 0xA0
#define CMD_INT7_DATA 0xB0
@ -92,8 +92,8 @@
#define CMD_SEL_INT0 0x1E
#define CMD_SEL_INT1 0x1F
#define CMD_SEL_INT2 0x2F
#define CMD_SEL_INT3 0x7F
#define CMD_SEL_INT4 0x8F
#define CMD_SEL_INT3 0x74
#define CMD_SEL_INT4 0x7F
#define CMD_SEL_INT5 0x9F
#define CMD_SEL_INT6 0xAF
#define CMD_SEL_INT7 0xBF

View File

@ -1,7 +1,7 @@
#define SX127X 0x00
#define SX1276 0x01
#define SX1278 0x02
#define SX126X 0x10
#define SX1262 0x11
#define SX128X 0x20
#define SX1280 0x21
#define INT_SX127X 0x00
#define INT_SX1276 0x01
#define INT_SX1278 0x02
#define INT_SX126X 0x10
#define INT_SX1262 0x11
#define INT_SX128X 0x20
#define INT_SX1280 0x21

File diff suppressed because it is too large Load Diff

2663
Radio.cpp

File diff suppressed because it is too large Load Diff

607
Radio.hpp
View File

@ -9,6 +9,7 @@
#include <Arduino.h>
#include <SPI.h>
#include <RadioLib.h>
#include "Interfaces.h"
#include "Boards.h"
#include "src/misc/FIFOBuffer.h"
@ -59,610 +60,4 @@ void led_indicate_airtime_lock();
// 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), _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),
_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_wait_until(0), _dcd_sample(0),
_post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p_min(0.1),
_csma_p_max(0.8), _preambleLength(6), _lora_symbol_time_ms(0.0),
_lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0),
_packet{0}, _onReceive(NULL) {};
virtual int begin() = 0;
virtual void end() = 0;
virtual int beginPacket(int implicitHeader = false) = 0;
virtual int endPacket() = 0;
virtual int packetRssi() = 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 uint8_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 uint8_t modemStatus() = 0;
virtual void enableCrc() = 0;
virtual void disableCrc() = 0;
virtual void enableTCXO() = 0;
virtual void disableTCXO() = 0;
virtual byte random() = 0;
virtual void setSPIFrequency(uint32_t frequency) = 0;
virtual void updateBitrate() = 0;
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;
updateCSMAp();
//kiss_indicate_channel_stats(); // todo: enable me!
};
void addAirtime(uint16_t written) {
float packet_cost_ms = 0.0;
float payload_cost_ms = ((float)written * _lora_us_per_byte)/1000.0;
packet_cost_ms += payload_cost_ms;
packet_cost_ms += (_preambleLength+4.25)*_lora_symbol_time_ms;
packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms;
uint16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
_airtime_bins[cb] += packet_cost_ms;
_airtime_bins[nb] = 0;
};
void checkModemStatus() {
if (millis()-_last_status_update >= STATUS_INTERVAL_MS) {
updateModemStatus();
_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 updateModemStatus() {
#if PLATFORM == PLATFORM_ESP32
portENTER_CRITICAL(&update_lock);
#elif PLATFORM == PLATFORM_NRF52
portENTER_CRITICAL();
#endif
uint8_t status = modemStatus();
_last_status_update = millis();
#if PLATFORM == PLATFORM_ESP32
portEXIT_CRITICAL(&update_lock);
#elif PLATFORM == PLATFORM_NRF52
portEXIT_CRITICAL();
#endif
if ((status & SIG_DETECT) == SIG_DETECT) { _stat_signal_detected = true; } else { _stat_signal_detected = false; }
if ((status & SIG_SYNCED) == SIG_SYNCED) { _stat_signal_synced = true; } else { _stat_signal_synced = false; }
if ((status & RX_ONGOING) == RX_ONGOING) { _stat_rx_ongoing = true; } else { _stat_rx_ongoing = false; }
// if (stat_signal_detected || stat_signal_synced || stat_rx_ongoing) {
if (_stat_signal_detected || _stat_signal_synced) {
if (_stat_rx_ongoing) {
if (_dcd_count < DCD_THRESHOLD) {
_dcd_count++;
} else {
_last_dcd = _last_status_update;
_dcd_led = true;
_dcd = true;
}
}
} else {
if (_dcd_count == 0) {
_dcd_led = false;
} else if (_dcd_count > DCD_LED_STEP_D) {
_dcd_count -= DCD_LED_STEP_D;
} else {
_dcd_count = 0;
}
if (_last_status_update > _last_dcd+_csma_slot_ms) {
_dcd = false;
_dcd_led = false;
_dcd_count = 0;
}
}
if (_dcd_led) {
led_rx_on();
} else {
if (_airtime_lock) {
led_indicate_airtime_lock();
} else {
led_rx_off();
}
}
};
void setPostTxYieldTimeout(uint32_t timeout) { _post_tx_yield_timeout = timeout; };
uint32_t getPostTxYieldTimeout() { return _post_tx_yield_timeout; };
void setDCD(bool dcd) { _dcd = dcd; };
bool getDCD() { return _dcd; };
void setDCDWaiting(bool dcd_waiting) { _dcd_waiting = dcd_waiting; };
bool getDCDWaiting() { return _dcd_waiting; };
void setDCDWaitUntil(uint32_t dcd_wait_until) { _dcd_wait_until = dcd_wait_until; };
bool getDCDWaitUntil() { return _dcd_wait_until; };
float getAirtime() { return _airtime; };
float getLongtermAirtime() { return _longterm_airtime; };
float getTotalChannelUtil() { return _total_channel_util; };
float getLongtermChannelUtil() { return _longterm_channel_util; };
float CSMASlope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); };
void updateCSMAp() {
_csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime)))*255.0);
};
uint8_t getCSMAp() { return _csma_p; };
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; };
protected:
virtual void explicitHeaderMode() = 0;
virtual void implicitHeaderMode() = 0;
uint8_t _index;
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 _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;
long _dcd_wait_until;
bool _util_samples[DCD_SAMPLES] = {false};
int _dcd_sample;
uint32_t _post_tx_yield_timeout;
uint8_t _csma_p;
int _csma_slot_ms;
float _csma_p_min;
float _csma_p_max;
long _preambleLength;
float _lora_symbol_time_ms;
float _lora_symbol_rate;
float _lora_us_per_byte;
uint32_t _bitrate;
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();
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();
uint8_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);
uint8_t modemStatus();
void enableCrc();
void disableCrc();
void enableTCXO();
void disableTCXO();
byte random();
void setSPIFrequency(uint32_t frequency);
void dumpRegisters(Stream& out);
void updateBitrate();
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;
int _txp;
uint8_t _sf;
uint8_t _bw;
uint8_t _cr;
uint8_t _ldro;
int _packetIndex;
int _implicitHeaderMode;
int _payloadLength;
int _crcMode;
int _fifo_tx_addr_ptr;
int _fifo_rx_addr_ptr;
bool _preinit_done;
uint8_t _index;
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();
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();
uint8_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);
uint8_t modemStatus();
void enableCrc();
void disableCrc();
void enableTCXO();
void disableTCXO();
byte random();
void setSPIFrequency(uint32_t frequency);
void updateBitrate();
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 _index;
uint8_t _sf;
uint8_t _cr;
};
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();
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();
uint8_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);
uint8_t modemStatus();
void enableCrc();
void disableCrc();
void enableTCXO();
void disableTCXO();
byte random();
void setSPIFrequency(uint32_t frequency);
void dumpRegisters(Stream& out);
void updateBitrate();
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;
int _txp;
uint8_t _sf;
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;
uint8_t _index;
bool _tcxo;
};
#endif

View File

@ -20,6 +20,10 @@
#include <algorithm>
#include <iterator>
// For CSMA
#define _e 2.71828183
#define _S 10.0
#if HAS_EEPROM
#include <EEPROM.h>
#elif PLATFORM == PLATFORM_NRF52
@ -565,16 +569,9 @@ int8_t led_standby_direction = 0;
#endif
#endif
bool interface_bitrate_cmp(RadioInterface* p, RadioInterface* q) {
long p_bitrate = p->getBitrate();
long q_bitrate = q->getBitrate();
return p_bitrate > q_bitrate;
}
// Sort interfaces in descending order according to bitrate.
void sort_interfaces() {
std::sort(std::begin(interface_obj_sorted), std::end(interface_obj_sorted), interface_bitrate_cmp);
//std::sort(std::begin(interface_obj_sorted), std::end(interface_obj_sorted), interface_bitrate_cmp);
}
void serial_write(uint8_t byte) {
@ -621,10 +618,10 @@ void kiss_indicate_error(uint8_t error_code) {
serial_write(FEND);
}
void kiss_indicate_radiostate(RadioInterface* radio) {
void kiss_indicate_radiostate(uint8_t index) {
serial_write(FEND);
serial_write(CMD_RADIO_STATE);
serial_write(radio->getRadioOnline());
serial_write(radio_details[index].radio_online);
serial_write(FEND);
}
@ -665,24 +662,25 @@ void kiss_indicate_stat_snr() {
serial_write(FEND);
}
void kiss_indicate_radio_lock(RadioInterface* radio) {
void kiss_indicate_radio_lock(uint8_t index) {
serial_write(FEND);
serial_write(CMD_RADIO_LOCK);
serial_write(radio->getRadioLock());
serial_write(radio_details[index].radio_locked);
serial_write(FEND);
}
void kiss_indicate_spreadingfactor(RadioInterface* radio) {
void kiss_indicate_spreadingfactor(uint8_t index) {
// \todo, add ability to choose FSK when multiple modem mode support added
serial_write(FEND);
serial_write(CMD_SF);
serial_write(radio->getSpreadingFactor());
serial_write(radio_details[index].sf);
serial_write(FEND);
}
void kiss_indicate_codingrate(RadioInterface* radio) {
void kiss_indicate_codingrate(uint8_t index) {
serial_write(FEND);
serial_write(CMD_CR);
serial_write(radio->getCodingRate4());
serial_write(radio_details[index].cr);
serial_write(FEND);
}
@ -693,16 +691,16 @@ void kiss_indicate_implicit_length() {
serial_write(FEND);
}
void kiss_indicate_txpower(RadioInterface* radio) {
int8_t txp = radio->getTxPower();
void kiss_indicate_txpower(uint8_t index) {
int8_t txp = radio_details[index].txp;
serial_write(FEND);
serial_write(CMD_TXPOWER);
serial_write(txp);
serial_write(FEND);
}
void kiss_indicate_bandwidth(RadioInterface* radio) {
uint32_t bw = radio->getSignalBandwidth();
void kiss_indicate_bandwidth(uint8_t index) {
uint32_t bw = radio_details[index].bw * 1000;
serial_write(FEND);
serial_write(CMD_BANDWIDTH);
escaped_serial_write(bw>>24);
@ -712,8 +710,8 @@ void kiss_indicate_bandwidth(RadioInterface* radio) {
serial_write(FEND);
}
void kiss_indicate_frequency(RadioInterface* radio) {
uint32_t freq = radio->getFrequency();
void kiss_indicate_frequency(uint8_t index) {
uint32_t freq = uint32_t(radio_details[index].freq * 1000000);
serial_write(FEND);
serial_write(CMD_FREQUENCY);
escaped_serial_write(freq>>24);
@ -732,8 +730,8 @@ void kiss_indicate_interface(int index) {
serial_write(FEND);
}
void kiss_indicate_st_alock(RadioInterface* radio) {
uint16_t at = (uint16_t)(radio->getSTALock()*100*100);
void kiss_indicate_st_alock(uint8_t index) {
uint16_t at = (uint16_t)(radio_details[index].st_airtime_limit*100*100);
serial_write(FEND);
serial_write(CMD_ST_ALOCK);
escaped_serial_write(at>>8);
@ -741,8 +739,8 @@ void kiss_indicate_st_alock(RadioInterface* radio) {
serial_write(FEND);
}
void kiss_indicate_lt_alock(RadioInterface* radio) {
uint16_t at = (uint16_t)(radio->getLTALock()*100*100);
void kiss_indicate_lt_alock(uint8_t index) {
uint16_t at = (uint16_t)(radio_details[index].lt_airtime_limit*100*100);
serial_write(FEND);
serial_write(CMD_LT_ALOCK);
escaped_serial_write(at>>8);
@ -750,11 +748,11 @@ void kiss_indicate_lt_alock(RadioInterface* radio) {
serial_write(FEND);
}
void kiss_indicate_channel_stats(RadioInterface* radio) {
uint16_t ats = (uint16_t)(radio->getAirtime()*100*100);
uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100);
uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100);
uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*100*100);
void kiss_indicate_channel_stats(uint8_t index) {
uint16_t ats = (uint16_t)(radio_details[index].airtime*100*100);
uint16_t atl = (uint16_t)(radio_details[index].longterm_airtime*100*100);
uint16_t cls = (uint16_t)(radio_details[index].total_channel_util*100*100);
uint16_t cll = (uint16_t)(radio_details[index].longterm_channel_util*100*100);
serial_write(FEND);
serial_write(CMD_STAT_CHTM);
escaped_serial_write(ats>>8);
@ -768,12 +766,12 @@ void kiss_indicate_channel_stats(RadioInterface* radio) {
serial_write(FEND);
}
void kiss_indicate_phy_stats(RadioInterface* radio) {
uint16_t lst = (uint16_t)(radio->getSymbolTime()*1000);
uint16_t lsr = (uint16_t)(radio->getSymbolRate());
uint16_t prs = (uint16_t)(radio->getPreambleLength()+4);
uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime());
uint16_t cst = (uint16_t)(radio->getCSMASlotMS());
void kiss_indicate_phy_stats(uint8_t index) {
uint16_t lst = (uint16_t)(radio_details[index].lora_symbol_time_ms*1000);
uint16_t lsr = (uint16_t)(radio_details[index].lora_symbol_rate);
uint16_t prs = (uint16_t)(radio_details[index].preamble_length+4);
uint16_t prt = (uint16_t)((radio_details[index].preamble_length+4)*radio_details[index].lora_symbol_time_ms);
uint16_t cst = (uint16_t)(radio_details[index].csma_slot_ms);
serial_write(FEND);
serial_write(CMD_STAT_PHYPRM);
escaped_serial_write(lst>>8);
@ -964,6 +962,203 @@ void kiss_indicate_mcu() {
serial_write(FEND);
}
void update_radio_params(PhysicalLayer* radio, struct radio_vars* config) {
DataRate_t params;
params.lora.spreadingFactor = config->sf;
params.lora.codingRate = config->cr;
params.lora.bandwidth = config->bw;
int16_t status = radio->setDataRate(params);
if (status != RADIOLIB_ERR_NONE) {
kiss_indicate_error(ERROR_INITRADIO);
led_indicate_error(0);
}
}
int16_t set_spreading_factor(PhysicalLayer* radio, uint8_t index, uint8_t sf) {
struct radio_vars* config = &radio_details[index];
config->sf = sf;
update_radio_params(radio, config);
}
int16_t set_coding_rate(PhysicalLayer* radio, uint8_t index, uint8_t cr) {
struct radio_vars* config = &radio_details[index];
config->cr = cr;
update_radio_params(radio, config);
}
int16_t set_bandwidth(PhysicalLayer* radio, uint8_t index, float bw) {
struct radio_vars* config = &radio_details[index];
config->bw = bw;
update_radio_params(radio, config);
}
void update_modem_status(PhysicalLayer* radio, uint8_t index) {
struct radio_vars* config = &radio_details[index];
#if PLATFORM == PLATFORM_ESP32
portENTER_CRITICAL(&update_lock);
#elif PLATFORM == PLATFORM_NRF52
portENTER_CRITICAL();
#endif
// \todo implement again
uint8_t status = 0;//modemStatus();
config->last_status_update = millis();
#if PLATFORM == PLATFORM_ESP32
portEXIT_CRITICAL(&update_lock);
#elif PLATFORM == PLATFORM_NRF52
portEXIT_CRITICAL();
#endif
if ((status & SIG_DETECT) == SIG_DETECT) { config->stat_signal_detected = true; } else { config->stat_signal_detected = false; }
if ((status & SIG_SYNCED) == SIG_SYNCED) { config->stat_signal_synced = true; } else { config->stat_signal_synced = false; }
if ((status & RX_ONGOING) == RX_ONGOING) { config->stat_rx_ongoing = true; } else { config->stat_rx_ongoing = false; }
if (config->stat_signal_detected || config->stat_signal_synced) {
if (config->stat_rx_ongoing) {
if (config->dcd_count < DCD_THRESHOLD) {
config->dcd_count++;
} else {
config->last_dcd = config->last_status_update;
config->dcd_led = true;
config->dcd = true;
}
}
} else {
if (config->dcd_count == 0) {
config->dcd_led = false;
} else if (config->dcd_count > DCD_LED_STEP_D) {
config->dcd_count -= DCD_LED_STEP_D;
} else {
config->dcd_count = 0;
}
if (config->last_status_update > config->last_dcd+config->csma_slot_ms) {
config->dcd = false;
config->dcd_led = false;
config->dcd_count = 0;
}
}
if (config->dcd_led) {
led_rx_on();
} else {
if (config->airtime_lock) {
led_indicate_airtime_lock();
} else {
led_rx_off();
}
}
};
float csma_slope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); };
void update_csma_p(struct radio_vars* config) {
config->csma_p = (uint8_t)((1.0-(config->csma_p_min+(config->csma_p_max-config->csma_p_min)*csma_slope(config->airtime)))*255.0);
};
bool calculate_alock(struct radio_vars* config) {
bool airtime_lock = false;
if (config->st_airtime_limit != 0.0 && config->airtime >= config->st_airtime_limit) {
airtime_lock = true;
config->airtime_lock = true;
}
if (config->lt_airtime_limit != 0.0 && config->longterm_airtime >= config->lt_airtime_limit) {
airtime_lock = true;
config->airtime_lock = true;
}
return airtime_lock;
};
void add_airtime(uint8_t index, uint16_t written) {
// \todo is referencing it this was actually necessary? Could I not just do it without the pointer?
struct radio_vars* config = &radio_details[index];
float packet_cost_ms = 0.0;
float payload_cost_ms = ((float)written * config->lora_us_per_byte)/1000.0;
packet_cost_ms += payload_cost_ms;
packet_cost_ms += (config->preamble_length+4.25)*config->lora_symbol_time_ms;
packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * config->lora_symbol_time_ms;
uint16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
config->airtime_bins[cb] += packet_cost_ms;
config->airtime_bins[nb] = 0;
};
void update_airtime(uint8_t index) {
struct radio_vars* config = &radio_details[index];
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; }
config->airtime_bins[nb] = 0;
config->airtime = (float)(config->airtime_bins[cb]+config->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 += config->airtime_bins[bin];
}
config->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 += config->longterm_bins[bin];
}
config->longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
update_csma_p(config);
//kiss_indicate_channel_stats(); // todo: enable me!
};
void check_modem_status(PhysicalLayer* radio, uint8_t index) {
struct radio_vars* config = &radio_details[index];
if (millis()-(config->last_status_update) >= STATUS_INTERVAL_MS) {
update_modem_status(radio, index);
config->util_samples[config->dcd_sample] = config->dcd;
config->dcd_sample = (config->dcd_sample+1)%DCD_SAMPLES;
if (config->dcd_sample % UTIL_UPDATE_INTERVAL == 0) {
int util_count = 0;
for (int ui = 0; ui < DCD_SAMPLES; ui++) {
if (config->util_samples[ui]) util_count++;
}
config->local_channel_util = (float)util_count / (float)DCD_SAMPLES;
config->total_channel_util = config->local_channel_util + config->airtime;
if (config->total_channel_util > 1.0) config->total_channel_util = 1.0;
int16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
if (config->total_channel_util > config->longterm_bins[cb]) config->longterm_bins[cb] = config->total_channel_util;
config->longterm_bins[nb] = 0.0;
update_airtime(index);
}
}
};
void update_bitrate(PhysicalLayer* radio, uint8_t index) {
struct radio_vars* config = &radio_details[index];
if (config->radio_online) {
config->lora_symbol_rate = (config->bw*1000)/(float)(pow(2, config->sf));
config->lora_symbol_time_ms = (1.0/config->lora_symbol_rate)*1000.0;
config->bitrate = (uint32_t)(config->sf * ( (4.0/(float)(config->cr+4)) / ((float)(pow(2, config->sf))/config->bw) ) * 1000.0);
config->lora_us_per_byte = 1000000.0/((float)config->bitrate/8.0);
//_csma_slot_ms = _lora_symbol_time_ms*10;
float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/config->lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else {
target_preamble_symbols = ceil(target_preamble_symbols);
}
// \todo actually update this on the radio
config->preamble_length = target_preamble_symbols;
radio->setPreambleLength(target_preamble_symbols);
} else {
config->bitrate = 0;
}
}
inline bool isSplitPacket(uint8_t header) {
return (header & FLAG_SPLIT);
}
@ -981,66 +1176,69 @@ void set_implicit_length(uint8_t len) {
}
}
void setTXPower(RadioInterface* radio, int txp) {
void setTXPower(PhysicalLayer* radio, uint8_t index, int txp) {
// Todo, revamp this function. The current parameters for setTxPower are
// suboptimal, as some chips have power amplifiers which means that the max
// dBm is not always the same.
if (model == MODEL_11) {
if (interfaces[radio->getIndex()] == SX128X) {
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
} else {
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
}
}
if (model == MODEL_12) {
if (interfaces[radio->getIndex()] == SX128X) {
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
} else {
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
}
}
int8_t set_pwr;
radio->checkOutputPower(txp, &set_pwr);
radio_details[index].txp = set_pwr;
//if (model == MODEL_11) {
// if (interfaces[radio->getIndex()] == SX128X) {
// radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
// } else {
// radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
// }
//}
//if (model == MODEL_12) {
// if (interfaces[radio->getIndex()] == SX128X) {
// radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
// } else {
// radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
// }
//}
if (model == MODEL_21) {
if (interfaces[radio->getIndex()] == SX128X) {
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
} else {
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
}
}
//if (model == MODEL_21) {
// if (interfaces[radio->getIndex()] == SX128X) {
// radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
// } else {
// radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
// }
//}
if (model == MODEL_A1) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A2) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A4) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A5) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A6) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A7) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_A1) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_A2) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_A3) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
//if (model == MODEL_A4) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
//if (model == MODEL_A5) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
//if (model == MODEL_A6) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_A7) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_A8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_A9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_B3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_B4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_B8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_B9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_E4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_E9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_E3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_E8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FE) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FF) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
//if (model == MODEL_FE) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
//if (model == MODEL_FF) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
}
uint8_t getRandom(RadioInterface* radio) {
if (radio->getRadioOnline()) {
return radio->random();
} else {
uint8_t getRandom(PhysicalLayer* radio) {
//if (radio->getRadioOnline()) {
// return radio->random();
//} else {
return 0x00;
}
//}
}
uint8_t getInterfaceIndex(uint8_t byte) {
@ -1475,57 +1673,59 @@ bool eeprom_have_conf() {
}
}
void eeprom_conf_load(RadioInterface* radio) {
if (eeprom_have_conf()) {
if (!(radio->getRadioOnline())) {
#if HAS_EEPROM
uint8_t sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF));
uint8_t cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR));
uint8_t txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP));
uint32_t freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
uint32_t bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03);
#elif MCU_VARIANT == MCU_NRF52
uint8_t sf = eeprom_read(eeprom_addr(ADDR_CONF_SF));
uint8_t cr = eeprom_read(eeprom_addr(ADDR_CONF_CR));
uint8_t txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP));
uint32_t freq = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
uint32_t bw = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x03);
#endif
radio->setSpreadingFactor(sf);
radio->setCodingRate4(cr);
setTXPower(radio, txp);
radio->setFrequency(freq);
radio->setSignalBandwidth(bw);
radio->updateBitrate();
}
}
void eeprom_conf_load(PhysicalLayer* radio) {
// \todo remove, or will attermann need it?
//if (eeprom_have_conf()) {
// if (!(radio->getRadioOnline())) {
// #if HAS_EEPROM
// uint8_t sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF));
// uint8_t cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR));
// uint8_t txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP));
// uint32_t freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
// uint32_t bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03);
// #elif MCU_VARIANT == MCU_NRF52
// uint8_t sf = eeprom_read(eeprom_addr(ADDR_CONF_SF));
// uint8_t cr = eeprom_read(eeprom_addr(ADDR_CONF_CR));
// uint8_t txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP));
// uint32_t freq = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
// uint32_t bw = (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)eeprom_read(eeprom_addr(ADDR_CONF_BW)+0x03);
// #endif
// radio->setSpreadingFactor(sf);
// radio->setCodingRate(cr);
// setTXPower(radio, txp);
// radio->setFrequency(freq);
// radio->setBandwidth(bw);
// radio->updateBitrate();
// }
//}
}
void eeprom_conf_save(RadioInterface* radio) {
if (hw_ready && radio->getRadioOnline()) {
eeprom_update(eeprom_addr(ADDR_CONF_SF), radio->getSpreadingFactor());
eeprom_update(eeprom_addr(ADDR_CONF_CR), radio->getCodingRate4());
eeprom_update(eeprom_addr(ADDR_CONF_TXP), radio->getTxPower());
void eeprom_conf_save(PhysicalLayer* radio) {
// \todo fixme
//if (hw_ready && radio->getRadioOnline()) {
// eeprom_update(eeprom_addr(ADDR_CONF_SF), radio->getSpreadingFactorVal());
// eeprom_update(eeprom_addr(ADDR_CONF_CR), radio->getCodingRateVal());
// eeprom_update(eeprom_addr(ADDR_CONF_TXP), radio->getTXPowerVal());
uint32_t bw = radio->getSignalBandwidth();
// uint32_t bw = radio->getBandwidthVal() * 1000;
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, bw>>24);
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, bw>>16);
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, bw>>8);
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, bw);
// eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, bw>>24);
// eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, bw>>16);
// eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, bw>>8);
// eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, bw);
uint32_t freq = radio->getFrequency();
// uint32_t freq = radio->getFrequencyVal() * 1000;
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, freq>>24);
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, freq>>16);
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, freq>>8);
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, freq);
// eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, freq>>24);
// eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, freq>>16);
// eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, freq>>8);
// eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, freq);
eeprom_update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE);
led_indicate_info(10);
} else {
led_indicate_warning(10);
}
// eeprom_update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE);
// led_indicate_info(10);
//} else {
// led_indicate_warning(10);
//}
}
void eeprom_conf_delete() {