mirror of
https://github.com/meshtastic/firmware.git
synced 2026-02-03 15:42:02 +00:00
Compare commits
12 Commits
crowpanelV
...
baseui_sta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d57a49b51 | ||
|
|
d8a0b6a737 | ||
|
|
0703e0e6d7 | ||
|
|
f514bc230b | ||
|
|
697dd2b5b2 | ||
|
|
0b8b757fb0 | ||
|
|
62f897eab3 | ||
|
|
523906d031 | ||
|
|
0022148323 | ||
|
|
78f29c0f87 | ||
|
|
9d06c1bf34 | ||
|
|
1d30342c00 |
@@ -89,22 +89,14 @@ class BluetoothStatus : public Status
|
|||||||
case ConnectionState::CONNECTED:
|
case ConnectionState::CONNECTED:
|
||||||
LOG_DEBUG("BluetoothStatus CONNECTED");
|
LOG_DEBUG("BluetoothStatus CONNECTED");
|
||||||
#ifdef BLE_LED
|
#ifdef BLE_LED
|
||||||
#ifdef BLE_LED_INVERTED
|
digitalWrite(BLE_LED, LED_STATE_ON);
|
||||||
digitalWrite(BLE_LED, LOW);
|
|
||||||
#else
|
|
||||||
digitalWrite(BLE_LED, HIGH);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConnectionState::DISCONNECTED:
|
case ConnectionState::DISCONNECTED:
|
||||||
LOG_DEBUG("BluetoothStatus DISCONNECTED");
|
LOG_DEBUG("BluetoothStatus DISCONNECTED");
|
||||||
#ifdef BLE_LED
|
#ifdef BLE_LED
|
||||||
#ifdef BLE_LED_INVERTED
|
digitalWrite(BLE_LED, LED_STATE_OFF);
|
||||||
digitalWrite(BLE_LED, HIGH);
|
|
||||||
#else
|
|
||||||
digitalWrite(BLE_LED, LOW);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -459,6 +459,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
}
|
}
|
||||||
// if it's not HIGH - check the battery
|
// if it's not HIGH - check the battery
|
||||||
#endif
|
#endif
|
||||||
|
// If we have an EXT_PWR_DETECT pin and it indicates no external power, believe it.
|
||||||
|
return false;
|
||||||
|
|
||||||
// technically speaking this should work for all(?) NRF52 boards
|
// technically speaking this should work for all(?) NRF52 boards
|
||||||
// but needs testing across multiple devices. NRF52 USB would not even work if
|
// but needs testing across multiple devices. NRF52 USB would not even work if
|
||||||
|
|||||||
@@ -1175,7 +1175,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||||
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||||
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
||||||
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
|
favoriteFrames.push_back(graphics::UIRenderer::drawFavoriteNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1204,7 +1204,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||||
|
|
||||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list just changed)
|
prevFrame = -1; // Force drawFavoriteNode to pick a new node (because our list just changed)
|
||||||
|
|
||||||
// Focus on a specific frame, in the frame set we just created
|
// Focus on a specific frame, in the frame set we just created
|
||||||
switch (focus) {
|
switch (focus) {
|
||||||
|
|||||||
@@ -877,15 +877,15 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
// Send Message (Right side)
|
// Send Message (Right side)
|
||||||
display->drawRect(x1 + 2 - bubbleW, y1 - bubbleH, bubbleW, bubbleH);
|
display->drawRect(x1 + 2 - bubbleW, y1 - bubbleH, bubbleW, bubbleH);
|
||||||
// Top Right Corner
|
// Top Right Corner
|
||||||
display->drawRect(x1, topY, 2, 1);
|
display->drawRect(x1 - 1, topY, 2, 1);
|
||||||
display->drawRect(x1, topY, 1, 2);
|
display->drawRect(x1, topY, 1, 2);
|
||||||
// Bottom Right Corner
|
// Bottom Right Corner
|
||||||
display->drawRect(x1 - 1, bottomY - 2, 2, 1);
|
display->drawRect(x1 - 1, bottomY - 2, 2, 1);
|
||||||
display->drawRect(x1, bottomY - 3, 1, 2);
|
display->drawRect(x1, bottomY - 3, 1, 2);
|
||||||
// Knock the corners off to make a bubble
|
// Knock the corners off to make a bubble
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
display->drawRect(x1 - bubbleW, topY - 1, 1, 1);
|
display->drawRect(x1 - bubbleW + 2, topY - 1, 1, 1);
|
||||||
display->drawRect(x1 - bubbleW, bottomY - 1, 1, 1);
|
display->drawRect(x1 - bubbleW + 2, bottomY - 1, 1, 1);
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
} else {
|
} else {
|
||||||
// Received Message (Left Side)
|
// Received Message (Left Side)
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#include "CompassRenderer.h"
|
#include "CompassRenderer.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "NodeListRenderer.h"
|
#include "NodeListRenderer.h"
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
#include "modules/StatusMessageModule.h"
|
||||||
|
#endif
|
||||||
#include "UIRenderer.h"
|
#include "UIRenderer.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
#include "gps/RTC.h" // for getTime() function
|
#include "gps/RTC.h" // for getTime() function
|
||||||
@@ -90,8 +93,41 @@ const char *getSafeNodeName(OLEDDisplay *display, meshtastic_NodeInfoLite *node,
|
|||||||
|
|
||||||
// 1) Choose target candidate (long vs short) only if present
|
// 1) Choose target candidate (long vs short) only if present
|
||||||
const char *raw = nullptr;
|
const char *raw = nullptr;
|
||||||
if (node && node->has_user) {
|
|
||||||
raw = config.display.use_long_node_name ? node->user.long_name : node->user.short_name;
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
// If long-name mode is enabled, and we have a recent status for this node,
|
||||||
|
// prefer "(short_name) statusText" as the raw candidate.
|
||||||
|
std::string composedFromStatus;
|
||||||
|
if (config.display.use_long_node_name && node && node->has_user && statusMessageModule) {
|
||||||
|
const auto &recent = statusMessageModule->getRecentReceived();
|
||||||
|
const StatusMessageModule::RecentStatus *found = nullptr;
|
||||||
|
for (auto it = recent.rbegin(); it != recent.rend(); ++it) {
|
||||||
|
if (it->fromNodeId == node->num && !it->statusText.empty()) {
|
||||||
|
found = &(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
const char *shortName = node->user.short_name;
|
||||||
|
composedFromStatus.reserve(4 + (shortName ? std::strlen(shortName) : 0) + 1 + found->statusText.size());
|
||||||
|
composedFromStatus += "(";
|
||||||
|
if (shortName && *shortName) {
|
||||||
|
composedFromStatus += shortName;
|
||||||
|
}
|
||||||
|
composedFromStatus += ") ";
|
||||||
|
composedFromStatus += found->statusText;
|
||||||
|
|
||||||
|
raw = composedFromStatus.c_str(); // safe for now; we'll sanitize immediately into std::string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If we didn't compose from status, use normal long/short selection
|
||||||
|
if (!raw) {
|
||||||
|
if (node && node->has_user) {
|
||||||
|
raw = config.display.use_long_node_name ? node->user.long_name : node->user.short_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Sanitize (empty if raw is null/empty)
|
// 2) Sanitize (empty if raw is null/empty)
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include "GPSStatus.h"
|
#include "GPSStatus.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "NodeListRenderer.h"
|
#include "NodeListRenderer.h"
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
#include "modules/StatusMessageModule.h"
|
||||||
|
#endif
|
||||||
#include "UIRenderer.h"
|
#include "UIRenderer.h"
|
||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
@@ -287,7 +290,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
|||||||
// **********************
|
// **********************
|
||||||
// * Favorite Node Info *
|
// * Favorite Node Info *
|
||||||
// **********************
|
// **********************
|
||||||
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void UIRenderer::drawFavoriteNode(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
if (favoritedNodes.empty())
|
if (favoritedNodes.empty())
|
||||||
return;
|
return;
|
||||||
@@ -341,6 +344,57 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
display->drawString(x, getTextPositions(display)[line++], usernameStr.c_str());
|
display->drawString(x, getTextPositions(display)[line++], usernameStr.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
// === Optional: Last received StatusMessage line for this node ===
|
||||||
|
// Display it directly under the username line (if we have one).
|
||||||
|
if (statusMessageModule) {
|
||||||
|
const auto &recent = statusMessageModule->getRecentReceived();
|
||||||
|
const StatusMessageModule::RecentStatus *found = nullptr;
|
||||||
|
|
||||||
|
// Search newest-to-oldest
|
||||||
|
for (auto it = recent.rbegin(); it != recent.rend(); ++it) {
|
||||||
|
if (it->fromNodeId == node->num && !it->statusText.empty()) {
|
||||||
|
found = &(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
std::string statusLine = std::string(" Status: ") + found->statusText;
|
||||||
|
{
|
||||||
|
const int screenW = display->getWidth();
|
||||||
|
const int ellipseW = display->getStringWidth("...");
|
||||||
|
int w = display->getStringWidth(statusLine.c_str());
|
||||||
|
|
||||||
|
// Only do work if it overflows
|
||||||
|
if (w > screenW) {
|
||||||
|
bool truncated = false;
|
||||||
|
if (ellipseW > screenW) {
|
||||||
|
statusLine.clear();
|
||||||
|
} else {
|
||||||
|
while (!statusLine.empty()) {
|
||||||
|
// remove one char (byte) at a time
|
||||||
|
statusLine.pop_back();
|
||||||
|
truncated = true;
|
||||||
|
|
||||||
|
// Measure candidate with ellipsis appended
|
||||||
|
std::string candidate = statusLine + "...";
|
||||||
|
if (display->getStringWidth(candidate.c_str()) <= screenW) {
|
||||||
|
statusLine = std::move(candidate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (statusLine.empty() && ellipseW <= screenW) {
|
||||||
|
statusLine = "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display->drawString(x, getTextPositions(display)[line++], statusLine.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// === 2. Signal and Hops (combined on one line, if available) ===
|
// === 2. Signal and Hops (combined on one line, if available) ===
|
||||||
// If both are present: "Sig: 97% [2hops]"
|
// If both are present: "Sig: 97% [2hops]"
|
||||||
// If only one: show only that one
|
// If only one: show only that one
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class UIRenderer
|
|||||||
// Navigation bar overlay
|
// Navigation bar overlay
|
||||||
static void drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *state);
|
static void drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||||
|
|
||||||
static void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y);
|
static void drawFavoriteNode(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
|
|
||||||
static void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
static void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
|
|
||||||
|
|||||||
10
src/main.cpp
10
src/main.cpp
@@ -366,11 +366,7 @@ void setup()
|
|||||||
|
|
||||||
#ifdef BLE_LED
|
#ifdef BLE_LED
|
||||||
pinMode(BLE_LED, OUTPUT);
|
pinMode(BLE_LED, OUTPUT);
|
||||||
#ifdef BLE_LED_INVERTED
|
digitalWrite(BLE_LED, LED_STATE_OFF);
|
||||||
digitalWrite(BLE_LED, HIGH);
|
|
||||||
#else
|
|
||||||
digitalWrite(BLE_LED, LOW);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
concurrency::hasBeenSetup = true;
|
concurrency::hasBeenSetup = true;
|
||||||
@@ -493,7 +489,9 @@ void setup()
|
|||||||
// The ThinkNodes have their own blink logic
|
// The ThinkNodes have their own blink logic
|
||||||
// ledPeriodic = new Periodic("Blink", elecrowLedBlinker);
|
// ledPeriodic = new Periodic("Blink", elecrowLedBlinker);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
ledPeriodic = new Periodic("Blink", ledBlinker);
|
ledPeriodic = new Periodic("Blink", ledBlinker);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fsInit();
|
fsInit();
|
||||||
@@ -834,7 +832,7 @@ void setup()
|
|||||||
SPI.begin();
|
SPI.begin();
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
// ESP32
|
// ESP32
|
||||||
#if defined(HW_SPI1_DEVICE)
|
#if defined(HW_SPI1_DEVICE)
|
||||||
SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||||
LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||||
|
|||||||
@@ -1404,6 +1404,15 @@ void NodeDB::loadFromDisk()
|
|||||||
if (portduino_config.has_configDisplayMode) {
|
if (portduino_config.has_configDisplayMode) {
|
||||||
config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)portduino_config.configDisplayMode;
|
config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)portduino_config.configDisplayMode;
|
||||||
}
|
}
|
||||||
|
if (portduino_config.has_statusMessage) {
|
||||||
|
moduleConfig.has_statusmessage = true;
|
||||||
|
strncpy(moduleConfig.statusmessage.node_status, portduino_config.statusMessage.c_str(),
|
||||||
|
sizeof(moduleConfig.statusmessage.node_status));
|
||||||
|
moduleConfig.statusmessage.node_status[sizeof(moduleConfig.statusmessage.node_status) - 1] = '\0';
|
||||||
|
}
|
||||||
|
if (portduino_config.enable_UDP) {
|
||||||
|
config.network.enabled_protocols = true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1544,6 +1553,7 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
|||||||
moduleConfig.has_ambient_lighting = true;
|
moduleConfig.has_ambient_lighting = true;
|
||||||
moduleConfig.has_audio = true;
|
moduleConfig.has_audio = true;
|
||||||
moduleConfig.has_paxcounter = true;
|
moduleConfig.has_paxcounter = true;
|
||||||
|
moduleConfig.has_statusmessage = true;
|
||||||
|
|
||||||
success &=
|
success &=
|
||||||
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||||
@@ -2213,8 +2223,8 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location,
|
|||||||
} else if (location == meshtastic_AdminMessage_BackupLocation_SD) {
|
} else if (location == meshtastic_AdminMessage_BackupLocation_SD) {
|
||||||
// TODO: After more mainline SD card support
|
// TODO: After more mainline SD card support
|
||||||
}
|
}
|
||||||
return success;
|
|
||||||
#endif
|
#endif
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Record an error that should be reported via analytics
|
/// Record an error that should be reported via analytics
|
||||||
|
|||||||
@@ -905,10 +905,11 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
|
|
||||||
bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
||||||
{
|
{
|
||||||
|
bool shouldReboot = true;
|
||||||
// If we are in an open transaction or configuring MQTT or Serial (which have validation), defer disabling Bluetooth
|
// If we are in an open transaction or configuring MQTT or Serial (which have validation), defer disabling Bluetooth
|
||||||
// Otherwise, disable Bluetooth to prevent the phone from interfering with the config
|
// Otherwise, disable Bluetooth to prevent the phone from interfering with the config
|
||||||
if (!hasOpenEditTransaction &&
|
if (!hasOpenEditTransaction && !IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag,
|
||||||
!IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag, meshtastic_ModuleConfig_serial_tag)) {
|
meshtastic_ModuleConfig_serial_tag, meshtastic_ModuleConfig_statusmessage_tag)) {
|
||||||
disableBluetooth();
|
disableBluetooth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,8 +1001,14 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
|||||||
moduleConfig.has_paxcounter = true;
|
moduleConfig.has_paxcounter = true;
|
||||||
moduleConfig.paxcounter = c.payload_variant.paxcounter;
|
moduleConfig.paxcounter = c.payload_variant.paxcounter;
|
||||||
break;
|
break;
|
||||||
|
case meshtastic_ModuleConfig_statusmessage_tag:
|
||||||
|
LOG_INFO("Set module config: StatusMessage");
|
||||||
|
moduleConfig.has_statusmessage = true;
|
||||||
|
moduleConfig.statusmessage = c.payload_variant.statusmessage;
|
||||||
|
shouldReboot = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
saveChanges(SEGMENT_MODULECONFIG);
|
saveChanges(SEGMENT_MODULECONFIG, shouldReboot);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1180,6 +1187,11 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
|||||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
|
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
|
||||||
res.get_module_config_response.payload_variant.paxcounter = moduleConfig.paxcounter;
|
res.get_module_config_response.payload_variant.paxcounter = moduleConfig.paxcounter;
|
||||||
break;
|
break;
|
||||||
|
case meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG:
|
||||||
|
LOG_INFO("Get module config: StatusMessage");
|
||||||
|
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_statusmessage_tag;
|
||||||
|
res.get_module_config_response.payload_variant.statusmessage = moduleConfig.statusmessage;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
|
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
|
||||||
|
|||||||
@@ -90,6 +90,9 @@
|
|||||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||||
#include "modules/DropzoneModule.h"
|
#include "modules/DropzoneModule.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
#include "modules/StatusMessageModule.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAS_HARDWARE_WATCHDOG)
|
#if defined(HAS_HARDWARE_WATCHDOG)
|
||||||
#include "watchdog/watchdogThread.h"
|
#include "watchdog/watchdogThread.h"
|
||||||
@@ -150,6 +153,9 @@ void setupModules()
|
|||||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||||
dropzoneModule = new DropzoneModule();
|
dropzoneModule = new DropzoneModule();
|
||||||
#endif
|
#endif
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
statusMessageModule = new StatusMessageModule();
|
||||||
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
||||||
new GenericThreadModule();
|
new GenericThreadModule();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
54
src/modules/StatusMessageModule.cpp
Normal file
54
src/modules/StatusMessageModule.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
|
||||||
|
#include "StatusMessageModule.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "ProtobufModule.h"
|
||||||
|
|
||||||
|
StatusMessageModule *statusMessageModule;
|
||||||
|
|
||||||
|
int32_t StatusMessageModule::runOnce()
|
||||||
|
{
|
||||||
|
if (moduleConfig.has_statusmessage && moduleConfig.statusmessage.node_status[0] != '\0') {
|
||||||
|
// create and send message with the status message set
|
||||||
|
meshtastic_StatusMessage ourStatus = meshtastic_StatusMessage_init_zero;
|
||||||
|
strncpy(ourStatus.status, moduleConfig.statusmessage.node_status, sizeof(ourStatus.status));
|
||||||
|
ourStatus.status[sizeof(ourStatus.status) - 1] = '\0'; // ensure null termination
|
||||||
|
meshtastic_MeshPacket *p = allocDataPacket();
|
||||||
|
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
|
||||||
|
meshtastic_StatusMessage_fields, &ourStatus);
|
||||||
|
p->to = NODENUM_BROADCAST;
|
||||||
|
p->decoded.want_response = false;
|
||||||
|
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||||
|
p->channel = 0;
|
||||||
|
service->sendToMesh(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1000 * 12 * 60 * 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessMessage StatusMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||||
|
{
|
||||||
|
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||||
|
meshtastic_StatusMessage incomingMessage = meshtastic_StatusMessage_init_zero;
|
||||||
|
|
||||||
|
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_StatusMessage_fields,
|
||||||
|
&incomingMessage)) {
|
||||||
|
|
||||||
|
LOG_INFO("Received a NodeStatus message %s", incomingMessage.status);
|
||||||
|
|
||||||
|
RecentStatus entry;
|
||||||
|
entry.fromNodeId = mp.from;
|
||||||
|
entry.statusText = incomingMessage.status;
|
||||||
|
|
||||||
|
recentReceived.push_back(std::move(entry));
|
||||||
|
|
||||||
|
// Keep only last MAX_RECENT_STATUSMESSAGES
|
||||||
|
if (recentReceived.size() > MAX_RECENT_STATUSMESSAGES) {
|
||||||
|
recentReceived.erase(recentReceived.begin()); // drop oldest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ProcessMessage::CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
48
src/modules/StatusMessageModule.h
Normal file
48
src/modules/StatusMessageModule.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
#include "SinglePortModule.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class StatusMessageModule : public SinglePortModule, private concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
StatusMessageModule()
|
||||||
|
: SinglePortModule("statusMessage", meshtastic_PortNum_NODE_STATUS_APP), concurrency::OSThread("StatusMessage")
|
||||||
|
{
|
||||||
|
if (moduleConfig.has_statusmessage && moduleConfig.statusmessage.node_status[0] != '\0') {
|
||||||
|
this->setInterval(2 * 60 * 1000);
|
||||||
|
} else {
|
||||||
|
this->setInterval(1000 * 12 * 60 * 60);
|
||||||
|
}
|
||||||
|
// TODO: If we have a string, set the initial delay (15 minutes maybe)
|
||||||
|
|
||||||
|
// Keep vector from reallocating as we fill up to MAX_RECENT_STATUSMESSAGES
|
||||||
|
recentReceived.reserve(MAX_RECENT_STATUSMESSAGES);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
|
struct RecentStatus {
|
||||||
|
uint32_t fromNodeId; // mp.from
|
||||||
|
std::string statusText; // incomingMessage.status
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<RecentStatus> &getRecentReceived() const { return recentReceived; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Called to handle a particular incoming message
|
||||||
|
*/
|
||||||
|
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t MAX_RECENT_STATUSMESSAGES = 5;
|
||||||
|
std::vector<RecentStatus> recentReceived;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern StatusMessageModule *statusMessageModule;
|
||||||
|
#endif
|
||||||
@@ -757,11 +757,7 @@ void NimbleBluetooth::deinit()
|
|||||||
isDeInit = true;
|
isDeInit = true;
|
||||||
|
|
||||||
#ifdef BLE_LED
|
#ifdef BLE_LED
|
||||||
#ifdef BLE_LED_INVERTED
|
digitalWrite(BLE_LED, LED_STATE_OFF);
|
||||||
digitalWrite(BLE_LED, HIGH);
|
|
||||||
#else
|
|
||||||
digitalWrite(BLE_LED, LOW);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#ifndef NIMBLE_TWO
|
#ifndef NIMBLE_TWO
|
||||||
NimBLEDevice::deinit();
|
NimBLEDevice::deinit();
|
||||||
|
|||||||
@@ -872,6 +872,7 @@ bool loadConfig(const char *configPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (yamlConfig["Config"]) {
|
if (yamlConfig["Config"]) {
|
||||||
|
portduino_config.has_config_overrides = true;
|
||||||
if (yamlConfig["Config"]["DisplayMode"]) {
|
if (yamlConfig["Config"]["DisplayMode"]) {
|
||||||
portduino_config.has_configDisplayMode = true;
|
portduino_config.has_configDisplayMode = true;
|
||||||
if ((yamlConfig["Config"]["DisplayMode"]).as<std::string>("") == "TWOCOLOR") {
|
if ((yamlConfig["Config"]["DisplayMode"]).as<std::string>("") == "TWOCOLOR") {
|
||||||
@@ -884,6 +885,13 @@ bool loadConfig(const char *configPath)
|
|||||||
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
|
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (yamlConfig["Config"]["StatusMessage"]) {
|
||||||
|
portduino_config.has_statusMessage = true;
|
||||||
|
portduino_config.statusMessage = (yamlConfig["Config"]["StatusMessage"]).as<std::string>("");
|
||||||
|
}
|
||||||
|
if ((yamlConfig["Config"]["EnableUDP"]).as<bool>(false)) {
|
||||||
|
portduino_config.enable_UDP = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yamlConfig["General"]) {
|
if (yamlConfig["General"]) {
|
||||||
|
|||||||
@@ -177,8 +177,12 @@ extern struct portduino_config_struct {
|
|||||||
int hostMetrics_channel = 0;
|
int hostMetrics_channel = 0;
|
||||||
|
|
||||||
// config
|
// config
|
||||||
|
bool has_config_overrides = false;
|
||||||
int configDisplayMode = 0;
|
int configDisplayMode = 0;
|
||||||
bool has_configDisplayMode = false;
|
bool has_configDisplayMode = false;
|
||||||
|
std::string statusMessage = "";
|
||||||
|
bool has_statusMessage = false;
|
||||||
|
bool enable_UDP = false;
|
||||||
|
|
||||||
// General
|
// General
|
||||||
std::string mac_address = "";
|
std::string mac_address = "";
|
||||||
@@ -505,21 +509,30 @@ extern struct portduino_config_struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// config
|
// config
|
||||||
if (has_configDisplayMode) {
|
if (has_config_overrides) {
|
||||||
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
|
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
|
||||||
switch (configDisplayMode) {
|
if (has_configDisplayMode) {
|
||||||
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
|
|
||||||
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
|
switch (configDisplayMode) {
|
||||||
break;
|
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
|
||||||
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
|
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
|
||||||
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
|
break;
|
||||||
break;
|
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
|
||||||
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
|
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
|
||||||
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
|
break;
|
||||||
break;
|
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
|
||||||
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
|
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
|
||||||
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
|
break;
|
||||||
break;
|
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
|
||||||
|
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_statusMessage) {
|
||||||
|
out << YAML::Key << "StatusMessage" << YAML::Value << statusMessage;
|
||||||
|
}
|
||||||
|
if (enable_UDP) {
|
||||||
|
out << YAML::Key << "EnableUDP" << YAML::Value << true;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << YAML::EndMap; // Config
|
out << YAML::EndMap; // Config
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
#define NO_GPS 1
|
#define NO_GPS 1
|
||||||
#define HAS_GPS 0
|
#define HAS_GPS 0
|
||||||
#define NO_SCREEN
|
|
||||||
#define HAS_SCREEN 0
|
#define HAS_SCREEN 0
|
||||||
|
|
||||||
// Default SPI1 will be mapped to the display
|
// Default SPI1 will be mapped to the display
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#define EXT_NOTIFY_OUT 22
|
#define EXT_NOTIFY_OUT 22
|
||||||
#define BUTTON_PIN 0 // 17
|
#define BUTTON_PIN 0 // 17
|
||||||
|
|
||||||
// #define LED_PIN PIN_LED
|
|
||||||
// Board has RGB LED 21
|
// Board has RGB LED 21
|
||||||
#define HAS_NEOPIXEL // Enable the use of neopixels
|
#define HAS_NEOPIXEL // Enable the use of neopixels
|
||||||
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
|
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ extern "C" {
|
|||||||
#define PIN_LED2 LED_BLUE
|
#define PIN_LED2 LED_BLUE
|
||||||
#define PIN_LED3 LED_RED
|
#define PIN_LED3 LED_RED
|
||||||
|
|
||||||
#define PIN_LED PIN_LED1
|
|
||||||
|
|
||||||
#define LED_STATE_ON 1 // State when LED is lit
|
#define LED_STATE_ON 1 // State when LED is lit
|
||||||
|
|
||||||
// XIAO Wio-SX1262 Shield User button
|
// XIAO Wio-SX1262 Shield User button
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ extern "C" {
|
|||||||
#define LED_GREEN PIN_LED1
|
#define LED_GREEN PIN_LED1
|
||||||
|
|
||||||
#define BLE_LED LED_BLUE
|
#define BLE_LED LED_BLUE
|
||||||
#define BLE_LED_INVERTED 1
|
|
||||||
#define LED_STATE_ON 0 // State when LED is lit
|
#define LED_STATE_ON 0 // State when LED is lit
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#define ADC_RESOLUTION (12u)
|
#define ADC_RESOLUTION (12u)
|
||||||
|
|
||||||
// LEDs
|
// LEDs
|
||||||
#define PIN_LED (24u)
|
#define LED_PIN (24u)
|
||||||
|
|
||||||
// Serial
|
// Serial
|
||||||
#define PIN_SERIAL1_TX (16u)
|
#define PIN_SERIAL1_TX (16u)
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#define EXT_NOTIFY_OUT 0xFFFFFFFF
|
#define EXT_NOTIFY_OUT 0xFFFFFFFF
|
||||||
#define BUTTON_PIN 0xFFFFFFFF
|
#define BUTTON_PIN 0xFFFFFFFF
|
||||||
|
|
||||||
#define LED_PIN PIN_LED
|
|
||||||
|
|
||||||
#define USE_RF95 // RFM95/SX127x
|
#define USE_RF95 // RFM95/SX127x
|
||||||
|
|
||||||
#undef LORA_SCK
|
#undef LORA_SCK
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ static const uint8_t A2 = PIN_A2;
|
|||||||
static const uint8_t A3 = PIN_A3;
|
static const uint8_t A3 = PIN_A3;
|
||||||
|
|
||||||
// LEDs
|
// LEDs
|
||||||
#define PIN_LED (23u)
|
#define PIN_LED1 (23u)
|
||||||
#define PIN_LED1 PIN_LED
|
|
||||||
#define LED_NOTIFICATION (24u)
|
#define LED_NOTIFICATION (24u)
|
||||||
|
|
||||||
#define ADC_RESOLUTION 12
|
#define ADC_RESOLUTION 12
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#define I2C_SDA1 2
|
#define I2C_SDA1 2
|
||||||
#define I2C_SCL1 3
|
#define I2C_SCL1 3
|
||||||
|
|
||||||
#define LED_PIN PIN_LED
|
#define LED_PIN PIN_LED1
|
||||||
#define ledOff(pin) pinMode(pin, INPUT)
|
#define ledOff(pin) pinMode(pin, INPUT)
|
||||||
|
|
||||||
#define BUTTON_PIN 9
|
#define BUTTON_PIN 9
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ static const uint8_t A2 = PIN_A2;
|
|||||||
static const uint8_t A3 = PIN_A3;
|
static const uint8_t A3 = PIN_A3;
|
||||||
|
|
||||||
// LEDs
|
// LEDs
|
||||||
#define PIN_LED (23u)
|
#define PIN_LED1 (23u)
|
||||||
#define PIN_LED1 PIN_LED
|
|
||||||
|
|
||||||
#define ADC_RESOLUTION 12
|
#define ADC_RESOLUTION 12
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#define BUTTON_PIN 2
|
#define BUTTON_PIN 2
|
||||||
#define BUTTON_NEED_PULLUP
|
#define BUTTON_NEED_PULLUP
|
||||||
|
|
||||||
#define LED_PIN PIN_LED
|
#define LED_PIN PIN_LED1
|
||||||
#define ledOff(pin) pinMode(pin, INPUT)
|
#define ledOff(pin) pinMode(pin, INPUT)
|
||||||
|
|
||||||
#undef BATTERY_PIN
|
#undef BATTERY_PIN
|
||||||
|
|||||||
Reference in New Issue
Block a user