add LR 2021 to portduino, and allow Framebuffer devices to rotate the screen from config (#11252)

* add LR 2021 to portduino, and allow Framebuffer devices to rotate the screen from config. Requires https://github.com/meshtastic/device-ui/pull/355 and supersedes https://github.com/meshtastic/firmware/pull/10567 and https://github.com/meshtastic/firmware/pull/11138

Many thanks to the original authors https://github.com/a-li3n and https://github.com/jessm33

* Build LR2021Interface.cpp in the wasm env

initLoRa() constructs LR2021Interface for Lora.Module: lr2021, so excluding
the file from the native-wasm source filter left the constructor undefined at
link time. LR20x0Interface.cpp stays excluded; it is template-only and comes in
via the InterfacesTemplates.cpp amalgamation.

Also replace the non-UTF-8 degree signs in the framebuffer rotation comment and
correct the rfswitch alias cleanup comment.

* Trim comments

* Report setenv failure for the framebuffer rotation
This commit is contained in:
Thomas Göttgens
2026-07-30 10:44:52 +00:00
committed by GitHub
co-authored by GitHub
parent 16765dd089
commit 047c4e9feb
9 changed files with 39 additions and 8 deletions
+7
View File
@@ -11,6 +11,8 @@
#ifdef ARCH_PORTDUINO #ifdef ARCH_PORTDUINO
#include "PortduinoGlue.h" #include "PortduinoGlue.h"
#include <cstdio>
#include <cstdlib>
#include <thread> #include <thread>
#endif #endif
@@ -60,6 +62,11 @@ void tftSetup(void)
} else } else
#elif defined(USE_FRAMEBUFFER) #elif defined(USE_FRAMEBUFFER)
if (portduino_config.displayPanel == fb) { if (portduino_config.displayPanel == fb) {
// Rotation from yaml Display.OffsetRotate: 1=90, 2=180, 3=270 deg
char rbuf[4];
snprintf(rbuf, sizeof(rbuf), "%d", portduino_config.displayRotate ? (portduino_config.displayOffsetRotate & 3) : 0);
if (setenv("MESHTASTIC_FB_ROTATION", rbuf, 1) != 0)
LOG_ERROR("Failed to set MESHTASTIC_FB_ROTATION, framebuffer will use its default rotation");
if (portduino_config.displayWidth && portduino_config.displayHeight) if (portduino_config.displayWidth && portduino_config.displayHeight)
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)portduino_config.displayWidth, displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)portduino_config.displayWidth,
(uint16_t)portduino_config.displayHeight); (uint16_t)portduino_config.displayHeight);
+1 -1
View File
@@ -27,7 +27,7 @@ template class LR11x0Interface<LR1110>;
template class LR11x0Interface<LR1120>; template class LR11x0Interface<LR1120>;
template class LR11x0Interface<LR1121>; template class LR11x0Interface<LR1121>;
#endif #endif
#if defined(USE_LR2021) && RADIOLIB_EXCLUDE_LR2021 != 1 #if (defined(USE_LR2021) || defined(ARCH_PORTDUINO)) && RADIOLIB_EXCLUDE_LR2021 != 1
template class LR20x0Interface<LR2021>; template class LR20x0Interface<LR2021>;
#endif #endif
#ifdef ARCH_STM32WL #ifdef ARCH_STM32WL
+4
View File
@@ -379,4 +379,8 @@ template <typename T> int16_t LR11x0Interface<T>::getCurrentRSSI()
#endif #endif
return (int16_t)round(rssi); return (int16_t)round(rssi);
} }
// Don't leak the aliases into the files InterfacesTemplates.cpp includes after this one.
#undef rfswitch_dio_pins
#undef rfswitch_table
#endif #endif
+1 -1
View File
@@ -1,6 +1,6 @@
#include "configuration.h" #include "configuration.h"
#if defined(USE_LR2021) && RADIOLIB_EXCLUDE_LR2021 != 1 #if (defined(USE_LR2021) || defined(ARCH_PORTDUINO)) && RADIOLIB_EXCLUDE_LR2021 != 1
#include "LR2021Interface.h" #include "LR2021Interface.h"
#include "error.h" #include "error.h"
+6 -1
View File
@@ -1,6 +1,6 @@
#include "configuration.h" #include "configuration.h"
#if defined(USE_LR2021) && RADIOLIB_EXCLUDE_LR2021 != 1 #if (defined(USE_LR2021) || defined(ARCH_PORTDUINO)) && RADIOLIB_EXCLUDE_LR2021 != 1
#include "LR20x0Interface.h" #include "LR20x0Interface.h"
#include "error.h" #include "error.h"
#include "mesh/NodeDB.h" #include "mesh/NodeDB.h"
@@ -381,4 +381,9 @@ template <typename T> int16_t LR20x0Interface<T>::getCurrentRSSI()
float rssi = lora.getRSSI(false, true); float rssi = lora.getRSSI(false, true);
return (int16_t)round(rssi); return (int16_t)round(rssi);
} }
// Don't leak the aliases into the files InterfacesTemplates.cpp includes after this one.
#undef lr20x0_rfswitch_dio_pins
#undef lr20x0_rfswitch_table
#undef LR20x0
#endif #endif
+2
View File
@@ -401,6 +401,8 @@ std::unique_ptr<RadioInterface> initLoRa()
return std::unique_ptr<RadioInterface>(new LR1121Interface(hal, cs, irq, rst, busy)); return std::unique_ptr<RadioInterface>(new LR1121Interface(hal, cs, irq, rst, busy));
case use_llcc68: case use_llcc68:
return std::unique_ptr<RadioInterface>(new LLCC68Interface(hal, cs, irq, rst, busy)); return std::unique_ptr<RadioInterface>(new LLCC68Interface(hal, cs, irq, rst, busy));
case use_lr2021:
return std::unique_ptr<RadioInterface>(new LR2021Interface(hal, cs, irq, rst, busy));
case use_simradio: case use_simradio:
return std::unique_ptr<RadioInterface>(new SimRadio); return std::unique_ptr<RadioInterface>(new SimRadio);
default: default:
+4
View File
@@ -899,6 +899,10 @@ bool loadConfig(const char *configPath)
portduino_config.lr1110_max_power = yamlConfig["Lora"]["LR1110_MAX_POWER"].as<int>(22); portduino_config.lr1110_max_power = yamlConfig["Lora"]["LR1110_MAX_POWER"].as<int>(22);
if (yamlConfig["Lora"]["LR1120_MAX_POWER"]) if (yamlConfig["Lora"]["LR1120_MAX_POWER"])
portduino_config.lr1120_max_power = yamlConfig["Lora"]["LR1120_MAX_POWER"].as<int>(13); portduino_config.lr1120_max_power = yamlConfig["Lora"]["LR1120_MAX_POWER"].as<int>(13);
if (yamlConfig["Lora"]["LR2021_MAX_POWER"])
portduino_config.lr2021_max_power = yamlConfig["Lora"]["LR2021_MAX_POWER"].as<int>(22);
if (yamlConfig["Lora"]["LR2021_MAX_POWER_HF"])
portduino_config.lr2021_max_power_hf = yamlConfig["Lora"]["LR2021_MAX_POWER_HF"].as<int>(12);
if (yamlConfig["Lora"]["RF95_MAX_POWER"]) if (yamlConfig["Lora"]["RF95_MAX_POWER"])
portduino_config.rf95_max_power = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20); portduino_config.rf95_max_power = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20);
+12 -4
View File
@@ -47,7 +47,8 @@ enum lora_module_enum {
use_lr1110, use_lr1110,
use_lr1120, use_lr1120,
use_lr1121, use_lr1121,
use_llcc68 use_llcc68,
use_lr2021
}; };
struct pinMapping { struct pinMapping {
@@ -76,9 +77,10 @@ std::string exec(const char *cmd);
extern struct portduino_config_struct { extern struct portduino_config_struct {
// Lora // Lora
std::map<lora_module_enum, std::string> loraModules = { std::map<lora_module_enum, std::string> loraModules = {{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"},
{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
{use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}}; {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"},
{use_llcc68, "LLCC68"}, {use_lr2021, "lr2021"}};
std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"}, std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"},
{st7735, "ST7735"}, {st7735s, "ST7735S"}, {st7796, "ST7796"}, {st7735, "ST7735"}, {st7735s, "ST7735S"}, {st7796, "ST7796"},
@@ -100,6 +102,8 @@ extern struct portduino_config_struct {
int sx128x_max_power = 13; int sx128x_max_power = 13;
int lr1110_max_power = 22; int lr1110_max_power = 22;
int lr1120_max_power = 13; int lr1120_max_power = 13;
int lr2021_max_power = 22;
int lr2021_max_power_hf = 12;
int rf95_max_power = 20; int rf95_max_power = 20;
bool dio2_as_rf_switch = false; bool dio2_as_rf_switch = false;
int dio3_tcxo_voltage = 0; int dio3_tcxo_voltage = 0;
@@ -287,6 +291,10 @@ extern struct portduino_config_struct {
out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power; out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power;
if (lr1120_max_power != 13) if (lr1120_max_power != 13)
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power; out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
if (lr2021_max_power != 22)
out << YAML::Key << "LR2021_MAX_POWER" << YAML::Value << lr2021_max_power;
if (lr2021_max_power_hf != 12)
out << YAML::Key << "LR2021_MAX_POWER_HF" << YAML::Value << lr2021_max_power_hf;
if (rf95_max_power != 20) if (rf95_max_power != 20)
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power; out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
+2 -1
View File
@@ -431,7 +431,8 @@ build_src_filter =
+<gps/RTC.cpp> +<gps/RTC.cpp>
+<buzz/buzz.cpp> +<buzz/BuzzerFeedbackThread.cpp> +<buzz/buzz.cpp> +<buzz/BuzzerFeedbackThread.cpp>
+<mesh/*.cpp> +<mesh/*.c> +<mesh/*.cpp> +<mesh/*.c>
-<mesh/LR2021Interface.cpp> -<mesh/LR20x0Interface.cpp> ; template-only, amalgamated into InterfacesTemplates.cpp
-<mesh/LR20x0Interface.cpp>
+<mesh/generated/> +<mesh/generated/>
+<concurrency/> +<concurrency/>
+<platform/portduino/PortduinoGlue.cpp> +<platform/portduino/SimRadio.cpp> +<platform/portduino/PortduinoGlue.cpp> +<platform/portduino/SimRadio.cpp>