Merge branch 'master' into nomad-gemini

This commit is contained in:
Thomas Göttgens
2025-07-13 18:18:32 +02:00
committed by GitHub
212 changed files with 10365 additions and 4609 deletions
+2 -7
View File
@@ -630,6 +630,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
#if USERPREFS_EVENT_MODE
// If we're in event mode, nobody is a Router or Repeater
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE ||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
}
@@ -1198,7 +1199,7 @@ void AdminModule::reboot(int32_t seconds)
{
LOG_INFO("Reboot in %d seconds", seconds);
if (screen)
screen->showOverlayBanner("Rebooting...", 0); // stays on screen
screen->showSimpleBanner("Rebooting...", 0); // stays on screen
rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000);
}
@@ -1334,12 +1335,6 @@ void AdminModule::handleSendInputEvent(const meshtastic_AdminMessage_InputEvent
LOG_DEBUG("Processing input event: event_code=%u, kb_char=%u, touch_x=%u, touch_y=%u", inputEvent.event_code,
inputEvent.kb_char, inputEvent.touch_x, inputEvent.touch_y);
// Validate input parameters
if (inputEvent.event_code > INPUT_BROKER_ANYKEY) {
LOG_WARN("Invalid input event code: %u", inputEvent.event_code);
return;
}
// Create InputEvent for injection
InputEvent event = {.inputEvent = (input_broker_event)inputEvent.event_code,
.kbchar = (unsigned char)inputEvent.kb_char,
+30 -14
View File
@@ -154,7 +154,7 @@ int CannedMessageModule::splitConfiguredMessages()
}
void CannedMessageModule::drawHeader(OLEDDisplay *display, int16_t x, int16_t y, char *buffer)
{
if (display->getWidth() > 128) {
if (graphics::isHighResolution) {
if (this->dest == NODENUM_BROADCAST) {
display->drawStringf(x, y, buffer, "To: Broadcast@%s", channels.getName(this->channel));
} else {
@@ -245,12 +245,15 @@ void CannedMessageModule::updateDestinationSelectionList()
}
}
/* As the nodeDB is sorted, can skip this step
// Sort by favorite, then last heard
std::sort(this->filteredNodes.begin(), this->filteredNodes.end(), [](const NodeEntry &a, const NodeEntry &b) {
if (a.node->is_favorite != b.node->is_favorite)
return a.node->is_favorite > b.node->is_favorite;
return a.lastHeard < b.lastHeard;
});
*/
scrollIndex = 0; // Show first result at the top
destIndex = 0; // Highlight the first entry
if (nodesChanged && runState == CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION) {
@@ -387,6 +390,7 @@ bool CannedMessageModule::handleTabSwitch(const InputEvent *event)
// RESTORE THIS!
if (runState == CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION)
updateDestinationSelectionList();
requestFocus();
UIFrameEvent e;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
@@ -438,25 +442,34 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event
return 1;
}
// UP
if (isUp && destIndex > 0) {
destIndex--;
if (isUp) {
if (destIndex > 0) {
destIndex--;
} else if (totalEntries > 0) {
destIndex = totalEntries - 1;
}
if ((destIndex / columns) < scrollIndex)
scrollIndex = destIndex / columns;
else if ((destIndex / columns) >= (scrollIndex + visibleRows))
scrollIndex = (destIndex / columns) - visibleRows + 1;
screen->forceDisplay();
screen->forceDisplay(true);
return 1;
}
// DOWN
if (isDown && destIndex + 1 < totalEntries) {
destIndex++;
if (isDown) {
if (destIndex + 1 < totalEntries) {
destIndex++;
} else if (totalEntries > 0) {
destIndex = 0;
scrollIndex = 0;
}
if ((destIndex / columns) >= (scrollIndex + visibleRows))
scrollIndex = (destIndex / columns) - visibleRows + 1;
screen->forceDisplay();
screen->forceDisplay(true);
return 1;
}
@@ -478,7 +491,7 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event
runState = returnToCannedList ? CANNED_MESSAGE_RUN_STATE_ACTIVE : CANNED_MESSAGE_RUN_STATE_FREETEXT;
returnToCannedList = false;
screen->forceDisplay();
screen->forceDisplay(true);
return 1;
}
@@ -491,7 +504,7 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event
// UIFrameEvent e;
// e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
// notifyObservers(&e);
screen->forceDisplay();
screen->forceDisplay(true);
return 1;
}
@@ -703,7 +716,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
}
// Backspace
if (event->inputEvent == INPUT_BROKER_BACK) {
if (event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() > 0) {
payload = 0x08;
lastTouchMillis = millis();
runOnce();
@@ -726,7 +739,8 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
}
// Cancel (dismiss freetext screen)
if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG) {
if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG ||
(event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() == 0)) {
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
freetext = "";
cursor = 0;
@@ -976,6 +990,7 @@ int32_t CannedMessageModule::runOnce()
}
this->cursor--;
}
} else {
}
break;
case INPUT_BROKER_MSG_TAB: // Tab key: handled by input handler
@@ -986,6 +1001,7 @@ int32_t CannedMessageModule::runOnce()
default:
// Only insert ASCII printable characters (32–126)
if (this->payload >= 32 && this->payload <= 126) {
requestFocus();
if (this->cursor == this->freetext.length()) {
this->freetext += (char)this->payload;
} else {
@@ -2061,4 +2077,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
#endif
#endif
+2 -3
View File
@@ -362,9 +362,8 @@ ExternalNotificationModule::ExternalNotificationModule()
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
strncpy(rtttlConfig.ringtone,
"24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
sizeof(rtttlConfig.ringtone));
// The default ringtone is always loaded from userPrefs.jsonc
strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE_RTTTL, sizeof(rtttlConfig.ringtone));
}
LOG_INFO("Init External Notification Module");
+30 -27
View File
@@ -2,7 +2,9 @@
#include "KeyVerificationModule.h"
#include "MeshService.h"
#include "RTC.h"
#include "graphics/draw/MenuHandler.h"
#include "main.h"
#include "meshUtils.h"
#include "modules/AdminModule.h"
#include <SHA256.h>
@@ -48,18 +50,22 @@ AdminMessageHandleResult KeyVerificationModule::handleAdminMessageForModule(cons
bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_KeyVerification *r)
{
updateState();
if (mp.pki_encrypted == false)
if (mp.pki_encrypted == false) {
return false;
if (mp.from != currentRemoteNode) // because the inital connection request is handled in allocReply()
}
if (mp.from != currentRemoteNode) { // because the inital connection request is handled in allocReply()
return false;
}
if (currentState == KEY_VERIFICATION_IDLE) {
return false; // if we're idle, the only acceptable message is an init, which should be handled by allocReply()
}
} else if (currentState == KEY_VERIFICATION_SENDER_HAS_INITIATED && r->nonce == currentNonce && r->hash2.size == 32 &&
r->hash1.size == 0) {
if (currentState == KEY_VERIFICATION_SENDER_HAS_INITIATED && r->nonce == currentNonce && r->hash2.size == 32 &&
r->hash1.size == 0) {
memcpy(hash2, r->hash2.bytes, 32);
if (screen)
screen->showOverlayBanner("Enter Security Number", 30000);
IF_SCREEN(screen->showNumberPicker("Enter Security Number", 60000, 6, [](int number_picked) -> void {
keyVerificationModule->processSecurityNumber(number_picked);
});)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
@@ -79,16 +85,20 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
memset(message, 0, sizeof(message));
sprintf(message, "Verification: \n");
generateVerificationCode(message + 15);
sprintf(message + 24, "\nACCEPT\nREJECT");
LOG_INFO("Hash1 matches!");
if (screen) {
screen->showOverlayBanner(message, 30000, 2, [=](int selected) {
if (selected == 0) {
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
}
});
}
static const char *optionsArray[] = {"Reject", "Accept"};
// Don't try to put the array definition in the macro. Does not work with curly braces.
IF_SCREEN(graphics::BannerOverlayOptions options; options.message = message; options.durationMs = 30000;
options.optionsArrayPtr = optionsArray; options.optionsCount = 2;
options.notificationType = graphics::notificationTypeEnum::selection_picker;
options.bannerCallback =
[=](int selected) {
if (selected == 1) {
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
}
};
screen->showOverlayBanner(options);)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
sprintf(cn->message, "Final confirmation for incoming manual key verification %s", message);
@@ -113,6 +123,7 @@ bool KeyVerificationModule::sendInitialRequest(NodeNum remoteNode)
// generate nonce
updateState();
if (currentState != KEY_VERIFICATION_IDLE) {
IF_SCREEN(graphics::menuHandler::menuQueue = graphics::menuHandler::throttle_message;)
return false;
}
currentNonce = random();
@@ -183,11 +194,8 @@ meshtastic_MeshPacket *KeyVerificationModule::allocReply()
responsePacket = allocDataProtobuf(response);
responsePacket->pki_encrypted = true;
if (screen) {
snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000);
screen->showOverlayBanner(message, 30000);
LOG_WARN("%s", message);
}
IF_SCREEN(snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000);
screen->showSimpleBanner(message, 30000); LOG_WARN("%s", message);)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
sprintf(cn->message, "Incoming Key Verification.\nSecurity Number\n%03u %03u", currentSecurityNumber / 1000,
@@ -251,12 +259,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
p->priority = meshtastic_MeshPacket_Priority_HIGH;
service->sendToMesh(p, RX_SRC_LOCAL, true);
currentState = KEY_VERIFICATION_SENDER_AWAITING_USER;
memset(message, 0, sizeof(message));
sprintf(message, "Verification: \n");
generateVerificationCode(message + 15); // send the toPhone packet
if (screen) {
screen->showOverlayBanner(message, 30000);
}
IF_SCREEN(screen->requestMenu(graphics::menuHandler::key_verification_final_prompt);)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
sprintf(cn->message, "Final confirmation for outgoing manual key verification %s", message);
@@ -275,7 +278,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
void KeyVerificationModule::updateState()
{
if (currentState != KEY_VERIFICATION_IDLE) {
// check for the 30 second timeout
// check for the 60 second timeout
if (currentNonceTimestamp < getTime() - 60) {
resetToIdle();
} else {
+4 -3
View File
@@ -27,6 +27,8 @@ class KeyVerificationModule : public ProtobufModule<meshtastic_KeyVerification>
}*/
virtual bool wantUIFrame() { return false; };
bool sendInitialRequest(NodeNum remoteNode);
void generateVerificationCode(char *); // fills char with the user readable verification code
uint32_t getCurrentRemoteNode() { return currentRemoteNode; }
protected:
/* Called to handle a particular incoming message
@@ -56,9 +58,8 @@ class KeyVerificationModule : public ProtobufModule<meshtastic_KeyVerification>
char message[40] = {0};
void processSecurityNumber(uint32_t);
void updateState(); // check the timeouts and maybe reset the state to idle
void resetToIdle(); // Zero out module state
void generateVerificationCode(char *); // fills char with the user readable verification code
void updateState(); // check the timeouts and maybe reset the state to idle
void resetToIdle(); // Zero out module state
};
extern KeyVerificationModule *keyVerificationModule;
+9 -1
View File
@@ -53,6 +53,7 @@
#endif
#if ARCH_PORTDUINO
#include "input/LinuxInputImpl.h"
#include "input/SeesawRotary.h"
#include "modules/Telemetry/HostMetrics.h"
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
#include "modules/StoreForwardModule.h"
@@ -163,7 +164,6 @@ void setupModules()
// Example: Put your module here
// new ReplyModule();
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
@@ -189,6 +189,11 @@ void setupModules()
#endif // HAS_BUTTON
#if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
}
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
}
@@ -213,11 +218,14 @@ void setupModules()
#if HAS_TELEMETRY
new DeviceTelemetryModule();
#endif
// TODO: How to improve this?
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
new EnvironmentTelemetryModule();
#if __has_include("Adafruit_PM25AQI.h")
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
new AirQualityTelemetryModule();
}
#endif
#if !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 ||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) {
+16 -12
View File
@@ -47,7 +47,7 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
bool isMuted = externalNotificationModule->getMute();
externalNotificationModule->setMute(!isMuted);
IF_SCREEN(graphics::isMuted = !isMuted; if (!isMuted) externalNotificationModule->stopNow();
screen->showOverlayBanner(isMuted ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);)
screen->showSimpleBanner(isMuted ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);)
}
return 0;
// Bluetooth
@@ -58,24 +58,24 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
#if defined(ARDUINO_ARCH_NRF52)
if (!config.bluetooth.enabled) {
disableBluetooth();
IF_SCREEN(screen->showOverlayBanner("Bluetooth OFF\nRebooting", 3000));
IF_SCREEN(screen->showSimpleBanner("Bluetooth OFF\nRebooting", 3000));
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 2000;
} else {
IF_SCREEN(screen->showOverlayBanner("Bluetooth ON\nRebooting", 3000));
IF_SCREEN(screen->showSimpleBanner("Bluetooth ON\nRebooting", 3000));
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000;
}
#else
if (!config.bluetooth.enabled) {
disableBluetooth();
IF_SCREEN(screen->showOverlayBanner("Bluetooth OFF", 3000));
IF_SCREEN(screen->showSimpleBanner("Bluetooth OFF", 3000));
} else {
IF_SCREEN(screen->showOverlayBanner("Bluetooth ON\nRebooting", 3000));
IF_SCREEN(screen->showSimpleBanner("Bluetooth ON\nRebooting", 3000));
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000;
}
#endif
return 0;
case INPUT_BROKER_MSG_REBOOT:
IF_SCREEN(screen->showOverlayBanner("Rebooting...", 0));
IF_SCREEN(screen->showSimpleBanner("Rebooting...", 0));
nodeDB->saveToDisk();
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000;
// runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
@@ -92,7 +92,7 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
gps->toggleGpsMode();
const char *msg =
(config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) ? "GPS Enabled" : "GPS Disabled";
IF_SCREEN(screen->forceDisplay(); screen->showOverlayBanner(msg, 3000);)
IF_SCREEN(screen->forceDisplay(); screen->showSimpleBanner(msg, 3000);)
}
#endif
return true;
@@ -100,19 +100,23 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
case INPUT_BROKER_SEND_PING:
service->refreshLocalMeshNode();
if (service->trySendPosition(NODENUM_BROADCAST, true)) {
IF_SCREEN(screen->showOverlayBanner("Position\nUpdate Sent", 3000));
IF_SCREEN(screen->showSimpleBanner("Position\nSent", 3000));
} else {
IF_SCREEN(screen->showOverlayBanner("Node Info\nUpdate Sent", 3000));
IF_SCREEN(screen->showSimpleBanner("Node Info\nSent", 3000));
}
return true;
// Power control
case INPUT_BROKER_SHUTDOWN:
LOG_ERROR("Shutting down");
IF_SCREEN(screen->showOverlayBanner("Shutting down..."));
LOG_ERROR("Shutting Down");
IF_SCREEN(screen->showSimpleBanner("Shutting Down..."));
nodeDB->saveToDisk();
shutdownAtMsec = millis() + DEFAULT_SHUTDOWN_SECONDS * 1000;
// runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
return true;
default:
// No other input events handled here
break;
}
return false;
}
}
@@ -30,7 +30,7 @@
namespace graphics
{
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr);
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only);
}
#if __has_include(<Adafruit_AHTX0.h>)
#include "Sensor/AHT10.h"
@@ -358,7 +358,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
int line = 1;
// === Set Title
const char *titleStr = (SCREEN_WIDTH > 128) ? "Environment" : "Env.";
const char *titleStr = (graphics::isHighResolution) ? "Environment" : "Env.";
// === Header ===
graphics::drawCommonHeader(display, x, y, titleStr);
@@ -450,7 +450,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
if (isOwnTelemetry && bannerMsg && isCooldownOver) {
LOG_INFO("drawFrame: IAQ %d (own) — showing banner: %s", m.iaq, bannerMsg);
screen->showOverlayBanner(bannerMsg, 3000);
screen->showSimpleBanner(bannerMsg, 3000);
// Only buzz if IAQ is over 200
if (m.iaq > 200 && moduleConfig.external_notification.enabled && !externalNotificationModule->getMute()) {
+2 -2
View File
@@ -24,7 +24,7 @@
namespace graphics
{
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr);
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only);
}
int32_t PowerTelemetryModule::runOnce()
@@ -115,7 +115,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s
int line = 1;
// === Set Title
const char *titleStr = (SCREEN_WIDTH > 128) ? "Power Telem." : "Power";
const char *titleStr = (graphics::isHighResolution) ? "Power Telem." : "Power";
// === Header ===
graphics::drawCommonHeader(display, x, y, titleStr);
@@ -1,6 +1,6 @@
#include "MAX17048Sensor.h"
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) && __has_include(<Adafruit_MAX1704X.h>)
#if !MESHTASTIC_EXCLUDE_I2C && __has_include(<Adafruit_MAX1704X.h>)
MAX17048Singleton *MAX17048Singleton::GetInstance()
{
@@ -5,7 +5,7 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) && __has_include(<Adafruit_MAX1704X.h>)
#if !MESHTASTIC_EXCLUDE_I2C && __has_include(<Adafruit_MAX1704X.h>)
// Samples to store in a buffer to determine if the battery is charging or discharging
#define MAX17048_CHARGING_SAMPLES 3
@@ -20,4 +20,15 @@ bool NullSensor::getMetrics(meshtastic_Telemetry *measurement)
{
return false;
}
uint16_t NullSensor::getBusVoltageMv()
{
return 0;
}
int16_t NullSensor::getCurrentMa()
{
return 0;
}
#endif
+8 -2
View File
@@ -4,9 +4,12 @@
#pragma once
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
class NullSensor : public TelemetrySensor
#include "CurrentSensor.h"
#include "TelemetrySensor.h"
#include "VoltageSensor.h"
class NullSensor : public TelemetrySensor, VoltageSensor, CurrentSensor
{
protected:
@@ -17,6 +20,9 @@ class NullSensor : public TelemetrySensor
virtual int32_t runOnce() override;
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
int32_t runTrigger() { return 0; }
virtual uint16_t getBusVoltageMv() override;
virtual int16_t getCurrentMa() override;
};
#endif
+5 -1
View File
@@ -4,6 +4,7 @@
#include "PowerFSM.h"
#include "buzz.h"
#include "configuration.h"
#include "graphics/Screen.h"
TextMessageModule *textMessageModule;
ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
@@ -17,7 +18,10 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
devicestate.rx_text_message = mp;
devicestate.has_rx_text_message = true;
powerFSM.trigger(EVENT_RECEIVED_MSG);
// Only trigger screen wake if configuration allows it
if (shouldWakeOnReceivedMessage()) {
powerFSM.trigger(EVENT_RECEIVED_MSG);
}
notifyObservers(&mp);
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
+9 -5
View File
@@ -137,10 +137,14 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) {
const meshtastic_PositionLite &op = ourNode->position;
float myHeading;
if (screen->hasHeading())
myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians
else
myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) {
myHeading = 0;
} else {
if (screen->hasHeading())
myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians
else
myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
}
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, (compassDiam / 2));
// Compass bearing to waypoint
@@ -148,7 +152,7 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i));
// If the top of the compass is a static north then bearingToOther can be drawn on the compass directly
// If the top of the compass is not a static north we need adjust bearingToOther based on heading
if (!config.display.compass_north_top)
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING)
bearingToOther -= myHeading;
graphics::CompassRenderer::drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther);