Compare commits

...

7 Commits

Author SHA1 Message Date
Jonathan Bennett
a0e2b06970 Merge branch 'develop' into agc-reset 2026-01-28 16:17:28 -06:00
Jonathan Bennett
1d219a93ab Move input init to an init function in InputBroker (#9463)
* Move input init to an init function in iInputBroker

* Unbreak targets with EXCLUDE_INPUTBROKER

* Update src/input/InputBroker.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix conditional compilation for input broker

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Trunk

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 14:58:05 -06:00
Eric Severance
f710cd6ecb Support fully direct request/responses (#9455)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-28 14:14:01 -06:00
Jonathan Bennett
571c1ac34c Initial serialModule cleanup (#9465)
* Initial serialModule cleanup

* Move SERIAL_PRINT_PORT definition to variant.h

* Add missed c6 check

* Update src/modules/SerialModule.cpp

Compile error for invalid SERIAL_PRINT_OBJECT value

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 14:08:32 -06:00
Jonathan Bennett
bc702b18d8 Merge branch 'develop' into agc-reset 2025-12-17 19:54:07 -06:00
Jonathan Bennett
5e2d8eac6a Merge branch 'develop' into agc-reset 2025-10-14 09:04:28 -05:00
Jonathan Bennett
971543fab3 Add agc reset attempt 2025-09-29 12:11:48 -05:00
23 changed files with 383 additions and 338 deletions

View File

@@ -1,8 +1,59 @@
#include "InputBroker.h" #include "InputBroker.h"
#include "PowerFSM.h" // needed for event trigger #include "PowerFSM.h" // needed for event trigger
#include "configuration.h" #include "configuration.h"
#include "graphics/Screen.h"
#include "modules/ExternalNotificationModule.h" #include "modules/ExternalNotificationModule.h"
#if ARCH_PORTDUINO
#include "input/LinuxInputImpl.h"
#include "input/SeesawRotary.h"
#include "platform/portduino/PortduinoGlue.h"
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "input/ExpressLRSFiveWay.h"
#include "input/RotaryEncoderImpl.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/SerialKeyboardImpl.h"
#include "input/UpDownInterruptImpl1.h"
#include "input/i2cButton.h"
#if HAS_TRACKBALL
#include "input/TrackballInterruptImpl1.h"
#endif
#include "modules/StatusLEDModule.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "input/cardKbI2cImpl.h"
#endif
#include "input/kbMatrixImpl.h"
#endif
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
#include "input/ButtonThread.h"
#if defined(BUTTON_PIN_TOUCH)
ButtonThread *TouchButtonThread = nullptr;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
static bool touchBacklightWasOn = false;
static bool touchBacklightActive = false;
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
ButtonThread *UserButtonThread = nullptr;
#endif
#if defined(ALT_BUTTON_PIN)
ButtonThread *BackButtonThread = nullptr;
#endif
#if defined(CANCEL_BUTTON_PIN)
ButtonThread *CancelButtonThread = nullptr;
#endif
#endif
InputBroker *inputBroker = nullptr; InputBroker *inputBroker = nullptr;
InputBroker::InputBroker() InputBroker::InputBroker()
@@ -74,3 +125,262 @@ void InputBroker::pollSoonWorker(void *p)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
#endif #endif
void InputBroker::Init()
{
#ifdef BUTTON_PIN
#ifdef ARCH_ESP32
#if ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef BUTTON_NEED_PULLUP
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#endif
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
delay(10);
#endif
#ifdef BUTTON_NEED_PULLUP2
gpio_pullup_en((gpio_num_t)BUTTON_NEED_PULLUP2);
delay(10);
#endif
#endif
#endif
#endif
// buttons are now inputBroker, so have to come after setupModules
#if HAS_BUTTON
int pullup_sense = 0;
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
#ifdef BUTTON_SENSE_TYPE
pullup_sense = BUTTON_SENSE_TYPE;
#else
pullup_sense = INPUT_PULLUP_SENSE;
#endif
#endif
#if defined(ARCH_PORTDUINO)
if (portduino_config.userButtonPin.enabled) {
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig config;
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
config.activeLow = true;
config.activePullup = true;
config.pullupSense = INPUT_PULLUP;
config.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
config.singlePress = INPUT_BROKER_USER_PRESS;
config.longPress = INPUT_BROKER_SELECT;
UserButtonThread->initButton(config);
}
}
#endif
#ifdef BUTTON_PIN_TOUCH
TouchButtonThread = new ButtonThread("BackButton");
ButtonConfig touchConfig;
touchConfig.pinNumber = BUTTON_PIN_TOUCH;
touchConfig.activeLow = true;
touchConfig.activePullup = true;
touchConfig.pullupSense = pullup_sense;
touchConfig.intRoutine = []() {
TouchButtonThread->userButton.tick();
TouchButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_BACK;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
touchConfig.longPress = INPUT_BROKER_NONE;
touchConfig.suppressLeadUpSound = true;
touchConfig.onPress = []() {
touchBacklightWasOn = uiconfig.screen_brightness == 1;
if (!touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, HIGH);
}
touchBacklightActive = true;
};
touchConfig.onRelease = []() {
if (touchBacklightActive && !touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, LOW);
}
touchBacklightActive = false;
};
#endif
TouchButtonThread->initButton(touchConfig);
#endif
#if defined(CANCEL_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
CancelButtonThread = new ButtonThread("CancelButton");
ButtonConfig cancelConfig;
cancelConfig.pinNumber = CANCEL_BUTTON_PIN;
cancelConfig.activeLow = CANCEL_BUTTON_ACTIVE_LOW;
cancelConfig.activePullup = CANCEL_BUTTON_ACTIVE_PULLUP;
cancelConfig.pullupSense = pullup_sense;
cancelConfig.intRoutine = []() {
CancelButtonThread->userButton.tick();
CancelButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
cancelConfig.singlePress = INPUT_BROKER_CANCEL;
cancelConfig.longPress = INPUT_BROKER_SHUTDOWN;
cancelConfig.longPressTime = 4000;
CancelButtonThread->initButton(cancelConfig);
#endif
#if defined(ALT_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
BackButtonThread = new ButtonThread("BackButton");
ButtonConfig backConfig;
backConfig.pinNumber = ALT_BUTTON_PIN;
backConfig.activeLow = ALT_BUTTON_ACTIVE_LOW;
backConfig.activePullup = ALT_BUTTON_ACTIVE_PULLUP;
backConfig.pullupSense = pullup_sense;
backConfig.intRoutine = []() {
BackButtonThread->userButton.tick();
BackButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
backConfig.singlePress = INPUT_BROKER_ALT_PRESS;
backConfig.longPress = INPUT_BROKER_ALT_LONG;
backConfig.longPressTime = 500;
BackButtonThread->initButton(backConfig);
#endif
#if defined(BUTTON_PIN)
#if defined(USERPREFS_BUTTON_PIN)
int _pinNum = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN;
#else
int _pinNum = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN;
#endif
#ifndef BUTTON_ACTIVE_LOW
#define BUTTON_ACTIVE_LOW true
#endif
#ifndef BUTTON_ACTIVE_PULLUP
#define BUTTON_ACTIVE_PULLUP true
#endif
// Buttons. Moved here cause we need NodeDB to be initialized
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig userConfig;
userConfig.pinNumber = (uint8_t)_pinNum;
userConfig.activeLow = BUTTON_ACTIVE_LOW;
userConfig.activePullup = BUTTON_ACTIVE_PULLUP;
userConfig.pullupSense = pullup_sense;
userConfig.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
userConfig.singlePress = INPUT_BROKER_USER_PRESS;
userConfig.longPress = INPUT_BROKER_SELECT;
userConfig.longPressTime = 500;
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
UserButtonThread->initButton(userConfig);
} else {
ButtonConfig userConfigNoScreen;
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
userConfigNoScreen.activePullup = BUTTON_ACTIVE_PULLUP;
userConfigNoScreen.pullupSense = pullup_sense;
userConfigNoScreen.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
userConfigNoScreen.longPress = INPUT_BROKER_NONE;
userConfigNoScreen.longPressTime = 500;
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
UserButtonThread->initButton(userConfigNoScreen);
}
#endif
#endif
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
#if defined(T_LORA_PAGER)
// use a special FSM based rotary encoder version for T-LoRa Pager
rotaryEncoderImpl = new RotaryEncoderImpl();
if (!rotaryEncoderImpl->init()) {
delete rotaryEncoderImpl;
rotaryEncoderImpl = nullptr;
}
#elif defined(INPUTDRIVER_ENCODER_TYPE) && (INPUTDRIVER_ENCODER_TYPE == 2)
upDownInterruptImpl1 = new UpDownInterruptImpl1();
if (!upDownInterruptImpl1->init()) {
delete upDownInterruptImpl1;
upDownInterruptImpl1 = nullptr;
}
#else
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
rotaryEncoderInterruptImpl1 = nullptr;
}
#endif
cardKbI2cImpl = new CardKbI2cImpl();
cardKbI2cImpl->init();
#if defined(M5STACK_UNITC6L)
i2cButton = new i2cButtonThread("i2cButtonThread");
#endif
#ifdef INPUTBROKER_MATRIX_TYPE
kbMatrixImpl = new KbMatrixImpl();
kbMatrixImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
#ifdef INPUTBROKER_SERIAL_TYPE
aSerialKeyboardImpl = new SerialKeyboardImpl();
aSerialKeyboardImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
}
#endif // HAS_BUTTON
#if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
}
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
}
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
trackballInterruptImpl1 = new TrackballInterruptImpl1();
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
}
#endif
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
expressLRSFiveWayInput = new ExpressLRSFiveWay();
#endif
}

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Observer.h" #include "Observer.h"
#include "concurrency/OSThread.h"
#include "freertosinc.h" #include "freertosinc.h"
#ifdef InputBrokerDebug #ifdef InputBrokerDebug
@@ -76,6 +77,7 @@ class InputBroker : public Observable<const InputEvent *>
void queueInputEvent(const InputEvent *event); void queueInputEvent(const InputEvent *event);
void processInputEventQueue(); void processInputEventQueue();
#endif #endif
void Init();
protected: protected:
int handleInputEvent(const InputEvent *event); int handleInputEvent(const InputEvent *event);
@@ -89,4 +91,5 @@ class InputBroker : public Observable<const InputEvent *>
#endif #endif
}; };
extern InputBroker *inputBroker; extern InputBroker *inputBroker;
extern bool runASAP;

View File

@@ -120,31 +120,6 @@ void printPartitionTable()
#endif // DEBUG_PARTITION_TABLE #endif // DEBUG_PARTITION_TABLE
#endif // ARCH_ESP32 #endif // ARCH_ESP32
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
#include "input/ButtonThread.h"
#if defined(BUTTON_PIN_TOUCH)
ButtonThread *TouchButtonThread = nullptr;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
static bool touchBacklightWasOn = false;
static bool touchBacklightActive = false;
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
ButtonThread *UserButtonThread = nullptr;
#endif
#if defined(ALT_BUTTON_PIN)
ButtonThread *BackButtonThread = nullptr;
#endif
#if defined(CANCEL_BUTTON_PIN)
ButtonThread *CancelButtonThread = nullptr;
#endif
#endif
#include "AmbientLightingThread.h" #include "AmbientLightingThread.h"
#include "PowerFSMThread.h" #include "PowerFSMThread.h"
@@ -218,6 +193,8 @@ bool kb_found = false;
// global bool to record that on-screen keyboard (OSK) is present // global bool to record that on-screen keyboard (OSK) is present
bool osk_found = false; bool osk_found = false;
unsigned long last_listen = 0;
// The I2C address of the RTC Module (if found) // The I2C address of the RTC Module (if found)
ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE; ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the Accelerometer (if found) // The I2C address of the Accelerometer (if found)
@@ -509,30 +486,6 @@ void setup()
LOG_INFO("Wait for peripherals to stabilize"); LOG_INFO("Wait for peripherals to stabilize");
delay(PERIPHERAL_WARMUP_MS); delay(PERIPHERAL_WARMUP_MS);
#endif #endif
#ifdef BUTTON_PIN
#ifdef ARCH_ESP32
#if ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef BUTTON_NEED_PULLUP
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#endif
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
delay(10);
#endif
#ifdef BUTTON_NEED_PULLUP2
gpio_pullup_en((gpio_num_t)BUTTON_NEED_PULLUP2);
delay(10);
#endif
#endif
#endif
#endif
initSPI(); initSPI();
OSThread::setup(); OSThread::setup();
@@ -999,180 +952,9 @@ void setup()
nodeDB->hasWarned = true; nodeDB->hasWarned = true;
} }
#endif #endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
// buttons are now inputBroker, so have to come after setupModules if (inputBroker)
#if HAS_BUTTON inputBroker->Init();
int pullup_sense = 0;
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
#ifdef BUTTON_SENSE_TYPE
pullup_sense = BUTTON_SENSE_TYPE;
#else
pullup_sense = INPUT_PULLUP_SENSE;
#endif
#endif
#if defined(ARCH_PORTDUINO)
if (portduino_config.userButtonPin.enabled) {
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig config;
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
config.activeLow = true;
config.activePullup = true;
config.pullupSense = INPUT_PULLUP;
config.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
config.singlePress = INPUT_BROKER_USER_PRESS;
config.longPress = INPUT_BROKER_SELECT;
UserButtonThread->initButton(config);
}
}
#endif
#ifdef BUTTON_PIN_TOUCH
TouchButtonThread = new ButtonThread("BackButton");
ButtonConfig touchConfig;
touchConfig.pinNumber = BUTTON_PIN_TOUCH;
touchConfig.activeLow = true;
touchConfig.activePullup = true;
touchConfig.pullupSense = pullup_sense;
touchConfig.intRoutine = []() {
TouchButtonThread->userButton.tick();
TouchButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_BACK;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
touchConfig.longPress = INPUT_BROKER_NONE;
touchConfig.suppressLeadUpSound = true;
touchConfig.onPress = []() {
touchBacklightWasOn = uiconfig.screen_brightness == 1;
if (!touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, HIGH);
}
touchBacklightActive = true;
};
touchConfig.onRelease = []() {
if (touchBacklightActive && !touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, LOW);
}
touchBacklightActive = false;
};
#endif
TouchButtonThread->initButton(touchConfig);
#endif
#if defined(CANCEL_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
CancelButtonThread = new ButtonThread("CancelButton");
ButtonConfig cancelConfig;
cancelConfig.pinNumber = CANCEL_BUTTON_PIN;
cancelConfig.activeLow = CANCEL_BUTTON_ACTIVE_LOW;
cancelConfig.activePullup = CANCEL_BUTTON_ACTIVE_PULLUP;
cancelConfig.pullupSense = pullup_sense;
cancelConfig.intRoutine = []() {
CancelButtonThread->userButton.tick();
CancelButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
cancelConfig.singlePress = INPUT_BROKER_CANCEL;
cancelConfig.longPress = INPUT_BROKER_SHUTDOWN;
cancelConfig.longPressTime = 4000;
CancelButtonThread->initButton(cancelConfig);
#endif
#if defined(ALT_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
BackButtonThread = new ButtonThread("BackButton");
ButtonConfig backConfig;
backConfig.pinNumber = ALT_BUTTON_PIN;
backConfig.activeLow = ALT_BUTTON_ACTIVE_LOW;
backConfig.activePullup = ALT_BUTTON_ACTIVE_PULLUP;
backConfig.pullupSense = pullup_sense;
backConfig.intRoutine = []() {
BackButtonThread->userButton.tick();
BackButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
backConfig.singlePress = INPUT_BROKER_ALT_PRESS;
backConfig.longPress = INPUT_BROKER_ALT_LONG;
backConfig.longPressTime = 500;
BackButtonThread->initButton(backConfig);
#endif
#if defined(BUTTON_PIN)
#if defined(USERPREFS_BUTTON_PIN)
int _pinNum = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN;
#else
int _pinNum = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN;
#endif
#ifndef BUTTON_ACTIVE_LOW
#define BUTTON_ACTIVE_LOW true
#endif
#ifndef BUTTON_ACTIVE_PULLUP
#define BUTTON_ACTIVE_PULLUP true
#endif
// Buttons. Moved here cause we need NodeDB to be initialized
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig userConfig;
userConfig.pinNumber = (uint8_t)_pinNum;
userConfig.activeLow = BUTTON_ACTIVE_LOW;
userConfig.activePullup = BUTTON_ACTIVE_PULLUP;
userConfig.pullupSense = pullup_sense;
userConfig.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
userConfig.singlePress = INPUT_BROKER_USER_PRESS;
userConfig.longPress = INPUT_BROKER_SELECT;
userConfig.longPressTime = 500;
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
UserButtonThread->initButton(userConfig);
} else {
ButtonConfig userConfigNoScreen;
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
userConfigNoScreen.activePullup = BUTTON_ACTIVE_PULLUP;
userConfigNoScreen.pullupSense = pullup_sense;
userConfigNoScreen.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
userConfigNoScreen.longPress = INPUT_BROKER_NONE;
userConfigNoScreen.longPressTime = 500;
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
UserButtonThread->initButton(userConfigNoScreen);
}
#endif
#endif #endif
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS #ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
@@ -1388,6 +1170,13 @@ void loop()
#endif #endif
power->powerCommandsCheck(); power->powerCommandsCheck();
if (last_listen + 1000 * 60 < millis() &&
!(RadioLibInterface::instance->isSending() || RadioLibInterface::instance->isActivelyReceiving())) {
RadioLibInterface::instance->startReceive();
LOG_DEBUG("attempting AGC reset");
last_listen = millis();
}
#ifdef DEBUG_STACK #ifdef DEBUG_STACK
static uint32_t lastPrint = 0; static uint32_t lastPrint = 0;
if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) { if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) {

View File

@@ -17,12 +17,6 @@
ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
{ {
if (p->want_ack) { if (p->want_ack) {
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
// counts and we want this message to get through the whole mesh, so use the default.
if (p->hop_limit == 0) {
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
}
DEBUG_HEAP_BEFORE; DEBUG_HEAP_BEFORE;
auto copy = packetPool.allocCopy(*p); auto copy = packetPool.allocCopy(*p);
DEBUG_HEAP_AFTER("ReliableRouter::send", copy); DEBUG_HEAP_AFTER("ReliableRouter::send", copy);

View File

@@ -266,6 +266,13 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
} }
} }
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
// counts and we want this message to get through the whole mesh, so use the default.
if (src == RX_SRC_USER && p->want_ack && p->hop_limit == 0) {
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
}
return send(p); return send(p);
} }
} }

View File

@@ -1,24 +1,7 @@
#include "configuration.h" #include "configuration.h"
#if !MESHTASTIC_EXCLUDE_INPUTBROKER #if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "buzz/BuzzerFeedbackThread.h" #include "buzz/BuzzerFeedbackThread.h"
#include "input/ExpressLRSFiveWay.h"
#include "input/InputBroker.h"
#include "input/RotaryEncoderImpl.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/SerialKeyboardImpl.h"
#include "input/UpDownInterruptImpl1.h"
#include "input/i2cButton.h"
#include "modules/SystemCommandsModule.h" #include "modules/SystemCommandsModule.h"
#if HAS_TRACKBALL
#include "input/TrackballInterruptImpl1.h"
#endif
#include "modules/StatusLEDModule.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "input/cardKbI2cImpl.h"
#endif
#include "input/kbMatrixImpl.h"
#endif #endif
#if !MESHTASTIC_EXCLUDE_PKI #if !MESHTASTIC_EXCLUDE_PKI
#include "KeyVerificationModule.h" #include "KeyVerificationModule.h"
@@ -59,8 +42,6 @@
#include "modules/WaypointModule.h" #include "modules/WaypointModule.h"
#endif #endif
#if ARCH_PORTDUINO #if ARCH_PORTDUINO
#include "input/LinuxInputImpl.h"
#include "input/SeesawRotary.h"
#include "modules/Telemetry/HostMetrics.h" #include "modules/Telemetry/HostMetrics.h"
#if !MESHTASTIC_EXCLUDE_STOREFORWARD #if !MESHTASTIC_EXCLUDE_STOREFORWARD
#include "modules/StoreForwardModule.h" #include "modules/StoreForwardModule.h"
@@ -179,63 +160,6 @@ void setupModules()
#endif #endif
// Example: Put your module here // Example: Put your module here
// new ReplyModule(); // new ReplyModule();
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
#if defined(T_LORA_PAGER)
// use a special FSM based rotary encoder version for T-LoRa Pager
rotaryEncoderImpl = new RotaryEncoderImpl();
if (!rotaryEncoderImpl->init()) {
delete rotaryEncoderImpl;
rotaryEncoderImpl = nullptr;
}
#elif defined(INPUTDRIVER_ENCODER_TYPE) && (INPUTDRIVER_ENCODER_TYPE == 2)
upDownInterruptImpl1 = new UpDownInterruptImpl1();
if (!upDownInterruptImpl1->init()) {
delete upDownInterruptImpl1;
upDownInterruptImpl1 = nullptr;
}
#else
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
rotaryEncoderInterruptImpl1 = nullptr;
}
#endif
cardKbI2cImpl = new CardKbI2cImpl();
cardKbI2cImpl->init();
#if defined(M5STACK_UNITC6L)
i2cButton = new i2cButtonThread("i2cButtonThread");
#endif
#ifdef INPUTBROKER_MATRIX_TYPE
kbMatrixImpl = new KbMatrixImpl();
kbMatrixImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
#ifdef INPUTBROKER_SERIAL_TYPE
aSerialKeyboardImpl = new SerialKeyboardImpl();
aSerialKeyboardImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
}
#endif // HAS_BUTTON
#if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
}
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
}
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
trackballInterruptImpl1 = new TrackballInterruptImpl1();
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
}
#endif
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
expressLRSFiveWayInput = new ExpressLRSFiveWay();
#endif
#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES #if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
cannedMessageModule = new CannedMessageModule(); cannedMessageModule = new CannedMessageModule();

View File

@@ -67,6 +67,8 @@ uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
#if !(EVENTMODE) // This falls through to the default. #if !(EVENTMODE) // This falls through to the default.
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
#endif #endif
} else if (mp.hop_start == 0) {
return 0; // The requesting node wanted 0 hops, so the response also uses a direct/local path.
} else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) { } else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) {
return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different
} }

View File

@@ -63,29 +63,26 @@
SerialModule *serialModule; SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio; SerialModuleRadio *serialModuleRadio;
#if defined(TTGO_T_ECHO) || defined(TTGO_T_ECHO_PLUS) || defined(CANARYONE) || defined(MESHLINK) || \ #ifndef SERIAL_PRINT_PORT
defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M4) || defined(ELECROW_ThinkNode_M5) || \ #define SERIAL_PRINT_PORT 2
defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3) || defined(MUZI_BASE)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &Serial;
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL)
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &Serial1;
#else
SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &Serial2;
#endif #endif
#if SERIAL_PRINT_PORT == 0
#define SERIAL_PRINT_OBJECT Serial
#elif SERIAL_PRINT_PORT == 1
#define SERIAL_PRINT_OBJECT Serial1
#elif SERIAL_PRINT_PORT == 2
#define SERIAL_PRINT_OBJECT Serial2
#else
#error "Unsupported SERIAL_PRINT_PORT value. Allowed values are 0, 1, or 2."
#endif
SerialModule::SerialModule() : StreamAPI(&SERIAL_PRINT_OBJECT), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &SERIAL_PRINT_OBJECT;
char serialBytes[512]; char serialBytes[512];
size_t serialPayloadSize; size_t serialPayloadSize;
@@ -205,9 +202,7 @@ int32_t SerialModule::runOnce()
Serial.begin(baud); Serial.begin(baud);
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT); Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
} }
#elif !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \ #elif SERIAL_PRINT_PORT != 0
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M4) && \
!defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) { if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
#ifdef ARCH_RP2040 #ifdef ARCH_RP2040
@@ -264,9 +259,7 @@ int32_t SerialModule::runOnce()
} }
} }
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \ #if SERIAL_PRINT_PORT != 0
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M4) && \
!defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) { else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
processWXSerial(); processWXSerial();
@@ -540,11 +533,7 @@ ParsedLine parseLine(const char *line)
*/ */
void SerialModule::processWXSerial() void SerialModule::processWXSerial()
{ {
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \ #if SERIAL_PRINT_PORT != 0 && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6)
!defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && \
!defined(ELECROW_ThinkNode_M3) && \
!defined(ELECROW_ThinkNode_M4) && \
!defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL) && !defined(MUZI_BASE)
static unsigned int lastAveraged = 0; static unsigned int lastAveraged = 0;
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded. static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.

View File

@@ -50,3 +50,5 @@ void c6l_init();
#endif #endif
#define SCREEN_TRANSITION_FRAMERATE 10 #define SCREEN_TRANSITION_FRAMERATE 10
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness #define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
#define SERIAL_PRINT_PORT 1

View File

@@ -19,3 +19,5 @@
#define SX126X_TXEN 14 #define SX126X_TXEN 14
#define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8 #define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define SERIAL_PRINT_PORT 1

View File

@@ -81,4 +81,6 @@
#define BUTTON_PIN PIN_BUTTON1 #define BUTTON_PIN PIN_BUTTON1
#define BUTTON_PIN_ALT PIN_BUTTON2 #define BUTTON_PIN_ALT PIN_BUTTON2
#define SERIAL_PRINT_PORT 0
#endif #endif

View File

@@ -159,6 +159,8 @@ External serial flash WP25R1635FZUIL0
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX GPS_TX_PIN
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX GPS_RX_PIN
#define SERIAL_PRINT_PORT 0
/* /*
* SPI Interfaces * SPI Interfaces
*/ */

View File

@@ -113,6 +113,8 @@ extern "C" {
#define LR11X0_DIO3_TCXO_VOLTAGE 3.3 #define LR11X0_DIO3_TCXO_VOLTAGE 3.3
#define LR11X0_DIO_AS_RF_SWITCH #define LR11X0_DIO_AS_RF_SWITCH
#define SERIAL_PRINT_PORT 0
// PCF8563 RTC Module // PCF8563 RTC Module
// REVISIT https://github.com/meshtastic/firmware/pull/9084 // REVISIT https://github.com/meshtastic/firmware/pull/9084
// #define PCF8563_RTC 0x51 // #define PCF8563_RTC 0x51

View File

@@ -135,6 +135,8 @@ static const uint8_t A0 = PIN_A0;
#define PIN_SERIAL1_RX GPS_RX_PIN #define PIN_SERIAL1_RX GPS_RX_PIN
#define PIN_SERIAL1_TX GPS_TX_PIN #define PIN_SERIAL1_TX GPS_TX_PIN
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -170,6 +170,8 @@ static const uint8_t A0 = PIN_A0;
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 #define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (2.0F) #define ADC_MULTIPLIER (2.0F)
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -142,6 +142,8 @@ No longer populated on PCB
#define BQ4050_SCL_PIN (32 + 0) // I2C clock line pin #define BQ4050_SCL_PIN (32 + 0) // I2C clock line pin
#define BQ4050_EMERGENCY_SHUTDOWN_PIN (32 + 3) // Emergency shutdown pin #define BQ4050_EMERGENCY_SHUTDOWN_PIN (32 + 3) // Emergency shutdown pin
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -54,6 +54,7 @@ extern "C" {
*/ */
#define PIN_SERIAL1_RX (32 + 8) #define PIN_SERIAL1_RX (32 + 8)
#define PIN_SERIAL1_TX (7) #define PIN_SERIAL1_TX (7)
#define SERIAL_PRINT_PORT 0
/* /*
* SPI Interfaces * SPI Interfaces

View File

@@ -176,6 +176,8 @@ extern "C" {
#define EXTERNAL_FLASH_DEVICES W25Q32JVSS #define EXTERNAL_FLASH_DEVICES W25Q32JVSS
#define EXTERNAL_FLASH_USE_QSPI #define EXTERNAL_FLASH_USE_QSPI
#define SERIAL_PRINT_PORT 0
// NFC is disabled via CONFIG_NFCT_PINS_AS_GPIOS=1 build flag // NFC is disabled via CONFIG_NFCT_PINS_AS_GPIOS=1 build flag
// This configures P0.09 and P0.10 as regular GPIO pins instead of NFC pins // This configures P0.09 and P0.10 as regular GPIO pins instead of NFC pins

View File

@@ -171,6 +171,8 @@ static const uint8_t A0 = PIN_A0;
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 #define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (2.0F) #define ADC_MULTIPLIER (2.0F)
#define SERIAL_PRINT_PORT 0
// #define NO_EXT_GPIO 1 // #define NO_EXT_GPIO 1
// PINs back side // PINs back side
// Batt & solar connector left up corner // Batt & solar connector left up corner

View File

@@ -138,6 +138,8 @@ static const uint8_t A0 = PIN_A0;
// Battery / ADC already defined above // Battery / ADC already defined above
#define HAS_RTC 1 #define HAS_RTC 1
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -88,6 +88,7 @@ static const uint8_t A0 = PIN_A0;
/* /*
* Serial interfaces * Serial interfaces
*/ */
#define SERIAL_PRINT_PORT 0
/* /*
No longer populated on PCB No longer populated on PCB

View File

@@ -19,5 +19,7 @@ Do not expect a working Meshtastic device with this target.
// #define LED_PIN PB3 // LED2 // #define LED_PIN PB3 // LED2
#define LED_STATE_ON 1 #define LED_STATE_ON 1
#define SERIAL_PRINT_PORT 1
#define EBYTE_E77_MBL #define EBYTE_E77_MBL
#endif #endif

View File

@@ -17,5 +17,6 @@ Do not expect a working Meshtastic device with this target.
#define LED_STATE_ON 1 #define LED_STATE_ON 1
#define RAK3172 #define RAK3172
#define SERIAL_PRINT_PORT 1
#endif #endif