Revert "add a .clang-format file (#9154)" (#9172)

I thought git would be smart enough to understand all the whitespace changes but even with all the flags I know to make it ignore theses it still blows up if there are identical changes on both sides.

I have a solution but it require creating a new commit at the merge base for each conflicting PR and merging it into develop.

I don't think blowing up all PRs is worth for now, maybe if we can coordinate this for V3 let's say.

This reverts commit 0d11331d18.
This commit is contained in:
Jorropo
2026-01-04 12:15:53 +01:00
committed by GitHub
parent 0d11331d18
commit beb268ff25
771 changed files with 83399 additions and 77967 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -12,26 +12,38 @@
// Product strings for auto-configuration
// {"PRODUCT_STRING", "CONFIG.YAML"}
// YAML paths are relative to `meshtastic/available.d`
inline const std::unordered_map<std::string, std::string> configProducts = {{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"},
{"MESHSTICK", "lora-meshstick-1262.yaml"},
{"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"},
{"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"},
{"POWERPI", "lora-MeshAdv-900M30S.yaml"},
{"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"},
{"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}};
inline const std::unordered_map<std::string, std::string> configProducts = {
{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"},
{"MESHSTICK", "lora-meshstick-1262.yaml"},
{"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"},
{"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"},
{"POWERPI", "lora-MeshAdv-900M30S.yaml"},
{"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"},
{"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}};
enum screen_modules { no_screen, x11, fb, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d };
enum touchscreen_modules { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
enum portduino_log_level { level_error, level_warn, level_info, level_debug, level_trace };
enum lora_module_enum { use_simradio, use_autoconf, use_rf95, use_sx1262, use_sx1268, use_sx1280, use_lr1110, use_lr1120, use_lr1121, use_llcc68 };
enum lora_module_enum {
use_simradio,
use_autoconf,
use_rf95,
use_sx1262,
use_sx1268,
use_sx1280,
use_lr1110,
use_lr1120,
use_lr1121,
use_llcc68
};
struct pinMapping {
std::string config_section;
std::string config_name;
int pin = RADIOLIB_NC;
int gpiochip;
int line;
bool enabled = false;
std::string config_section;
std::string config_name;
int pin = RADIOLIB_NC;
int gpiochip;
int line;
bool enabled = false;
};
extern std::ofstream traceFile;
@@ -47,446 +59,448 @@ void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault
std::string exec(const char *cmd);
extern struct portduino_config_struct {
// Lora
std::map<lora_module_enum, std::string> loraModules = {
{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"},
{use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"}, {st7735, "ST7735"},
{st7735s, "ST7735S"}, {st7796, "ST7796"}, {ili9341, "ILI9341"}, {ili9342, "ILI9342"},
{ili9486, "ILI9486"}, {ili9488, "ILI9488"}, {hx8357d, "HX8357D"}};
lora_module_enum lora_module;
bool has_rfswitch_table = false;
uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
Module::RfSwitchMode_t rfswitch_table[8];
bool force_simradio = false;
bool has_device_id = false;
uint8_t device_id[16] = {0};
std::string lora_spi_dev = "";
std::string lora_usb_serial_num = "";
int lora_spi_dev_int = 0;
int lora_default_gpiochip = 0;
int sx126x_max_power = 22;
int sx128x_max_power = 13;
int lr1110_max_power = 22;
int lr1120_max_power = 13;
int rf95_max_power = 20;
bool dio2_as_rf_switch = false;
int dio3_tcxo_voltage = 0;
int lora_usb_pid = 0x5512;
int lora_usb_vid = 0x1A86;
int spiSpeed = 2000000;
pinMapping lora_cs_pin = {"Lora", "CS"};
pinMapping lora_irq_pin = {"Lora", "IRQ"};
pinMapping lora_busy_pin = {"Lora", "Busy"};
pinMapping lora_reset_pin = {"Lora", "Reset"};
pinMapping lora_txen_pin = {"Lora", "TXen"};
pinMapping lora_rxen_pin = {"Lora", "RXen"};
pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"};
// GPS
bool has_gps = false;
// I2C
std::string i2cdev = "";
// Display
std::string display_spi_dev = "";
int display_spi_dev_int = 0;
int displayBusFrequency = 40000000;
screen_modules displayPanel = no_screen;
int displayWidth = 0;
int displayHeight = 0;
bool displayRGBOrder = false;
bool displayBacklightInvert = false;
bool displayRotate = false;
int displayOffsetRotate = 1;
bool displayInvert = false;
int displayOffsetX = 0;
int displayOffsetY = 0;
pinMapping displayDC = {"Display", "DC"};
pinMapping displayCS = {"Display", "CS"};
pinMapping displayBacklight = {"Display", "Backlight"};
pinMapping displayBacklightPWMChannel = {"Display", "BacklightPWMChannel"};
pinMapping displayReset = {"Display", "Reset"};
// Touchscreen
std::string touchscreen_spi_dev = "";
int touchscreen_spi_dev_int = 0;
touchscreen_modules touchscreenModule = no_touchscreen;
int touchscreenI2CAddr = -1;
int touchscreenBusFrequency = 1000000;
int touchscreenRotate = -1;
pinMapping touchscreenCS = {"Touchscreen", "CS"};
pinMapping touchscreenIRQ = {"Touchscreen", "IRQ"};
// Input
std::string keyboardDevice = "";
std::string pointerDevice = "";
int tbDirection;
pinMapping userButtonPin = {"Input", "User"};
pinMapping tbUpPin = {"Input", "TrackballUp"};
pinMapping tbDownPin = {"Input", "TrackballDown"};
pinMapping tbLeftPin = {"Input", "TrackballLwft"};
pinMapping tbRightPin = {"Input", "TrackballRight"};
pinMapping tbPressPin = {"Input", "TrackballPress"};
// Logging
portduino_log_level logoutputlevel = level_debug;
std::string traceFilename;
bool ascii_logs = !isatty(1);
bool ascii_logs_explicit = false;
std::string JSONFilename;
meshtastic_PortNum JSONFilter = (_meshtastic_PortNum)0;
// Webserver
std::string webserver_root_path = "";
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
std::string webserver_ssl_cert_path = "/etc/meshtasticd/ssl/certificate.pem";
int webserverport = -1;
// HostMetrics
std::string hostMetrics_user_command = "";
int hostMetrics_interval = 0;
int hostMetrics_channel = 0;
// config
int configDisplayMode = 0;
bool has_configDisplayMode = false;
// General
std::string mac_address = "";
bool mac_address_explicit = false;
std::string mac_address_source = "";
std::string config_directory = "";
std::string available_directory = "/etc/meshtasticd/available.d/";
int maxtophone = 100;
int MaxNodes = 200;
pinMapping *all_pins[20] = {&lora_cs_pin,
&lora_irq_pin,
&lora_busy_pin,
&lora_reset_pin,
&lora_txen_pin,
&lora_rxen_pin,
&lora_sx126x_ant_sw_pin,
&displayDC,
&displayCS,
&displayBacklight,
&displayBacklightPWMChannel,
&displayReset,
&touchscreenCS,
&touchscreenIRQ,
&userButtonPin,
&tbUpPin,
&tbDownPin,
&tbLeftPin,
&tbRightPin,
&tbPressPin};
std::string emit_yaml() {
YAML::Emitter out;
out << YAML::BeginMap;
// Lora
out << YAML::Key << "Lora" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "Module" << YAML::Value << loraModules[lora_module];
std::map<lora_module_enum, std::string> loraModules = {
{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"},
{use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
for (auto lora_pin : all_pins) {
if (lora_pin->config_section == "Lora" && lora_pin->enabled) {
out << YAML::Key << lora_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << lora_pin->pin;
out << YAML::Key << "line" << YAML::Value << lora_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << lora_pin->gpiochip;
out << YAML::EndMap; // User
}
}
std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"},
{st7735, "ST7735"}, {st7735s, "ST7735S"}, {st7796, "ST7796"},
{ili9341, "ILI9341"}, {ili9342, "ILI9342"}, {ili9486, "ILI9486"},
{ili9488, "ILI9488"}, {hx8357d, "HX8357D"}};
if (sx126x_max_power != 22)
out << YAML::Key << "SX126X_MAX_POWER" << YAML::Value << sx126x_max_power;
if (sx128x_max_power != 13)
out << YAML::Key << "SX128X_MAX_POWER" << YAML::Value << sx128x_max_power;
if (lr1110_max_power != 22)
out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power;
if (lr1120_max_power != 13)
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
if (rf95_max_power != 20)
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
if (dio3_tcxo_voltage != 0)
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
if (lora_usb_pid != 0x5512)
out << YAML::Key << "USB_PID" << YAML::Value << YAML::Hex << lora_usb_pid;
if (lora_usb_vid != 0x1A86)
out << YAML::Key << "USB_VID" << YAML::Value << YAML::Hex << lora_usb_vid;
if (lora_spi_dev != "")
out << YAML::Key << "spidev" << YAML::Value << lora_spi_dev;
if (lora_usb_serial_num != "")
out << YAML::Key << "USB_Serialnum" << YAML::Value << lora_usb_serial_num;
out << YAML::Key << "spiSpeed" << YAML::Value << spiSpeed;
if (rfswitch_dio_pins[0] != RADIOLIB_NC) {
out << YAML::Key << "rfswitch_table" << YAML::Value << YAML::BeginMap;
lora_module_enum lora_module;
bool has_rfswitch_table = false;
uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
Module::RfSwitchMode_t rfswitch_table[8];
bool force_simradio = false;
bool has_device_id = false;
uint8_t device_id[16] = {0};
std::string lora_spi_dev = "";
std::string lora_usb_serial_num = "";
int lora_spi_dev_int = 0;
int lora_default_gpiochip = 0;
int sx126x_max_power = 22;
int sx128x_max_power = 13;
int lr1110_max_power = 22;
int lr1120_max_power = 13;
int rf95_max_power = 20;
bool dio2_as_rf_switch = false;
int dio3_tcxo_voltage = 0;
int lora_usb_pid = 0x5512;
int lora_usb_vid = 0x1A86;
int spiSpeed = 2000000;
pinMapping lora_cs_pin = {"Lora", "CS"};
pinMapping lora_irq_pin = {"Lora", "IRQ"};
pinMapping lora_busy_pin = {"Lora", "Busy"};
pinMapping lora_reset_pin = {"Lora", "Reset"};
pinMapping lora_txen_pin = {"Lora", "TXen"};
pinMapping lora_rxen_pin = {"Lora", "RXen"};
pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"};
out << YAML::Key << "pins";
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
// GPS
bool has_gps = false;
for (int i = 0; i < 5; i++) {
// set up the pin array first
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO5)
out << "DIO5";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO6)
out << "DIO6";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO7)
out << "DIO7";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO8)
out << "DIO8";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO10)
out << "DIO10";
}
out << YAML::EndSeq;
for (int i = 0; i < 7; i++) {
switch (i) {
case 0:
out << YAML::Key << "MODE_STBY";
break;
case 1:
out << YAML::Key << "MODE_RX";
break;
case 2:
out << YAML::Key << "MODE_TX";
break;
case 3:
out << YAML::Key << "MODE_TX_HP";
break;
case 4:
out << YAML::Key << "MODE_TX_HF";
break;
case 5:
out << YAML::Key << "MODE_GNSS";
break;
case 6:
out << YAML::Key << "MODE_WIFI";
break;
}
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
for (int j = 0; j < 5; j++) {
if (rfswitch_table[i].values[j] == HIGH) {
out << "HIGH";
} else {
out << "LOW";
}
}
out << YAML::EndSeq;
}
out << YAML::EndMap; // rfswitch_table
}
out << YAML::EndMap; // Lora
if (i2cdev != "") {
out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev;
out << YAML::EndMap; // I2C
}
// I2C
std::string i2cdev = "";
// Display
if (displayPanel != no_screen) {
out << YAML::Key << "Display" << YAML::Value << YAML::BeginMap;
for (auto &screen_name : screen_names) {
if (displayPanel == screen_name.first)
out << YAML::Key << "Module" << YAML::Value << screen_name.second;
}
for (auto display_pin : all_pins) {
if (display_pin->config_section == "Display" && display_pin->enabled) {
out << YAML::Key << display_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << display_pin->pin;
out << YAML::Key << "line" << YAML::Value << display_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << display_pin->gpiochip;
out << YAML::EndMap;
}
}
out << YAML::Key << "spidev" << YAML::Value << display_spi_dev;
out << YAML::Key << "BusFrequency" << YAML::Value << displayBusFrequency;
if (displayWidth)
out << YAML::Key << "Width" << YAML::Value << displayWidth;
if (displayHeight)
out << YAML::Key << "Height" << YAML::Value << displayHeight;
if (displayRGBOrder)
out << YAML::Key << "RGBOrder" << YAML::Value << true;
if (displayBacklightInvert)
out << YAML::Key << "BacklightInvert" << YAML::Value << true;
if (displayRotate)
out << YAML::Key << "Rotate" << YAML::Value << true;
if (displayInvert)
out << YAML::Key << "Invert" << YAML::Value << true;
if (displayOffsetX)
out << YAML::Key << "OffsetX" << YAML::Value << displayOffsetX;
if (displayOffsetY)
out << YAML::Key << "OffsetY" << YAML::Value << displayOffsetY;
out << YAML::Key << "OffsetRotate" << YAML::Value << displayOffsetRotate;
out << YAML::EndMap; // Display
}
std::string display_spi_dev = "";
int display_spi_dev_int = 0;
int displayBusFrequency = 40000000;
screen_modules displayPanel = no_screen;
int displayWidth = 0;
int displayHeight = 0;
bool displayRGBOrder = false;
bool displayBacklightInvert = false;
bool displayRotate = false;
int displayOffsetRotate = 1;
bool displayInvert = false;
int displayOffsetX = 0;
int displayOffsetY = 0;
pinMapping displayDC = {"Display", "DC"};
pinMapping displayCS = {"Display", "CS"};
pinMapping displayBacklight = {"Display", "Backlight"};
pinMapping displayBacklightPWMChannel = {"Display", "BacklightPWMChannel"};
pinMapping displayReset = {"Display", "Reset"};
// Touchscreen
if (touchscreen_spi_dev != "") {
out << YAML::Key << "Touchscreen" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "spidev" << YAML::Value << touchscreen_spi_dev;
out << YAML::Key << "BusFrequency" << YAML::Value << touchscreenBusFrequency;
switch (touchscreenModule) {
case xpt2046:
out << YAML::Key << "Module" << YAML::Value << "XPT2046";
case stmpe610:
out << YAML::Key << "Module" << YAML::Value << "STMPE610";
case gt911:
out << YAML::Key << "Module" << YAML::Value << "GT911";
case ft5x06:
out << YAML::Key << "Module" << YAML::Value << "FT5x06";
}
for (auto touchscreen_pin : all_pins) {
if (touchscreen_pin->config_section == "Touchscreen" && touchscreen_pin->enabled) {
out << YAML::Key << touchscreen_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << touchscreen_pin->pin;
out << YAML::Key << "line" << YAML::Value << touchscreen_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << touchscreen_pin->gpiochip;
out << YAML::EndMap;
}
}
if (touchscreenRotate != -1)
out << YAML::Key << "Rotate" << YAML::Value << touchscreenRotate;
if (touchscreenI2CAddr != -1)
out << YAML::Key << "I2CAddr" << YAML::Value << touchscreenI2CAddr;
out << YAML::EndMap; // Touchscreen
}
std::string touchscreen_spi_dev = "";
int touchscreen_spi_dev_int = 0;
touchscreen_modules touchscreenModule = no_touchscreen;
int touchscreenI2CAddr = -1;
int touchscreenBusFrequency = 1000000;
int touchscreenRotate = -1;
pinMapping touchscreenCS = {"Touchscreen", "CS"};
pinMapping touchscreenIRQ = {"Touchscreen", "IRQ"};
// Input
out << YAML::Key << "Input" << YAML::Value << YAML::BeginMap;
if (keyboardDevice != "")
out << YAML::Key << "KeyboardDevice" << YAML::Value << keyboardDevice;
if (pointerDevice != "")
out << YAML::Key << "PointerDevice" << YAML::Value << pointerDevice;
std::string keyboardDevice = "";
std::string pointerDevice = "";
int tbDirection;
pinMapping userButtonPin = {"Input", "User"};
pinMapping tbUpPin = {"Input", "TrackballUp"};
pinMapping tbDownPin = {"Input", "TrackballDown"};
pinMapping tbLeftPin = {"Input", "TrackballLwft"};
pinMapping tbRightPin = {"Input", "TrackballRight"};
pinMapping tbPressPin = {"Input", "TrackballPress"};
for (auto input_pin : all_pins) {
if (input_pin->config_section == "Input" && input_pin->enabled) {
out << YAML::Key << input_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << input_pin->pin;
out << YAML::Key << "line" << YAML::Value << input_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << input_pin->gpiochip;
out << YAML::EndMap;
}
}
if (tbDirection == 3)
out << YAML::Key << "TrackballDirection" << YAML::Value << "FALLING";
// Logging
portduino_log_level logoutputlevel = level_debug;
std::string traceFilename;
bool ascii_logs = !isatty(1);
bool ascii_logs_explicit = false;
out << YAML::EndMap; // Input
out << YAML::Key << "Logging" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "LogLevel" << YAML::Value;
switch (logoutputlevel) {
case level_error:
out << "error";
break;
case level_warn:
out << "warn";
break;
case level_info:
out << "info";
break;
case level_debug:
out << "debug";
break;
case level_trace:
out << "trace";
break;
}
if (traceFilename != "")
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
if (JSONFilename != "") {
out << YAML::Key << "JSONFile" << YAML::Value << JSONFilename;
if (JSONFilter == meshtastic_PortNum_TEXT_MESSAGE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "textmessage";
else if (JSONFilter == meshtastic_PortNum_TELEMETRY_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "telemetry";
else if (JSONFilter == meshtastic_PortNum_NODEINFO_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "nodeinfo";
else if (JSONFilter == meshtastic_PortNum_POSITION_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "position";
else if (JSONFilter == meshtastic_PortNum_WAYPOINT_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "waypoint";
else if (JSONFilter == meshtastic_PortNum_NEIGHBORINFO_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "neighborinfo";
else if (JSONFilter == meshtastic_PortNum_TRACEROUTE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "traceroute";
else if (JSONFilter == meshtastic_PortNum_DETECTION_SENSOR_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "detection";
else if (JSONFilter == meshtastic_PortNum_PAXCOUNTER_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "paxcounter";
else if (JSONFilter == meshtastic_PortNum_REMOTE_HARDWARE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "remotehardware";
}
if (ascii_logs_explicit) {
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
}
out << YAML::EndMap; // Logging
std::string JSONFilename;
meshtastic_PortNum JSONFilter = (_meshtastic_PortNum)0;
// Webserver
if (webserver_root_path != "") {
out << YAML::Key << "Webserver" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "RootPath" << YAML::Value << webserver_root_path;
out << YAML::Key << "SSLKey" << YAML::Value << webserver_ssl_key_path;
out << YAML::Key << "SSLCert" << YAML::Value << webserver_ssl_cert_path;
out << YAML::Key << "Port" << YAML::Value << webserverport;
out << YAML::EndMap; // Webserver
}
std::string webserver_root_path = "";
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
std::string webserver_ssl_cert_path = "/etc/meshtasticd/ssl/certificate.pem";
int webserverport = -1;
// HostMetrics
if (hostMetrics_user_command != "") {
out << YAML::Key << "HostMetrics" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "UserStringCommand" << YAML::Value << hostMetrics_user_command;
out << YAML::Key << "ReportInterval" << YAML::Value << hostMetrics_interval;
out << YAML::Key << "Channel" << YAML::Value << hostMetrics_channel;
out << YAML::EndMap; // HostMetrics
}
std::string hostMetrics_user_command = "";
int hostMetrics_interval = 0;
int hostMetrics_channel = 0;
// config
if (has_configDisplayMode) {
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
switch (configDisplayMode) {
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
break;
}
out << YAML::EndMap; // Config
}
int configDisplayMode = 0;
bool has_configDisplayMode = false;
// General
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
if (config_directory != "")
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
if (mac_address_explicit)
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
if (mac_address_source != "")
out << YAML::Key << "MACAddressSource" << YAML::Value << mac_address_source;
if (available_directory != "")
out << YAML::Key << "AvailableDirectory" << YAML::Value << available_directory;
out << YAML::Key << "MaxMessageQueue" << YAML::Value << maxtophone;
out << YAML::Key << "MaxNodes" << YAML::Value << MaxNodes;
out << YAML::EndMap; // General
return out.c_str();
}
std::string mac_address = "";
bool mac_address_explicit = false;
std::string mac_address_source = "";
std::string config_directory = "";
std::string available_directory = "/etc/meshtasticd/available.d/";
int maxtophone = 100;
int MaxNodes = 200;
pinMapping *all_pins[20] = {&lora_cs_pin,
&lora_irq_pin,
&lora_busy_pin,
&lora_reset_pin,
&lora_txen_pin,
&lora_rxen_pin,
&lora_sx126x_ant_sw_pin,
&displayDC,
&displayCS,
&displayBacklight,
&displayBacklightPWMChannel,
&displayReset,
&touchscreenCS,
&touchscreenIRQ,
&userButtonPin,
&tbUpPin,
&tbDownPin,
&tbLeftPin,
&tbRightPin,
&tbPressPin};
std::string emit_yaml()
{
YAML::Emitter out;
out << YAML::BeginMap;
// Lora
out << YAML::Key << "Lora" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "Module" << YAML::Value << loraModules[lora_module];
for (auto lora_pin : all_pins) {
if (lora_pin->config_section == "Lora" && lora_pin->enabled) {
out << YAML::Key << lora_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << lora_pin->pin;
out << YAML::Key << "line" << YAML::Value << lora_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << lora_pin->gpiochip;
out << YAML::EndMap; // User
}
}
if (sx126x_max_power != 22)
out << YAML::Key << "SX126X_MAX_POWER" << YAML::Value << sx126x_max_power;
if (sx128x_max_power != 13)
out << YAML::Key << "SX128X_MAX_POWER" << YAML::Value << sx128x_max_power;
if (lr1110_max_power != 22)
out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power;
if (lr1120_max_power != 13)
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
if (rf95_max_power != 20)
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
if (dio3_tcxo_voltage != 0)
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
if (lora_usb_pid != 0x5512)
out << YAML::Key << "USB_PID" << YAML::Value << YAML::Hex << lora_usb_pid;
if (lora_usb_vid != 0x1A86)
out << YAML::Key << "USB_VID" << YAML::Value << YAML::Hex << lora_usb_vid;
if (lora_spi_dev != "")
out << YAML::Key << "spidev" << YAML::Value << lora_spi_dev;
if (lora_usb_serial_num != "")
out << YAML::Key << "USB_Serialnum" << YAML::Value << lora_usb_serial_num;
out << YAML::Key << "spiSpeed" << YAML::Value << spiSpeed;
if (rfswitch_dio_pins[0] != RADIOLIB_NC) {
out << YAML::Key << "rfswitch_table" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pins";
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
for (int i = 0; i < 5; i++) {
// set up the pin array first
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO5)
out << "DIO5";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO6)
out << "DIO6";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO7)
out << "DIO7";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO8)
out << "DIO8";
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO10)
out << "DIO10";
}
out << YAML::EndSeq;
for (int i = 0; i < 7; i++) {
switch (i) {
case 0:
out << YAML::Key << "MODE_STBY";
break;
case 1:
out << YAML::Key << "MODE_RX";
break;
case 2:
out << YAML::Key << "MODE_TX";
break;
case 3:
out << YAML::Key << "MODE_TX_HP";
break;
case 4:
out << YAML::Key << "MODE_TX_HF";
break;
case 5:
out << YAML::Key << "MODE_GNSS";
break;
case 6:
out << YAML::Key << "MODE_WIFI";
break;
}
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
for (int j = 0; j < 5; j++) {
if (rfswitch_table[i].values[j] == HIGH) {
out << "HIGH";
} else {
out << "LOW";
}
}
out << YAML::EndSeq;
}
out << YAML::EndMap; // rfswitch_table
}
out << YAML::EndMap; // Lora
if (i2cdev != "") {
out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev;
out << YAML::EndMap; // I2C
}
// Display
if (displayPanel != no_screen) {
out << YAML::Key << "Display" << YAML::Value << YAML::BeginMap;
for (auto &screen_name : screen_names) {
if (displayPanel == screen_name.first)
out << YAML::Key << "Module" << YAML::Value << screen_name.second;
}
for (auto display_pin : all_pins) {
if (display_pin->config_section == "Display" && display_pin->enabled) {
out << YAML::Key << display_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << display_pin->pin;
out << YAML::Key << "line" << YAML::Value << display_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << display_pin->gpiochip;
out << YAML::EndMap;
}
}
out << YAML::Key << "spidev" << YAML::Value << display_spi_dev;
out << YAML::Key << "BusFrequency" << YAML::Value << displayBusFrequency;
if (displayWidth)
out << YAML::Key << "Width" << YAML::Value << displayWidth;
if (displayHeight)
out << YAML::Key << "Height" << YAML::Value << displayHeight;
if (displayRGBOrder)
out << YAML::Key << "RGBOrder" << YAML::Value << true;
if (displayBacklightInvert)
out << YAML::Key << "BacklightInvert" << YAML::Value << true;
if (displayRotate)
out << YAML::Key << "Rotate" << YAML::Value << true;
if (displayInvert)
out << YAML::Key << "Invert" << YAML::Value << true;
if (displayOffsetX)
out << YAML::Key << "OffsetX" << YAML::Value << displayOffsetX;
if (displayOffsetY)
out << YAML::Key << "OffsetY" << YAML::Value << displayOffsetY;
out << YAML::Key << "OffsetRotate" << YAML::Value << displayOffsetRotate;
out << YAML::EndMap; // Display
}
// Touchscreen
if (touchscreen_spi_dev != "") {
out << YAML::Key << "Touchscreen" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "spidev" << YAML::Value << touchscreen_spi_dev;
out << YAML::Key << "BusFrequency" << YAML::Value << touchscreenBusFrequency;
switch (touchscreenModule) {
case xpt2046:
out << YAML::Key << "Module" << YAML::Value << "XPT2046";
case stmpe610:
out << YAML::Key << "Module" << YAML::Value << "STMPE610";
case gt911:
out << YAML::Key << "Module" << YAML::Value << "GT911";
case ft5x06:
out << YAML::Key << "Module" << YAML::Value << "FT5x06";
}
for (auto touchscreen_pin : all_pins) {
if (touchscreen_pin->config_section == "Touchscreen" && touchscreen_pin->enabled) {
out << YAML::Key << touchscreen_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << touchscreen_pin->pin;
out << YAML::Key << "line" << YAML::Value << touchscreen_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << touchscreen_pin->gpiochip;
out << YAML::EndMap;
}
}
if (touchscreenRotate != -1)
out << YAML::Key << "Rotate" << YAML::Value << touchscreenRotate;
if (touchscreenI2CAddr != -1)
out << YAML::Key << "I2CAddr" << YAML::Value << touchscreenI2CAddr;
out << YAML::EndMap; // Touchscreen
}
// Input
out << YAML::Key << "Input" << YAML::Value << YAML::BeginMap;
if (keyboardDevice != "")
out << YAML::Key << "KeyboardDevice" << YAML::Value << keyboardDevice;
if (pointerDevice != "")
out << YAML::Key << "PointerDevice" << YAML::Value << pointerDevice;
for (auto input_pin : all_pins) {
if (input_pin->config_section == "Input" && input_pin->enabled) {
out << YAML::Key << input_pin->config_name << YAML::Value << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << input_pin->pin;
out << YAML::Key << "line" << YAML::Value << input_pin->line;
out << YAML::Key << "gpiochip" << YAML::Value << input_pin->gpiochip;
out << YAML::EndMap;
}
}
if (tbDirection == 3)
out << YAML::Key << "TrackballDirection" << YAML::Value << "FALLING";
out << YAML::EndMap; // Input
out << YAML::Key << "Logging" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "LogLevel" << YAML::Value;
switch (logoutputlevel) {
case level_error:
out << "error";
break;
case level_warn:
out << "warn";
break;
case level_info:
out << "info";
break;
case level_debug:
out << "debug";
break;
case level_trace:
out << "trace";
break;
}
if (traceFilename != "")
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
if (JSONFilename != "") {
out << YAML::Key << "JSONFile" << YAML::Value << JSONFilename;
if (JSONFilter == meshtastic_PortNum_TEXT_MESSAGE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "textmessage";
else if (JSONFilter == meshtastic_PortNum_TELEMETRY_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "telemetry";
else if (JSONFilter == meshtastic_PortNum_NODEINFO_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "nodeinfo";
else if (JSONFilter == meshtastic_PortNum_POSITION_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "position";
else if (JSONFilter == meshtastic_PortNum_WAYPOINT_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "waypoint";
else if (JSONFilter == meshtastic_PortNum_NEIGHBORINFO_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "neighborinfo";
else if (JSONFilter == meshtastic_PortNum_TRACEROUTE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "traceroute";
else if (JSONFilter == meshtastic_PortNum_DETECTION_SENSOR_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "detection";
else if (JSONFilter == meshtastic_PortNum_PAXCOUNTER_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "paxcounter";
else if (JSONFilter == meshtastic_PortNum_REMOTE_HARDWARE_APP)
out << YAML::Key << "JSONFilter" << YAML::Value << "remotehardware";
}
if (ascii_logs_explicit) {
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
}
out << YAML::EndMap; // Logging
// Webserver
if (webserver_root_path != "") {
out << YAML::Key << "Webserver" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "RootPath" << YAML::Value << webserver_root_path;
out << YAML::Key << "SSLKey" << YAML::Value << webserver_ssl_key_path;
out << YAML::Key << "SSLCert" << YAML::Value << webserver_ssl_cert_path;
out << YAML::Key << "Port" << YAML::Value << webserverport;
out << YAML::EndMap; // Webserver
}
// HostMetrics
if (hostMetrics_user_command != "") {
out << YAML::Key << "HostMetrics" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "UserStringCommand" << YAML::Value << hostMetrics_user_command;
out << YAML::Key << "ReportInterval" << YAML::Value << hostMetrics_interval;
out << YAML::Key << "Channel" << YAML::Value << hostMetrics_channel;
out << YAML::EndMap; // HostMetrics
}
// config
if (has_configDisplayMode) {
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
switch (configDisplayMode) {
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
break;
}
out << YAML::EndMap; // Config
}
// General
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
if (config_directory != "")
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
if (mac_address_explicit)
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
if (mac_address_source != "")
out << YAML::Key << "MACAddressSource" << YAML::Value << mac_address_source;
if (available_directory != "")
out << YAML::Key << "AvailableDirectory" << YAML::Value << available_directory;
out << YAML::Key << "MaxMessageQueue" << YAML::Value << maxtophone;
out << YAML::Key << "MaxNodes" << YAML::Value << MaxNodes;
out << YAML::EndMap; // General
return out.c_str();
}
} portduino_config;

View File

@@ -2,311 +2,341 @@
#include "MeshService.h"
#include "Router.h"
SimRadio::SimRadio() : NotifiedWorkerThread("SimRadio") { instance = this; }
SimRadio::SimRadio() : NotifiedWorkerThread("SimRadio")
{
instance = this;
}
SimRadio *SimRadio::instance;
ErrorCode SimRadio::send(meshtastic_MeshPacket *p) {
printPacket("enqueuing for send", p);
ErrorCode SimRadio::send(meshtastic_MeshPacket *p)
{
printPacket("enqueuing for send", p);
bool dropped = false;
ErrorCode res = txQueue.enqueue(p, &dropped) ? ERRNO_OK : ERRNO_UNKNOWN;
bool dropped = false;
ErrorCode res = txQueue.enqueue(p, &dropped) ? ERRNO_OK : ERRNO_UNKNOWN;
if (dropped) {
txDrop++;
}
if (dropped) {
txDrop++;
}
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p);
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p);
return res;
}
// set (random) transmit delay to let others reconfigure their radio,
// to avoid collisions and implement timing-based flooding
LOG_DEBUG("Set random delay before tx");
setTransmitDelay();
return res;
}
// set (random) transmit delay to let others reconfigure their radio,
// to avoid collisions and implement timing-based flooding
LOG_DEBUG("Set random delay before tx");
setTransmitDelay();
return res;
}
void SimRadio::setTransmitDelay() {
meshtastic_MeshPacket *p = txQueue.getFront();
// We want all sending/receiving to be done by our daemon thread.
// We use a delay here because this packet might have been sent in response to a packet we just received.
// So we want to make sure the other side has had a chance to reconfigure its radio.
void SimRadio::setTransmitDelay()
{
meshtastic_MeshPacket *p = txQueue.getFront();
// We want all sending/receiving to be done by our daemon thread.
// We use a delay here because this packet might have been sent in response to a packet we just received.
// So we want to make sure the other side has had a chance to reconfigure its radio.
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
* This assumption is valid because of the offset generated by the radio to account for the noise
* floor.
*/
if (p->rx_snr == 0 && p->rx_rssi == 0) {
startTransmitTimer(true);
} else {
// If there is a SNR, start a timer scaled based on that SNR.
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f", p->hop_limit, p->rx_snr);
startTransmitTimerRebroadcast(p);
}
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
* This assumption is valid because of the offset generated by the radio to account for the noise
* floor.
*/
if (p->rx_snr == 0 && p->rx_rssi == 0) {
startTransmitTimer(true);
} else {
// If there is a SNR, start a timer scaled based on that SNR.
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f", p->hop_limit, p->rx_snr);
startTransmitTimerRebroadcast(p);
}
}
void SimRadio::startTransmitTimer(bool withDelay) {
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
// LOG_DEBUG("xmit timer %d", delay);
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
}
void SimRadio::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
// LOG_DEBUG("xmit timer %d", delay);
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
}
}
void SimRadio::startTransmitTimerRebroadcast(meshtastic_MeshPacket *p) {
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delayMsec = getTxDelayMsecWeighted(p);
// LOG_DEBUG("xmit timer %d", delay);
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
}
void SimRadio::startTransmitTimerRebroadcast(meshtastic_MeshPacket *p)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delayMsec = getTxDelayMsecWeighted(p);
// LOG_DEBUG("xmit timer %d", delay);
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
}
}
void SimRadio::handleTransmitInterrupt() {
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending();
void SimRadio::handleTransmitInterrupt()
{
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending();
isReceiving = true;
if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough
handleReceiveInterrupt();
isReceiving = true;
if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough
handleReceiveInterrupt();
}
void SimRadio::completeSending() {
// We are careful to clear sending packet before calling printPacket because
// that can take a long time
auto p = sendingPacket;
sendingPacket = NULL;
void SimRadio::completeSending()
{
// We are careful to clear sending packet before calling printPacket because
// that can take a long time
auto p = sendingPacket;
sendingPacket = NULL;
if (p) {
txGood++;
if (!isFromUs(p))
txRelay++;
printPacket("Completed sending", p);
if (p) {
txGood++;
if (!isFromUs(p))
txRelay++;
printPacket("Completed sending", p);
// We are done sending that packet, release it
packetPool.release(p);
// LOG_DEBUG("Done with send");
}
// We are done sending that packet, release it
packetPool.release(p);
// LOG_DEBUG("Done with send");
}
}
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
bool SimRadio::canSendImmediately() {
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
// we almost certainly guarantee no one outside will like the packet we are sending.
bool busyTx = sendingPacket != NULL;
bool busyRx = isReceiving && isActivelyReceiving();
bool SimRadio::canSendImmediately()
{
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
// we almost certainly guarantee no one outside will like the packet we are sending.
bool busyTx = sendingPacket != NULL;
bool busyRx = isReceiving && isActivelyReceiving();
if (busyTx || busyRx) {
if (busyTx)
LOG_WARN("Can not send yet, busyTx");
if (busyRx)
LOG_WARN("Can not send yet, busyRx");
return false;
} else
return true;
if (busyTx || busyRx) {
if (busyTx)
LOG_WARN("Can not send yet, busyTx");
if (busyRx)
LOG_WARN("Can not send yet, busyRx");
return false;
} else
return true;
}
bool SimRadio::isActivelyReceiving() { return receivingPacket != nullptr; }
bool SimRadio::isActivelyReceiving()
{
return receivingPacket != nullptr;
}
bool SimRadio::isChannelActive() { return receivingPacket != nullptr; }
bool SimRadio::isChannelActive()
{
return receivingPacket != nullptr;
}
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool SimRadio::cancelSending(NodeNum from, PacketId id) {
auto p = txQueue.remove(from, id);
if (p)
packetPool.release(p); // free the packet we just removed
bool SimRadio::cancelSending(NodeNum from, PacketId id)
{
auto p = txQueue.remove(from, id);
if (p)
packetPool.release(p); // free the packet we just removed
bool result = (p != NULL);
LOG_DEBUG("cancelSending id=0x%x, removed=%d", id, result);
return result;
bool result = (p != NULL);
LOG_DEBUG("cancelSending id=0x%x, removed=%d", id, result);
return result;
}
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
bool SimRadio::findInTxQueue(NodeNum from, PacketId id) { return txQueue.find(from, id); }
bool SimRadio::findInTxQueue(NodeNum from, PacketId id)
{
return txQueue.find(from, id);
}
void SimRadio::onNotify(uint32_t notification) {
switch (notification) {
case ISR_TX:
handleTransmitInterrupt();
// LOG_DEBUG("tx complete - starting timer");
startTransmitTimer();
break;
case ISR_RX:
handleReceiveInterrupt();
// LOG_DEBUG("rx complete - starting timer");
startTransmitTimer();
break;
case TRANSMIT_DELAY_COMPLETED:
if (receivingPacket) { // This happens when we had a timer pending and we started receiving
handleReceiveInterrupt();
startTransmitTimer();
break;
}
LOG_DEBUG("delay done");
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
if (!txQueue.empty()) {
if (!canSendImmediately()) {
// LOG_DEBUG("Currently Rx/Tx-ing: set random delay");
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
} else {
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
// LOG_DEBUG("Channel is active: set random delay");
setTransmitDelay(); // reset random delay
} else {
// Send any outgoing packets we have ready
meshtastic_MeshPacket *txp = txQueue.dequeue();
assert(txp);
startSend(txp);
// Packet has been sent, count it toward our TX airtime utilization.
uint32_t xmitMsec = RadioInterface::getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec);
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
void SimRadio::onNotify(uint32_t notification)
{
switch (notification) {
case ISR_TX:
handleTransmitInterrupt();
// LOG_DEBUG("tx complete - starting timer");
startTransmitTimer();
break;
case ISR_RX:
handleReceiveInterrupt();
// LOG_DEBUG("rx complete - starting timer");
startTransmitTimer();
break;
case TRANSMIT_DELAY_COMPLETED:
if (receivingPacket) { // This happens when we had a timer pending and we started receiving
handleReceiveInterrupt();
startTransmitTimer();
break;
}
}
} else {
// LOG_DEBUG("done with txqueue");
LOG_DEBUG("delay done");
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
if (!txQueue.empty()) {
if (!canSendImmediately()) {
// LOG_DEBUG("Currently Rx/Tx-ing: set random delay");
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
} else {
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
// LOG_DEBUG("Channel is active: set random delay");
setTransmitDelay(); // reset random delay
} else {
// Send any outgoing packets we have ready
meshtastic_MeshPacket *txp = txQueue.dequeue();
assert(txp);
startSend(txp);
// Packet has been sent, count it toward our TX airtime utilization.
uint32_t xmitMsec = RadioInterface::getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec);
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
}
}
} else {
// LOG_DEBUG("done with txqueue");
}
break;
default:
assert(0); // We expected to receive a valid notification from the ISR
}
break;
default:
assert(0); // We expected to receive a valid notification from the ISR
}
}
/** start an immediate transmit */
void SimRadio::startSend(meshtastic_MeshPacket *txp) {
printPacket("Start low level send", txp);
isReceiving = false;
size_t numbytes = beginSending(txp);
meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
perhapsDecode(p);
meshtastic_Compressed c = meshtastic_Compressed_init_default;
c.portnum = p->decoded.portnum;
// LOG_DEBUG("Send back to simulator with portNum %d", p->decoded.portnum);
if (p->decoded.payload.size <= sizeof(c.data.bytes)) {
memcpy(&c.data.bytes, p->decoded.payload.bytes, p->decoded.payload.size);
c.data.size = p->decoded.payload.size;
} else {
LOG_WARN("Payload size larger than compressed message allows! Send empty payload");
}
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Compressed_msg, &c);
p->decoded.portnum = meshtastic_PortNum_SIMULATOR_APP;
void SimRadio::startSend(meshtastic_MeshPacket *txp)
{
printPacket("Start low level send", txp);
isReceiving = false;
size_t numbytes = beginSending(txp);
meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
perhapsDecode(p);
meshtastic_Compressed c = meshtastic_Compressed_init_default;
c.portnum = p->decoded.portnum;
// LOG_DEBUG("Send back to simulator with portNum %d", p->decoded.portnum);
if (p->decoded.payload.size <= sizeof(c.data.bytes)) {
memcpy(&c.data.bytes, p->decoded.payload.bytes, p->decoded.payload.size);
c.data.size = p->decoded.payload.size;
} else {
LOG_WARN("Payload size larger than compressed message allows! Send empty payload");
}
p->decoded.payload.size =
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Compressed_msg, &c);
p->decoded.portnum = meshtastic_PortNum_SIMULATOR_APP;
service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id);
service->sendToPhone(p); // Sending back to simulator
service->loop(); // Process the send immediately
service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id);
service->sendToPhone(p); // Sending back to simulator
service->loop(); // Process the send immediately
}
// Simulates device received a packet via the LoRa chip
void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p) {
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
meshtastic_Compressed scratch;
meshtastic_Compressed *decoded = NULL;
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch));
p.decoded.payload.size = pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
if (p.decoded.payload.size) {
decoded = &scratch;
// Extract the original payload and replace
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
p.decoded.portnum = decoded->portnum;
} else
LOG_ERROR("Error decoding proto for simulator message!");
}
// Let SimRadio receive as if it did via its LoRa chip
startReceive(&p);
void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p)
{
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
meshtastic_Compressed scratch;
meshtastic_Compressed *decoded = NULL;
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch));
p.decoded.payload.size =
pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
if (p.decoded.payload.size) {
decoded = &scratch;
// Extract the original payload and replace
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
p.decoded.portnum = decoded->portnum;
} else
LOG_ERROR("Error decoding proto for simulator message!");
}
// Let SimRadio receive as if it did via its LoRa chip
startReceive(&p);
}
void SimRadio::startReceive(meshtastic_MeshPacket *p) {
void SimRadio::startReceive(meshtastic_MeshPacket *p)
{
#ifdef USERPREFS_SIMRADIO_EMULATE_COLLISIONS
if (isActivelyReceiving()) {
LOG_WARN("Collision detected, dropping current and previous packet!");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true));
packetPool.release(receivingPacket);
receivingPacket = nullptr;
return;
} else if (sendingPacket) {
uint32_t airtimeLeft = tillRun(millis());
if (airtimeLeft <= 0) {
LOG_WARN("Transmitting packet was already done");
handleTransmitInterrupt(); // Finish sending first
} else if ((interval - airtimeLeft) > preambleTimeMsec) {
// Only if transmitting for longer than preamble there is a collision
// (channel should actually be detected as active otherwise)
LOG_WARN("Collision detected during transmission!");
return;
if (isActivelyReceiving()) {
LOG_WARN("Collision detected, dropping current and previous packet!");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true));
packetPool.release(receivingPacket);
receivingPacket = nullptr;
return;
} else if (sendingPacket) {
uint32_t airtimeLeft = tillRun(millis());
if (airtimeLeft <= 0) {
LOG_WARN("Transmitting packet was already done");
handleTransmitInterrupt(); // Finish sending first
} else if ((interval - airtimeLeft) > preambleTimeMsec) {
// Only if transmitting for longer than preamble there is a collision
// (channel should actually be detected as active otherwise)
LOG_WARN("Collision detected during transmission!");
return;
}
}
}
isReceiving = true;
receivingPacket = packetPool.allocCopy(*p);
uint32_t airtimeMsec = getPacketTime(p, true);
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
isReceiving = true;
receivingPacket = packetPool.allocCopy(*p);
uint32_t airtimeMsec = getPacketTime(p, true);
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
#else
isReceiving = true;
receivingPacket = packetPool.allocCopy(*p);
handleReceiveInterrupt(); // Simulate receiving the packet immediately
startTransmitTimer();
isReceiving = true;
receivingPacket = packetPool.allocCopy(*p);
handleReceiveInterrupt(); // Simulate receiving the packet immediately
startTransmitTimer();
#endif
}
meshtastic_QueueStatus SimRadio::getQueueStatus() {
meshtastic_QueueStatus qs;
meshtastic_QueueStatus SimRadio::getQueueStatus()
{
meshtastic_QueueStatus qs;
qs.res = qs.mesh_packet_id = 0;
qs.free = txQueue.getFree();
qs.maxlen = txQueue.getMaxLen();
qs.res = qs.mesh_packet_id = 0;
qs.free = txQueue.getFree();
qs.maxlen = txQueue.getMaxLen();
return qs;
return qs;
}
void SimRadio::handleReceiveInterrupt() {
if (receivingPacket == nullptr) {
return;
}
void SimRadio::handleReceiveInterrupt()
{
if (receivingPacket == nullptr) {
return;
}
if (!isReceiving) {
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode");
return;
}
if (!isReceiving) {
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode");
return;
}
LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
rxGood++;
LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
rxGood++;
meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
packetPool.release(receivingPacket); // release the original
receivingPacket = nullptr;
meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
packetPool.release(receivingPacket); // release the original
receivingPacket = nullptr;
printPacket("Lora RX", mp);
printPacket("Lora RX", mp);
airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true));
airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true));
deliverToReceiver(mp);
deliverToReceiver(mp);
}
size_t SimRadio::getPacketLength(meshtastic_MeshPacket *mp) {
auto &p = mp->decoded;
return (size_t)p.payload.size + sizeof(PacketHeader);
size_t SimRadio::getPacketLength(meshtastic_MeshPacket *mp)
{
auto &p = mp->decoded;
return (size_t)p.payload.size + sizeof(PacketHeader);
}
int16_t SimRadio::readData(uint8_t *data, size_t len) {
int16_t state = RADIOLIB_ERR_NONE;
int16_t SimRadio::readData(uint8_t *data, size_t len)
{
int16_t state = RADIOLIB_ERR_NONE;
if (state == RADIOLIB_ERR_NONE) {
// add null terminator
data[len] = 0;
}
if (state == RADIOLIB_ERR_NONE) {
// add null terminator
data[len] = 0;
}
return state;
return state;
}
/**
@@ -316,18 +346,20 @@ int16_t SimRadio::readData(uint8_t *data, size_t len) {
*
* @return num msecs for the packet
*/
uint32_t SimRadio::getPacketTime(uint32_t pl, bool received) {
float bandwidthHz = bw * 1000.0f;
bool headDisable = false; // we currently always use the header
float tSym = (1 << sf) / bandwidthHz;
uint32_t SimRadio::getPacketTime(uint32_t pl, bool received)
{
float bandwidthHz = bw * 1000.0f;
bool headDisable = false; // we currently always use the header
float tSym = (1 << sf) / bandwidthHz;
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
float tPreamble = (preambleLength + 4.25f) * tSym;
float numPayloadSym = 8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
float tPayload = numPayloadSym * tSym;
float tPacket = tPreamble + tPayload;
float tPreamble = (preambleLength + 4.25f) * tSym;
float numPayloadSym =
8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
float tPayload = numPayloadSym * tSym;
float tPacket = tPreamble + tPayload;
uint32_t msecs = tPacket * 1000;
return msecs;
uint32_t msecs = tPacket * 1000;
return msecs;
}

View File

@@ -7,89 +7,90 @@
#include <RadioLib.h>
class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThread {
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThread
{
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
public:
SimRadio();
public:
SimRadio();
/** MeshService needs this to find our active instance
*/
static SimRadio *instance;
/** MeshService needs this to find our active instance
*/
static SimRadio *instance;
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive();
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive();
/** are we actively receiving a packet (only called during receiving state)
* This method is only public to facilitate debugging. Do not call.
*/
virtual bool isActivelyReceiving();
/** are we actively receiving a packet (only called during receiving state)
* This method is only public to facilitate debugging. Do not call.
*/
virtual bool isActivelyReceiving();
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id) override;
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id) override;
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
/**
* Start waiting to receive a message
*
* External functions can call this method to wake the device from sleep.
*/
virtual void startReceive(meshtastic_MeshPacket *p);
/**
* Start waiting to receive a message
*
* External functions can call this method to wake the device from sleep.
*/
virtual void startReceive(meshtastic_MeshPacket *p);
meshtastic_QueueStatus getQueueStatus() override;
meshtastic_QueueStatus getQueueStatus() override;
// Convert Compressed_msg to normal msg and receive it
void unpackAndReceive(meshtastic_MeshPacket &p);
// Convert Compressed_msg to normal msg and receive it
void unpackAndReceive(meshtastic_MeshPacket &p);
/**
* Debugging counts
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
uint16_t txDrop = 0;
/**
* Debugging counts
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
uint16_t txDrop = 0;
protected:
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
bool isReceiving = true;
protected:
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
bool isReceiving = true;
private:
void setTransmitDelay();
private:
void setTransmitDelay();
/** random timer with certain min. and max. settings */
void startTransmitTimer(bool withDelay = true);
/** random timer with certain min. and max. settings */
void startTransmitTimer(bool withDelay = true);
/** timer scaled to SNR of to be flooded packet */
void startTransmitTimerRebroadcast(meshtastic_MeshPacket *p);
/** timer scaled to SNR of to be flooded packet */
void startTransmitTimerRebroadcast(meshtastic_MeshPacket *p);
void handleTransmitInterrupt();
void handleReceiveInterrupt();
void handleTransmitInterrupt();
void handleReceiveInterrupt();
void onNotify(uint32_t notification);
void onNotify(uint32_t notification);
// start an immediate transmit
virtual void startSend(meshtastic_MeshPacket *txp);
// start an immediate transmit
virtual void startSend(meshtastic_MeshPacket *txp);
// derive packet length
size_t getPacketLength(meshtastic_MeshPacket *p);
// derive packet length
size_t getPacketLength(meshtastic_MeshPacket *p);
int16_t readData(uint8_t *str, size_t len);
int16_t readData(uint8_t *str, size_t len);
meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving
meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving
protected:
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
virtual bool canSendImmediately();
protected:
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
virtual bool canSendImmediately();
/**
* If a send was in progress finish it and return the buffer to the pool */
void completeSending();
/**
* If a send was in progress finish it and return the buffer to the pool */
void completeSending();
virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override;
virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override;
};
extern SimRadio *simRadio;

View File

@@ -23,132 +23,146 @@
// the HAL must inherit from the base RadioLibHal class
// and implement all of its virtual methods
class Ch341Hal : public RadioLibHal {
public:
// default constructor - initializes the base HAL and any needed private members
explicit Ch341Hal(uint8_t spiChannel, std::string serial = "", uint32_t vid = 0x1A86, uint32_t pid = 0x5512, uint32_t spiSpeed = 2000000,
uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING) {
if (serial != "") {
strncpy(pinedio.serial_number, serial.c_str(), 8);
pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
}
// LOG_INFO("USB Serial: %s", pinedio.serial_number);
class Ch341Hal : public RadioLibHal
{
public:
// default constructor - initializes the base HAL and any needed private members
explicit Ch341Hal(uint8_t spiChannel, std::string serial = "", uint32_t vid = 0x1A86, uint32_t pid = 0x5512,
uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING)
{
if (serial != "") {
strncpy(pinedio.serial_number, serial.c_str(), 8);
pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
}
// LOG_INFO("USB Serial: %s", pinedio.serial_number);
// There is no vendor with 0x0 -> so check
if (vid != 0x0) {
pinedio_set_option(&pinedio, PINEDIO_OPTION_VID, vid);
pinedio_set_option(&pinedio, PINEDIO_OPTION_PID, pid);
}
int32_t ret = pinedio_init(&pinedio, NULL);
if (ret != 0) {
std::string s = "Could not open SPI: ";
throw(s + std::to_string(ret));
// There is no vendor with 0x0 -> so check
if (vid != 0x0) {
pinedio_set_option(&pinedio, PINEDIO_OPTION_VID, vid);
pinedio_set_option(&pinedio, PINEDIO_OPTION_PID, pid);
}
int32_t ret = pinedio_init(&pinedio, NULL);
if (ret != 0) {
std::string s = "Could not open SPI: ";
throw(s + std::to_string(ret));
}
pinedio_set_option(&pinedio, PINEDIO_OPTION_AUTO_CS, 0);
pinedio_set_pin_mode(&pinedio, 3, true);
pinedio_set_pin_mode(&pinedio, 5, true);
}
pinedio_set_option(&pinedio, PINEDIO_OPTION_AUTO_CS, 0);
pinedio_set_pin_mode(&pinedio, 3, true);
pinedio_set_pin_mode(&pinedio, 5, true);
}
~Ch341Hal() { pinedio_deinit(&pinedio); }
~Ch341Hal() { pinedio_deinit(&pinedio); }
void getSerialString(char *_serial, size_t len) {
len = len > 8 ? 8 : len;
strncpy(_serial, pinedio.serial_number, len);
}
void getProductString(char *_product_string, size_t len) {
len = len > 95 ? 95 : len;
strncpy(_product_string, pinedio.product_string, len);
}
void init() override {}
void term() override {}
// GPIO-related methods (pinMode, digitalWrite etc.) should check
// RADIOLIB_NC as an alias for non-connected pins
void pinMode(uint32_t pin, uint32_t mode) override {
if (pin == RADIOLIB_NC) {
return;
void getSerialString(char *_serial, size_t len)
{
len = len > 8 ? 8 : len;
strncpy(_serial, pinedio.serial_number, len);
}
pinedio_set_pin_mode(&pinedio, pin, mode);
}
void digitalWrite(uint32_t pin, uint32_t value) override {
if (pin == RADIOLIB_NC) {
return;
void getProductString(char *_product_string, size_t len)
{
len = len > 95 ? 95 : len;
strncpy(_product_string, pinedio.product_string, len);
}
pinedio_digital_write(&pinedio, pin, value);
}
uint32_t digitalRead(uint32_t pin) override {
if (pin == RADIOLIB_NC) {
return 0;
void init() override {}
void term() override {}
// GPIO-related methods (pinMode, digitalWrite etc.) should check
// RADIOLIB_NC as an alias for non-connected pins
void pinMode(uint32_t pin, uint32_t mode) override
{
if (pin == RADIOLIB_NC) {
return;
}
pinedio_set_pin_mode(&pinedio, pin, mode);
}
return pinedio_digital_read(&pinedio, pin);
}
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
if (interruptNum == RADIOLIB_NC) {
return;
void digitalWrite(uint32_t pin, uint32_t value) override
{
if (pin == RADIOLIB_NC) {
return;
}
pinedio_digital_write(&pinedio, pin, value);
}
// LOG_DEBUG("Attach interrupt to pin %d", interruptNum);
pinedio_attach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum, (pinedio_int_mode)mode, interruptCb);
}
void detachInterrupt(uint32_t interruptNum) override {
if (interruptNum == RADIOLIB_NC) {
return;
uint32_t digitalRead(uint32_t pin) override
{
if (pin == RADIOLIB_NC) {
return 0;
}
return pinedio_digital_read(&pinedio, pin);
}
// LOG_DEBUG("Detach interrupt from pin %d", interruptNum);
pinedio_deattach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum);
}
void delay(unsigned long ms) override { delayMicroseconds(ms * 1000); }
void delayMicroseconds(unsigned long us) override {
if (us == 0) {
sched_yield();
return;
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override
{
if (interruptNum == RADIOLIB_NC) {
return;
}
// LOG_DEBUG("Attach interrupt to pin %d", interruptNum);
pinedio_attach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum, (pinedio_int_mode)mode, interruptCb);
}
usleep(us);
}
void yield() override { sched_yield(); }
unsigned long millis() override {
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL);
}
unsigned long micros() override {
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
}
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
std::cerr << "pulseIn for pin " << pin << "is not supported!" << std::endl;
return 0;
}
void spiBegin() {}
void spiBeginTransaction() {}
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) {
int32_t ret = pinedio_transceive(&this->pinedio, out, in, len);
if (ret < 0) {
std::cerr << "Could not perform SPI transfer: " << ret << std::endl;
void detachInterrupt(uint32_t interruptNum) override
{
if (interruptNum == RADIOLIB_NC) {
return;
}
// LOG_DEBUG("Detach interrupt from pin %d", interruptNum);
pinedio_deattach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum);
}
}
void spiEndTransaction() {}
void spiEnd() {}
void delay(unsigned long ms) override { delayMicroseconds(ms * 1000); }
private:
pinedio_inst pinedio = {0};
void delayMicroseconds(unsigned long us) override
{
if (us == 0) {
sched_yield();
return;
}
usleep(us);
}
void yield() override { sched_yield(); }
unsigned long millis() override
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL);
}
unsigned long micros() override
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
}
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
{
std::cerr << "pulseIn for pin " << pin << "is not supported!" << std::endl;
return 0;
}
void spiBegin() {}
void spiBeginTransaction() {}
void spiTransfer(uint8_t *out, size_t len, uint8_t *in)
{
int32_t ret = pinedio_transceive(&this->pinedio, out, in, len);
if (ret < 0) {
std::cerr << "Could not perform SPI transfer: " << ret << std::endl;
}
}
void spiEndTransaction() {}
void spiEnd() {}
private:
pinedio_inst pinedio = {0};
};
#endif