Merge branch 'master' into add-traceroute

This commit is contained in:
whywilson 2025-07-21 11:50:01 +08:00
commit d7a3dee1be
282 changed files with 673 additions and 406 deletions

24
.github/workflows/pr_enforce_labels.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: Check PR Labels
on:
pull_request:
types: [opened, edited, labeled, unlabeled, synchronize, reopened]
permissions:
pull-requests: read
contents: read
jobs:
check-label:
runs-on: ubuntu-24.04
steps:
- name: Check for PR labels
uses: actions/github-script@v7
with:
script: |
const labels = context.payload.pull_request.labels.map(label => label.name);
const requiredLabels = ['bugfix', 'enhancement', 'hardware-support', 'dependencies', 'submodules', 'github_actions', 'trunk'];
const hasRequiredLabel = labels.some(label => requiredLabels.includes(label));
if (!hasRequiredLabel) {
core.setFailed(`PR must have at least one of the following labels before it can be merged: ${requiredLabels.join(', ')}.`);
}

View File

@ -103,8 +103,9 @@ jobs:
with: with:
base: ${{ github.event.repository.default_branch }} base: ${{ github.event.repository.default_branch }}
branch: create-pull-request/bump-version branch: create-pull-request/bump-version
labels: github_actions
title: Bump release version title: Bump release version
commit-message: automated bumps commit-message: Automated version bumps
add-paths: | add-paths: |
version.properties version.properties
debian/changelog debian/changelog

View File

@ -34,7 +34,9 @@ jobs:
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v7
with: with:
branch: create-pull-request/update-protobufs branch: create-pull-request/update-protobufs
labels: submodules
title: Update protobufs and classes title: Update protobufs and classes
commit-message: Update protobufs
add-paths: | add-paths: |
protobufs protobufs
src/mesh src/mesh

View File

@ -8,15 +8,15 @@ plugins:
uri: https://github.com/trunk-io/plugins uri: https://github.com/trunk-io/plugins
lint: lint:
enabled: enabled:
- checkov@3.2.450 - checkov@3.2.451
- renovate@41.30.5 - renovate@41.37.9
- prettier@3.6.2 - prettier@3.6.2
- trufflehog@3.89.2 - trufflehog@3.90.0
- yamllint@1.37.1 - yamllint@1.37.1
- bandit@1.8.6 - bandit@1.8.6
- trivy@0.64.1 - trivy@0.64.1
- taplo@0.9.3 - taplo@0.9.3
- ruff@0.12.2 - ruff@0.12.3
- isort@6.0.1 - isort@6.0.1
- markdownlint@0.45.0 - markdownlint@0.45.0
- oxipng@9.1.5 - oxipng@9.1.5

View File

@ -39,7 +39,7 @@ build_flags =
-Isrc/platform/portduino -Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED -DRADIOLIB_EEPROM_UNSUPPORTED
-DPORTDUINO_LINUX_HARDWARE -DPORTDUINO_LINUX_HARDWARE
-DHAS_UDP_MULTICAST -DHAS_UDP_MULTICAST=1
-lpthread -lpthread
-lstdc++fs -lstdc++fs
-lbluetooth -lbluetooth

View File

@ -87,6 +87,9 @@
</screenshots> </screenshots>
<releases> <releases>
<release version="2.7.4" date="2025-07-19">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.4</url>
</release>
<release version="2.7.3" date="2025-07-10"> <release version="2.7.3" date="2025-07-10">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.3</url> <url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.3</url>
</release> </release>

7
debian/changelog vendored
View File

@ -1,4 +1,4 @@
meshtasticd (2.7.3.0) UNRELEASED; urgency=medium meshtasticd (2.7.4.0) UNRELEASED; urgency=medium
[ Austin Lane ] [ Austin Lane ]
* Initial packaging * Initial packaging
@ -31,4 +31,7 @@ meshtasticd (2.7.3.0) UNRELEASED; urgency=medium
[ Ubuntu ] [ Ubuntu ]
* GitHub Actions Automatic version bump * GitHub Actions Automatic version bump
-- Ubuntu <github-actions[bot]@users.noreply.github.com> Thu, 10 Jul 2025 16:29:27 +0000 [ ]
* GitHub Actions Automatic version bump
-- <github-actions[bot]@users.noreply.github.com> Sat, 19 Jul 2025 11:36:55 +0000

View File

@ -6,7 +6,9 @@ default_envs = tbeam
extra_configs = extra_configs =
arch/*/*.ini arch/*/*.ini
variants/*/platformio.ini variants/*/platformio.ini ; Remove when all variants migrated to new dir structure
variants/*/*/platformio.ini
variants/*/diy/*/platformio.ini
src/graphics/niche/InkHUD/PlatformioConfig.ini src/graphics/niche/InkHUD/PlatformioConfig.ini
description = Meshtastic description = Meshtastic

@ -1 +1 @@
Subproject commit f6448be7770a3521bf52407ff8f5fa5b9b06da7b Subproject commit 15c1fbde882de953dec279160fa984d0e00569d0

View File

@ -681,7 +681,16 @@ bool Power::setup()
void Power::shutdown() void Power::shutdown()
{ {
LOG_INFO("Shutting Down");
#if HAS_SCREEN
if (screen) {
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
}
#endif
#if !defined(ARCH_STM32WL)
playShutdownMelody();
#endif
nodeDB->saveToDisk();
#if defined(ARCH_NRF52) || defined(ARCH_ESP32) || defined(ARCH_RP2040) #if defined(ARCH_NRF52) || defined(ARCH_ESP32) || defined(ARCH_RP2040)
#ifdef PIN_LED1 #ifdef PIN_LED1
@ -693,7 +702,11 @@ void Power::shutdown()
#ifdef PIN_LED3 #ifdef PIN_LED3
ledOff(PIN_LED3); ledOff(PIN_LED3);
#endif #endif
doDeepSleep(DELAY_FOREVER, false, false); doDeepSleep(DELAY_FOREVER, false, true);
#elif defined(ARCH_PORTDUINO)
exit(EXIT_SUCCESS);
#else
LOG_WARN("FIXME implement shutdown for this platform");
#endif #endif
} }

View File

@ -47,10 +47,6 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
playComboTune(); // Ping sent feedback playComboTune(); // Ping sent feedback
break; break;
case INPUT_BROKER_SHUTDOWN:
playShutdownMelody(); // Shutdown feedback
break;
default: default:
// For other events, check if it's a printable character // For other events, check if it's a printable character
if (event->kbchar >= 32 && event->kbchar <= 126) { if (event->kbchar >= 32 && event->kbchar <= 126) {
@ -69,10 +65,7 @@ int32_t BuzzerFeedbackThread::runOnce()
// This thread is primarily event-driven, but we can use runOnce // This thread is primarily event-driven, but we can use runOnce
// for any periodic tasks if needed in the future // for any periodic tasks if needed in the future
if (needsUpdate) { needsUpdate = false;
needsUpdate = false;
// Could add any periodic processing here
}
// Run every 100ms when active, less frequently when idle // Run every 100ms when active, less frequently when idle
return needsUpdate ? 100 : 1000; return needsUpdate ? 100 : 1000;

View File

@ -1001,7 +1001,7 @@ void Screen::setFrames(FrameFocus focus)
// Insert favorite frames *after* collecting them all // Insert favorite frames *after* collecting them all
if (!favoriteFrames.empty()) { if (!favoriteFrames.empty()) {
fsi.positions.firstFavorite = numframes; fsi.positions.firstFavorite = numframes;
for (auto &f : favoriteFrames) { for (const auto &f : favoriteFrames) {
normalFrames[numframes++] = f; normalFrames[numframes++] = f;
indicatorIcons.push_back(icon_node); indicatorIcons.push_back(icon_node);
} }

View File

@ -218,7 +218,6 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
hour %= 12; hour %= 12;
if (hour == 0) if (hour == 0)
hour = 12; hour = 12;
bool isPM = hour >= 12;
snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute); snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute);
} else { } else {
snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute); snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute);
@ -367,7 +366,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// hour hand radius and y coordinate // hour hand radius and y coordinate
int16_t hourHandRadius = radius * 0.35; int16_t hourHandRadius = radius * 0.35;
if (isHighResolution) { if (isHighResolution) {
int16_t hourHandRadius = radius * 0.55; hourHandRadius = radius * 0.55;
} }
int16_t hourHandNoonY = centerY - hourHandRadius; int16_t hourHandNoonY = centerY - hourHandRadius;
@ -386,7 +385,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
bool isPM = hour >= 12; bool isPM = hour >= 12;
if (config.display.use_12h_clock) { if (config.display.use_12h_clock) {
bool isPM = hour >= 12; isPM = hour >= 12;
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
int yOffset = isHighResolution ? 1 : 0; int yOffset = isHighResolution ? 1 : 0;
#ifdef USE_EINK #ifdef USE_EINK

View File

@ -825,9 +825,8 @@ void menuHandler::shutdownMenu()
bannerOptions.optionsCount = 2; bannerOptions.optionsCount = 2;
bannerOptions.bannerCallback = [](int selected) -> void { bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == 1) { if (selected == 1) {
IF_SCREEN(screen->showSimpleBanner("Shutting Down...", 0)); InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_SHUTDOWN, .kbchar = 0, .touchX = 0, .touchY = 0};
nodeDB->saveToDisk(); inputBroker->injectInputEvent(&event);
power->shutdown();
} else { } else {
menuQueue = power_menu; menuQueue = power_menu;
screen->runNow(); screen->runNow();

View File

@ -53,23 +53,21 @@ bool ButtonThread::initButton(const ButtonConfig &config)
}, },
this); this);
if (config.longPress != INPUT_BROKER_NONE) { _longPress = config.longPress;
_longPress = config.longPress; userButton.attachLongPressStart(
userButton.attachLongPressStart( [](void *callerThread) -> void {
[](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread;
ButtonThread *thread = (ButtonThread *)callerThread; // if (millis() > 30000) // hold off 30s after boot
// if (millis() > 30000) // hold off 30s after boot thread->btnEvent = BUTTON_EVENT_LONG_PRESSED;
thread->btnEvent = BUTTON_EVENT_LONG_PRESSED; },
}, this);
this); userButton.attachLongPressStop(
userButton.attachLongPressStop( [](void *callerThread) -> void {
[](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread;
ButtonThread *thread = (ButtonThread *)callerThread; // if (millis() > 30000) // hold off 30s after boot
// if (millis() > 30000) // hold off 30s after boot thread->btnEvent = BUTTON_EVENT_LONG_RELEASED;
thread->btnEvent = BUTTON_EVENT_LONG_RELEASED; },
}, this);
this);
}
if (config.doublePress != INPUT_BROKER_NONE) { if (config.doublePress != INPUT_BROKER_NONE) {
_doublePress = config.doublePress; _doublePress = config.doublePress;
@ -202,11 +200,11 @@ int32_t ButtonThread::runOnce()
break; break;
} }
if (_longPress != INPUT_BROKER_NONE) {
// Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event) // Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event)
evt.inputEvent = _longPress; evt.inputEvent = _longPress;
this->notifyObservers(&evt); this->notifyObservers(&evt);
}
// Reset combination tracking // Reset combination tracking
waitingForLongPress = false; waitingForLongPress = false;
@ -253,7 +251,7 @@ int32_t ButtonThread::runOnce()
// may wake the board immediatedly. // may wake the board immediatedly.
case BUTTON_EVENT_LONG_RELEASED: { case BUTTON_EVENT_LONG_RELEASED: {
LOG_INFO("LONG PRESS RELEASE"); LOG_INFO("LONG PRESS RELEASE AFTER %u MILLIS", millis() - buttonPressStartTime);
if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE && if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE &&
(millis() - buttonPressStartTime) >= _longLongPressTime) { (millis() - buttonPressStartTime) >= _longLongPressTime) {
evt.inputEvent = _longLongPress; evt.inputEvent = _longLongPress;

View File

@ -18,13 +18,13 @@ struct ButtonConfig {
uint16_t longPressTime = 500; uint16_t longPressTime = 500;
input_broker_event doublePress = INPUT_BROKER_NONE; input_broker_event doublePress = INPUT_BROKER_NONE;
input_broker_event longLongPress = INPUT_BROKER_NONE; input_broker_event longLongPress = INPUT_BROKER_NONE;
uint16_t longLongPressTime = 5000; uint16_t longLongPressTime = 3900;
input_broker_event triplePress = INPUT_BROKER_NONE; input_broker_event triplePress = INPUT_BROKER_NONE;
input_broker_event shortLong = INPUT_BROKER_NONE; input_broker_event shortLong = INPUT_BROKER_NONE;
bool touchQuirk = false; bool touchQuirk = false;
// Constructor to set required parameter // Constructor to set required parameter
ButtonConfig(uint8_t pin = 0) : pinNumber(pin) {} explicit ButtonConfig(uint8_t pin = 0) : pinNumber(pin) {}
}; };
#ifndef BUTTON_CLICK_MS #ifndef BUTTON_CLICK_MS
@ -62,7 +62,7 @@ class ButtonThread : public Observable<const InputEvent *>, public concurrency::
BUTTON_EVENT_COMBO_SHORT_LONG, BUTTON_EVENT_COMBO_SHORT_LONG,
}; };
ButtonThread(const char *name); explicit ButtonThread(const char *name);
int32_t runOnce() override; int32_t runOnce() override;
OneButton userButton; OneButton userButton;
void attachButtonInterrupts(); void attachButtonInterrupts();

View File

@ -233,14 +233,7 @@ void ExpressLRSFiveWay::sendAdhocPing()
// Contained as one method for easier remapping of buttons by user // Contained as one method for easier remapping of buttons by user
void ExpressLRSFiveWay::shutdown() void ExpressLRSFiveWay::shutdown()
{ {
LOG_INFO("Shutdown from long press"); sendKey(INPUT_BROKER_SHUTDOWN);
powerFSM.trigger(EVENT_PRESS);
screen->startAlert("Shutting Down...");
// Don't set alerting = true. We don't want to auto-dismiss this alert.
playShutdownMelody(); // In case user adds a buzzer
shutdownAtMsec = millis() + 3000;
} }
void ExpressLRSFiveWay::click() void ExpressLRSFiveWay::click()

View File

@ -1042,8 +1042,9 @@ void setup()
mainDelay.interruptFromISR(&higherWake); mainDelay.interruptFromISR(&higherWake);
}; };
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS; userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
userConfigNoScreen.longPress = INPUT_BROKER_SHUTDOWN; userConfigNoScreen.longPress = INPUT_BROKER_NONE;
userConfigNoScreen.longPressTime = 5000; userConfigNoScreen.longPressTime = 500;
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING; userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE; userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
UserButtonThread->initButton(userConfigNoScreen); UserButtonThread->initButton(userConfigNoScreen);

View File

@ -121,7 +121,7 @@ meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool t
bool MeshPacketQueue::find(const NodeNum from, const PacketId id) bool MeshPacketQueue::find(const NodeNum from, const PacketId id)
{ {
for (auto it = queue.begin(); it != queue.end(); it++) { for (auto it = queue.begin(); it != queue.end(); it++) {
const auto p = (*it); const auto *p = *it;
if (getFrom(p) == from && p->id == id) { if (getFrom(p) == from && p->id == id) {
return true; return true;
} }

View File

@ -16,6 +16,7 @@
#include "meshUtils.h" #include "meshUtils.h"
#include "modules/NodeInfoModule.h" #include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h" #include "modules/PositionModule.h"
#include "modules/RoutingModule.h"
#include "power.h" #include "power.h"
#include <assert.h> #include <assert.h>
#include <string> #include <string>
@ -333,6 +334,21 @@ void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage
fromNum++; fromNum++;
} }
void MeshService::sendRoutingErrorResponse(meshtastic_Routing_Error error, const meshtastic_MeshPacket *mp)
{
if (!mp) {
LOG_WARN("Cannot send routing error response: null packet");
return;
}
// Use the routing module to send the error response
if (routingModule) {
routingModule->sendAckNak(error, mp->from, mp->id, mp->channel);
} else {
LOG_ERROR("Cannot send routing error response: no routing module");
}
}
void MeshService::sendClientNotification(meshtastic_ClientNotification *n) void MeshService::sendClientNotification(meshtastic_ClientNotification *n)
{ {
LOG_DEBUG("Send client notification to phone"); LOG_DEBUG("Send client notification to phone");

View File

@ -148,6 +148,9 @@ class MeshService
/// Send a ClientNotification to the phone /// Send a ClientNotification to the phone
void sendClientNotification(meshtastic_ClientNotification *cn); void sendClientNotification(meshtastic_ClientNotification *cn);
/// Send an error response to the phone
void sendRoutingErrorResponse(meshtastic_Routing_Error error, const meshtastic_MeshPacket *mp);
bool isToPhoneQueueEmpty(); bool isToPhoneQueueEmpty();
ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id); ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);

View File

@ -1868,7 +1868,7 @@ UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum)
return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed; return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed;
} }
bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t keyToTest) bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest)
{ {
if (keyToTest.size == 32) { if (keyToTest.size == 32) {
uint8_t keyHash[32] = {0}; uint8_t keyHash[32] = {0};

View File

@ -279,7 +279,7 @@ class NodeDB
bool hasValidPosition(const meshtastic_NodeInfoLite *n); bool hasValidPosition(const meshtastic_NodeInfoLite *n);
bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t keyToTest); bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest);
bool backupPreferences(meshtastic_AdminMessage_BackupLocation location); bool backupPreferences(meshtastic_AdminMessage_BackupLocation location);
bool restorePreferences(meshtastic_AdminMessage_BackupLocation location, bool restorePreferences(meshtastic_AdminMessage_BackupLocation location,

View File

@ -181,7 +181,7 @@ PacketHistory::PacketRecord *PacketHistory::find(NodeNum sender, PacketId id)
} }
/** Insert/Replace oldest PacketRecord in recentPackets. */ /** Insert/Replace oldest PacketRecord in recentPackets. */
void PacketHistory::insert(PacketRecord &r) void PacketHistory::insert(const PacketRecord &r)
{ {
uint32_t now_millis = millis(); // Should not jump with time changes uint32_t now_millis = millis(); // Should not jump with time changes
uint32_t OldtrxTimeMsec = 0; uint32_t OldtrxTimeMsec = 0;
@ -308,7 +308,7 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N
return false; return false;
} }
PacketRecord *found = find(sender, id); const PacketRecord *found = find(sender, id);
if (found == NULL) { if (found == NULL) {
#if VERBOSE_PACKET_HISTORY #if VERBOSE_PACKET_HISTORY
@ -327,7 +327,7 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N
/* Check if a certain node was a relayer of a packet in the history given iterator /* Check if a certain node was a relayer of a packet in the history given iterator
* @return true if node was indeed a relayer, false if not */ * @return true if node was indeed a relayer, false if not */
bool PacketHistory::wasRelayer(const uint8_t relayer, PacketRecord &r) bool PacketHistory::wasRelayer(const uint8_t relayer, const PacketRecord &r)
{ {
for (uint8_t i = 0; i < NUM_RELAYERS; i++) { for (uint8_t i = 0; i < NUM_RELAYERS; i++) {
if (r.relayed_by[i] == relayer) { if (r.relayed_by[i] == relayer) {

View File

@ -31,11 +31,11 @@ class PacketHistory
/** Insert/Replace oldest PacketRecord in mx_recentPackets. /** Insert/Replace oldest PacketRecord in mx_recentPackets.
* @param r PacketRecord to insert or replace */ * @param r PacketRecord to insert or replace */
void insert(PacketRecord &r); // Insert or replace a packet record in the history void insert(const PacketRecord &r); // Insert or replace a packet record in the history
/* Check if a certain node was a relayer of a packet in the history given iterator /* Check if a certain node was a relayer of a packet in the history given iterator
* @return true if node was indeed a relayer, false if not */ * @return true if node was indeed a relayer, false if not */
bool wasRelayer(const uint8_t relayer, PacketRecord &r); bool wasRelayer(const uint8_t relayer, const PacketRecord &r);
PacketHistory(const PacketHistory &); // non construction-copyable PacketHistory(const PacketHistory &); // non construction-copyable
PacketHistory &operator=(const PacketHistory &); // non copyable PacketHistory &operator=(const PacketHistory &); // non copyable

View File

@ -686,7 +686,8 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
LOG_WARN("Rate limit portnum %d", p.decoded.portnum); LOG_WARN("Rate limit portnum %d", p.decoded.portnum);
meshtastic_QueueStatus qs = router->getQueueStatus(); meshtastic_QueueStatus qs = router->getQueueStatus();
service->sendQueueStatusToPhone(qs, 0, p.id); service->sendQueueStatusToPhone(qs, 0, p.id);
sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds"); service->sendRoutingErrorResponse(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED, &p);
// sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds");
return false; return false;
} }
lastPortNumToRadio[p.decoded.portnum] = millis(); lastPortNumToRadio[p.decoded.portnum] = millis();

View File

@ -68,6 +68,11 @@ static int32_t reconnectETH()
initApiServer(); initApiServer();
} }
#endif #endif
#if HAS_UDP_MULTICAST
if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
udpHandler->start();
}
#endif
ethStartupComplete = true; ethStartupComplete = true;
} }

View File

@ -2,7 +2,6 @@
#include "configuration.h" #include "configuration.h"
#include <Arduino.h> #include <Arduino.h>
#include <functional>
bool initEthernet(); bool initEthernet();
bool isEthernetAvailable(); bool isEthernetAvailable();

View File

@ -480,7 +480,8 @@ typedef struct _meshtastic_Config_DisplayConfig {
/* Number of seconds the screen stays on after pressing the user button or receiving a message /* Number of seconds the screen stays on after pressing the user button or receiving a message
0 for default of one minute MAXUINT for always on */ 0 for default of one minute MAXUINT for always on */
uint32_t screen_on_secs; uint32_t screen_on_secs;
/* How the GPS coordinates are formatted on the OLED screen. */ /* Deprecated in 2.7.4: Unused
How the GPS coordinates are formatted on the OLED screen. */
meshtastic_Config_DisplayConfig_GpsCoordinateFormat gps_format; meshtastic_Config_DisplayConfig_GpsCoordinateFormat gps_format;
/* Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds. /* Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds.
Potentially useful for devices without user buttons. */ Potentially useful for devices without user buttons. */

View File

@ -426,7 +426,10 @@ typedef enum _meshtastic_Routing_Error {
/* Admin packet otherwise checks out, but uses a bogus or expired session key */ /* Admin packet otherwise checks out, but uses a bogus or expired session key */
meshtastic_Routing_Error_ADMIN_BAD_SESSION_KEY = 36, meshtastic_Routing_Error_ADMIN_BAD_SESSION_KEY = 36,
/* Admin packet sent using PKC, but not from a public key on the admin key list */ /* Admin packet sent using PKC, but not from a public key on the admin key list */
meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37 meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37,
/* Airtime fairness rate limit exceeded for a packet
This typically enforced per portnum and is used to prevent a single node from monopolizing airtime */
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38
} meshtastic_Routing_Error; } meshtastic_Routing_Error;
/* The priority of this message for sending. /* The priority of this message for sending.
@ -1222,8 +1225,8 @@ extern "C" {
#define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1)) #define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1))
#define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE #define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED #define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED+1)) #define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1))
#define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET #define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET
#define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX #define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX

View File

@ -93,7 +93,11 @@ typedef enum _meshtastic_TelemetrySensorType {
/* PCT2075 Temperature Sensor */ /* PCT2075 Temperature Sensor */
meshtastic_TelemetrySensorType_PCT2075 = 39, meshtastic_TelemetrySensorType_PCT2075 = 39,
/* ADS1X15 ADC */ /* ADS1X15 ADC */
meshtastic_TelemetrySensorType_ADS1X15 = 40 meshtastic_TelemetrySensorType_ADS1X15 = 40,
/* ADS1X15 ADC_ALT */
meshtastic_TelemetrySensorType_ADS1X15_ALT = 41,
/* Sensirion SFA30 Formaldehyde sensor */
meshtastic_TelemetrySensorType_SFA30 = 42
} meshtastic_TelemetrySensorType; } meshtastic_TelemetrySensorType;
/* Struct definitions */ /* Struct definitions */
@ -287,6 +291,15 @@ typedef struct _meshtastic_AirQualityMetrics {
/* CO2 sensor relative humidity in % */ /* CO2 sensor relative humidity in % */
bool has_co2_humidity; bool has_co2_humidity;
float co2_humidity; float co2_humidity;
/* Formaldehyde sensor formaldehyde concentration in ppb */
bool has_form_formaldehyde;
float form_formaldehyde;
/* Formaldehyde sensor relative humidity in %RH */
bool has_form_humidity;
float form_humidity;
/* Formaldehyde sensor temperature in degrees Celsius */
bool has_form_temperature;
float form_temperature;
} meshtastic_AirQualityMetrics; } meshtastic_AirQualityMetrics;
/* Local device mesh statistics */ /* Local device mesh statistics */
@ -398,8 +411,8 @@ extern "C" {
/* Helper constants for enums */ /* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_ADS1X15 #define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SFA30
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_ADS1X15+1)) #define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SFA30+1))
@ -415,7 +428,7 @@ extern "C" {
#define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0} #define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0}
#define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""} #define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
@ -424,7 +437,7 @@ extern "C" {
#define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0} #define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0}
#define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""} #define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
@ -490,6 +503,9 @@ extern "C" {
#define meshtastic_AirQualityMetrics_co2_tag 13 #define meshtastic_AirQualityMetrics_co2_tag 13
#define meshtastic_AirQualityMetrics_co2_temperature_tag 14 #define meshtastic_AirQualityMetrics_co2_temperature_tag 14
#define meshtastic_AirQualityMetrics_co2_humidity_tag 15 #define meshtastic_AirQualityMetrics_co2_humidity_tag 15
#define meshtastic_AirQualityMetrics_form_formaldehyde_tag 16
#define meshtastic_AirQualityMetrics_form_humidity_tag 17
#define meshtastic_AirQualityMetrics_form_temperature_tag 18
#define meshtastic_LocalStats_uptime_seconds_tag 1 #define meshtastic_LocalStats_uptime_seconds_tag 1
#define meshtastic_LocalStats_channel_utilization_tag 2 #define meshtastic_LocalStats_channel_utilization_tag 2
#define meshtastic_LocalStats_air_util_tx_tag 3 #define meshtastic_LocalStats_air_util_tx_tag 3
@ -597,7 +613,10 @@ X(a, STATIC, OPTIONAL, UINT32, particles_50um, 11) \
X(a, STATIC, OPTIONAL, UINT32, particles_100um, 12) \ X(a, STATIC, OPTIONAL, UINT32, particles_100um, 12) \
X(a, STATIC, OPTIONAL, UINT32, co2, 13) \ X(a, STATIC, OPTIONAL, UINT32, co2, 13) \
X(a, STATIC, OPTIONAL, FLOAT, co2_temperature, 14) \ X(a, STATIC, OPTIONAL, FLOAT, co2_temperature, 14) \
X(a, STATIC, OPTIONAL, FLOAT, co2_humidity, 15) X(a, STATIC, OPTIONAL, FLOAT, co2_humidity, 15) \
X(a, STATIC, OPTIONAL, FLOAT, form_formaldehyde, 16) \
X(a, STATIC, OPTIONAL, FLOAT, form_humidity, 17) \
X(a, STATIC, OPTIONAL, FLOAT, form_temperature, 18)
#define meshtastic_AirQualityMetrics_CALLBACK NULL #define meshtastic_AirQualityMetrics_CALLBACK NULL
#define meshtastic_AirQualityMetrics_DEFAULT NULL #define meshtastic_AirQualityMetrics_DEFAULT NULL
@ -686,7 +705,7 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size
#define meshtastic_AirQualityMetrics_size 88 #define meshtastic_AirQualityMetrics_size 106
#define meshtastic_DeviceMetrics_size 27 #define meshtastic_DeviceMetrics_size 27
#define meshtastic_EnvironmentMetrics_size 113 #define meshtastic_EnvironmentMetrics_size 113
#define meshtastic_HealthMetrics_size 11 #define meshtastic_HealthMetrics_size 11

View File

@ -4,8 +4,13 @@
#include "main.h" #include "main.h"
#include "mesh/Router.h" #include "mesh/Router.h"
#include <AsyncUDP.h> #if HAS_ETHERNET && defined(ARCH_NRF52)
#include "mesh/eth/ethClient.h"
#else
#include <WiFi.h> #include <WiFi.h>
#endif
#include <AsyncUDP.h>
#if HAS_ETHERNET && defined(USE_WS5500) #if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h> #include <ETHClass2.h>
@ -22,11 +27,11 @@ class UdpMulticastHandler final
void start() void start()
{ {
if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) { if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) {
#ifndef ARCH_PORTDUINO #if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
// FIXME(PORTDUINO): arduino lacks IPAddress::toString() LOG_DEBUG("UDP Listening on IP: %u.%u.%u.%u:%u", udpIpAddress[0], udpIpAddress[1], udpIpAddress[2], udpIpAddress[3],
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str()); UDP_MULTICAST_DEFAUL_PORT);
#else #else
LOG_DEBUG("UDP Listening"); LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
#endif #endif
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); }); udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
} else { } else {
@ -37,7 +42,10 @@ class UdpMulticastHandler final
void onReceive(AsyncUDPPacket packet) void onReceive(AsyncUDPPacket packet)
{ {
size_t packetLength = packet.length(); size_t packetLength = packet.length();
#ifndef ARCH_PORTDUINO #if defined(ARCH_NRF52)
IPAddress ip = packet.remoteIP();
LOG_DEBUG("UDP broadcast from: %u.%u.%u.%u, len=%u", ip[0], ip[1], ip[2], ip[3], packetLength);
#elif !defined(ARCH_PORTDUINO)
// FIXME(PORTDUINO): arduino lacks IPAddress::toString() // FIXME(PORTDUINO): arduino lacks IPAddress::toString()
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength); LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
#endif #endif
@ -61,7 +69,11 @@ class UdpMulticastHandler final
if (!mp || !udp) { if (!mp || !udp) {
return false; return false;
} }
#ifndef ARCH_PORTDUINO #if defined(ARCH_NRF52)
if (!isEthernetAvailable()) {
return false;
}
#elif !defined(ARCH_PORTDUINO)
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED) {
return false; return false;
} }

View File

@ -1447,7 +1447,7 @@ void CannedMessageModule::drawEmotePickerScreen(OLEDDisplay *display, OLEDDispla
int headerY = y; int headerY = y;
int listTop = headerY + headerFontHeight + headerMargin; int listTop = headerY + headerFontHeight + headerMargin;
int visibleRows = (display->getHeight() - listTop - 2) / rowHeight; int _visibleRows = (display->getHeight() - listTop - 2) / rowHeight;
int numEmotes = graphics::numEmotes; int numEmotes = graphics::numEmotes;
// Clamp highlight index // Clamp highlight index
@ -1457,11 +1457,11 @@ void CannedMessageModule::drawEmotePickerScreen(OLEDDisplay *display, OLEDDispla
emotePickerIndex = numEmotes - 1; emotePickerIndex = numEmotes - 1;
// Determine which emote is at the top // Determine which emote is at the top
int topIndex = emotePickerIndex - visibleRows / 2; int topIndex = emotePickerIndex - _visibleRows / 2;
if (topIndex < 0) if (topIndex < 0)
topIndex = 0; topIndex = 0;
if (topIndex > numEmotes - visibleRows) if (topIndex > numEmotes - _visibleRows)
topIndex = std::max(0, numEmotes - visibleRows); topIndex = std::max(0, numEmotes - _visibleRows);
// Draw header/title // Draw header/title
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
@ -1709,7 +1709,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
} else { } else {
// Text: split by words and wrap inside word if needed // Text: split by words and wrap inside word if needed
String text = token.second; String text = token.second;
uint16_t pos = 0; pos = 0;
while (pos < text.length()) { while (pos < text.length()) {
// Find next space (or end) // Find next space (or end)
int spacePos = text.indexOf(' ', pos); int spacePos = text.indexOf(' ', pos);
@ -1753,7 +1753,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
int yLine = inputY; int yLine = inputY;
for (auto &line : lines) { for (auto &line : lines) {
int nextX = x; int nextX = x;
for (auto &token : line) { for (const auto &token : line) {
if (token.first) { if (token.first) {
const graphics::Emote *emote = nullptr; const graphics::Emote *emote = nullptr;
for (int j = 0; j < graphics::numEmotes; j++) { for (int j = 0; j < graphics::numEmotes; j++) {
@ -1789,19 +1789,20 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
int topMsg; int topMsg;
std::vector<int> rowHeights; std::vector<int> rowHeights;
int visibleRows; int _visibleRows;
// Draw header (To: ...) // Draw header (To: ...)
drawHeader(display, x, y, buffer); drawHeader(display, x, y, buffer);
// Shift message list upward by 3 pixels to reduce spacing between header and first message // Shift message list upward by 3 pixels to reduce spacing between header and first message
const int listYOffset = y + FONT_HEIGHT_SMALL - 3; const int listYOffset = y + FONT_HEIGHT_SMALL - 3;
visibleRows = (display->getHeight() - listYOffset) / baseRowSpacing; _visibleRows = (display->getHeight() - listYOffset) / baseRowSpacing;
// Figure out which messages are visible and their needed heights // Figure out which messages are visible and their needed heights
topMsg = topMsg = (messagesCount > _visibleRows && currentMessageIndex >= _visibleRows - 1)
(messagesCount > visibleRows && currentMessageIndex >= visibleRows - 1) ? currentMessageIndex - visibleRows + 2 : 0; ? currentMessageIndex - _visibleRows + 2
int countRows = std::min(messagesCount, visibleRows); : 0;
int countRows = std::min(messagesCount, _visibleRows);
// --- Build per-row max height based on all emotes in line --- // --- Build per-row max height based on all emotes in line ---
for (int i = 0; i < countRows; i++) { for (int i = 0; i < countRows; i++) {
@ -1828,7 +1829,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
int lineY = yCursor; int lineY = yCursor;
const char *msg = getMessageByIndex(msgIdx); const char *msg = getMessageByIndex(msgIdx);
int rowHeight = rowHeights[vis]; int rowHeight = rowHeights[vis];
bool highlight = (msgIdx == currentMessageIndex); bool _highlight = (msgIdx == currentMessageIndex);
// --- Multi-emote tokenization --- // --- Multi-emote tokenization ---
std::vector<std::pair<bool, String>> tokens; // (isEmote, token) std::vector<std::pair<bool, String>> tokens; // (isEmote, token)
@ -1881,20 +1882,20 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
int textYOffset = (rowHeight - FONT_HEIGHT_SMALL) / 2; int textYOffset = (rowHeight - FONT_HEIGHT_SMALL) / 2;
#ifdef USE_EINK #ifdef USE_EINK
int nextX = x + (highlight ? 12 : 0); int nextX = x + (_highlight ? 12 : 0);
if (highlight) if (_highlight)
display->drawString(x + 0, lineY + textYOffset, ">"); display->drawString(x + 0, lineY + textYOffset, ">");
#else #else
int scrollPadding = 8; int scrollPadding = 8;
if (highlight) { if (_highlight) {
display->fillRect(x + 0, lineY, display->getWidth() - scrollPadding, rowHeight); display->fillRect(x + 0, lineY, display->getWidth() - scrollPadding, rowHeight);
display->setColor(BLACK); display->setColor(BLACK);
} }
int nextX = x + (highlight ? 2 : 0); int nextX = x + (_highlight ? 2 : 0);
#endif #endif
// Draw all tokens left to right // Draw all tokens left to right
for (auto &token : tokens) { for (const auto &token : tokens) {
if (token.first) { if (token.first) {
// Emote // Emote
const graphics::Emote *emote = nullptr; const graphics::Emote *emote = nullptr;
@ -1916,7 +1917,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
} }
} }
#ifndef USE_EINK #ifndef USE_EINK
if (highlight) if (_highlight)
display->setColor(WHITE); display->setColor(WHITE);
#endif #endif
@ -1924,11 +1925,11 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
} }
// Scrollbar // Scrollbar
if (messagesCount > visibleRows) { if (messagesCount > _visibleRows) {
int scrollHeight = display->getHeight() - listYOffset; int scrollHeight = display->getHeight() - listYOffset;
int scrollTrackX = display->getWidth() - 6; int scrollTrackX = display->getWidth() - 6;
display->drawRect(scrollTrackX, listYOffset, 4, scrollHeight); display->drawRect(scrollTrackX, listYOffset, 4, scrollHeight);
int barHeight = (scrollHeight * visibleRows) / messagesCount; int barHeight = (scrollHeight * _visibleRows) / messagesCount;
int scrollPos = listYOffset + (scrollHeight * topMsg) / messagesCount; int scrollPos = listYOffset + (scrollHeight * topMsg) / messagesCount;
display->fillRect(scrollTrackX, scrollPos, 4, barHeight); display->fillRect(scrollTrackX, scrollPos, 4, barHeight);
} }

View File

@ -107,11 +107,7 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
return true; return true;
// Power control // Power control
case INPUT_BROKER_SHUTDOWN: case INPUT_BROKER_SHUTDOWN:
LOG_ERROR("Shutting Down"); shutdownAtMsec = millis();
IF_SCREEN(screen->showSimpleBanner("Shutting Down..."));
nodeDB->saveToDisk();
shutdownAtMsec = millis() + DEFAULT_SHUTDOWN_SECONDS * 1000;
// runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
return true; return true;
default: default:

View File

@ -0,0 +1,73 @@
#include "AsyncUDP.h"
#if HAS_ETHERNET
AsyncUDP::AsyncUDP() : OSThread("AsyncUDP"), localPort(0) {}
bool AsyncUDP::listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl)
{
if (!isMulticast(multicastIP))
return false;
localPort = port;
udp.beginMulticast(multicastIP, port);
return true;
}
size_t AsyncUDP::write(uint8_t b)
{
return udp.write(&b, 1);
}
size_t AsyncUDP::write(const uint8_t *data, size_t len)
{
return udp.write(data, len);
}
void AsyncUDP::onPacket(const std::function<void(AsyncUDPPacket)> &callback)
{
_onPacket = callback;
}
bool AsyncUDP::writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port)
{
if (!udp.beginPacket(ip, port))
return false;
udp.write(data, len);
return udp.endPacket();
}
// AsyncUDPPacket
AsyncUDPPacket::AsyncUDPPacket(EthernetUDP &source) : _udp(source), _remoteIP(source.remoteIP()), _remotePort(source.remotePort())
{
if (_udp.available() > 0) {
_readLength = _udp.read(_buffer, sizeof(_buffer));
} else {
_readLength = 0;
}
}
IPAddress AsyncUDPPacket::remoteIP()
{
return _remoteIP;
}
uint16_t AsyncUDPPacket::length()
{
return _readLength;
}
const uint8_t *AsyncUDPPacket::data()
{
return _buffer;
}
int32_t AsyncUDP::runOnce()
{
if (_onPacket && udp.parsePacket() > 0) {
AsyncUDPPacket packet(udp);
_onPacket(packet);
}
return 5; // check every 5ms
}
#endif // HAS_ETHERNET

View File

@ -0,0 +1,63 @@
#ifndef ASYNC_UDP_H
#define ASYNC_UDP_H
#include "configuration.h"
#if HAS_ETHERNET
#include "concurrency/OSThread.h"
#include <IPAddress.h>
#include <Print.h>
#include <RAK13800_W5100S.h>
#include <cstdint>
#include <functional>
class AsyncUDPPacket;
class AsyncUDP : public Print, private concurrency::OSThread
{
public:
AsyncUDP();
explicit operator bool() const { return localPort != 0; }
bool listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl = 64);
bool writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port);
size_t write(uint8_t b) override;
size_t write(const uint8_t *data, size_t len) override;
void onPacket(const std::function<void(AsyncUDPPacket)> &callback);
private:
EthernetUDP udp;
uint16_t localPort;
std::function<void(AsyncUDPPacket)> _onPacket;
virtual int32_t runOnce() override;
};
class AsyncUDPPacket
{
public:
AsyncUDPPacket(EthernetUDP &source);
IPAddress remoteIP();
uint16_t length();
const uint8_t *data();
private:
EthernetUDP &_udp;
IPAddress _remoteIP;
uint16_t _remotePort;
size_t _readLength = 0;
static constexpr size_t BUF_SIZE = 512;
uint8_t _buffer[BUF_SIZE];
};
inline bool isMulticast(const IPAddress &ip)
{
return (ip[0] & 0xF0) == 0xE0;
}
#endif // HAS_ETHERNET
#endif // ASYNC_UDP_H

View File

@ -40,21 +40,8 @@ void powerCommandsCheck()
#endif #endif
} }
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
if (shutdownAtMsec && screen) {
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
}
#endif
if (shutdownAtMsec && millis() > shutdownAtMsec) { if (shutdownAtMsec && millis() > shutdownAtMsec) {
LOG_INFO("Shut down from admin command"); shutdownAtMsec = 0;
#if defined(ARCH_NRF52) || defined(ARCH_ESP32) || defined(ARCH_RP2040)
playShutdownMelody();
power->shutdown(); power->shutdown();
#elif defined(ARCH_PORTDUINO)
exit(EXIT_SUCCESS);
#else
LOG_WARN("FIXME implement shutdown for this platform");
#endif
} }
} }

View File

@ -1,47 +1,3 @@
; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module
[env:meshtastic-diy-v1]
extends = esp32_base
board = esp32doit-devkit-v1
board_check = true
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-D EBYTE_E22
-I variants/diy/v1
; Meshtastic DIY v1.1 new schematic based on ESP32-WROOM-32 & SX1262/SX1268 modules
[env:meshtastic-diy-v1_1]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-D EBYTE_E22
-I variants/diy/v1_1
; Port to Disaster Radio's ESP32-v3 Dev Board
[env:meshtastic-dr-dev]
extends = esp32_base
board = esp32doit-devkit-v1
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 532480
build_flags =
${esp32_base.build_flags}
-D DR_DEV
-D EBYTE_E22
-I variants/diy/dr-dev
; Hydra - Meshtastic DIY v1 hardware with some specific changes
[env:hydra]
extends = esp32_base
board = esp32doit-devkit-v1
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-I variants/diy/hydra
; Promicro + E22(0)-xxxMM / RA-01SH modules board variant - DIY - without TCXO ; Promicro + E22(0)-xxxMM / RA-01SH modules board variant - DIY - without TCXO
[env:nrf52_promicro_diy_xtal] [env:nrf52_promicro_diy_xtal]
extends = nrf52840_base extends = nrf52840_base
@ -122,35 +78,3 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/diy/seeed-xiao-n
lib_deps = lib_deps =
${nrf52840_base.lib_deps} ${nrf52840_base.lib_deps}
debug_tool = jlink debug_tool = jlink
; NanoVHF T-Energy-S3 + E22(0)-xxxM - DIY
[env:t-energy-s3_e22]
extends = esp32s3_base
board = esp32-s3-devkitc-1
board_build.partitions = default_16MB.csv
board_level = extra
board_upload.flash_size = 16MB ;Specify the FLASH capacity as 16MB
board_build.arduino.memory_type = qio_opi ;Enable internal PSRAM
build_unflags =
${esp32s3_base.build_unflags}
-D ARDUINO_USB_MODE=1
build_flags =
${esp32s3_base.build_flags}
-D EBYTE_ESP32_S3
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=0
-D ARDUINO_USB_CDC_ON_BOOT=1
-I variants/diy/t-energy-s3_e22
; ESP32 C3 Super Mini Development Board
; https://www.espboards.dev/esp32/esp32-c3-super-mini/
[env:esp32c3_super_mini]
extends = esp32c3_base
board = esp32-c3-devkitm-1
build_flags =
${esp32_base.build_flags}
-D PRIVATE_HW
-I variants/diy/esp32c3_super_mini
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
board_level = extra

View File

@ -8,11 +8,11 @@ build_flags =
-D VTABLES_IN_FLASH=1 -D VTABLES_IN_FLASH=1
-D CONFIG_DISABLE_HAL_LOCKS=1 -D CONFIG_DISABLE_HAL_LOCKS=1
-O2 -O2
-I variants/betafpv_2400_tx_micro -I variants/esp32/betafpv_2400_tx_micro
board_build.f_cpu = 240000000L board_build.f_cpu = 240000000L
upload_protocol = esptool upload_protocol = esptool
;upload_port = /dev/ttyUSB0 ;upload_port = /dev/ttyUSB0
upload_speed = 460800 upload_speed = 460800
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}
adafruit/Adafruit NeoPixel @ ^1.12.0 adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@ -8,10 +8,10 @@ build_flags =
-D VTABLES_IN_FLASH=1 -D VTABLES_IN_FLASH=1
-D CONFIG_DISABLE_HAL_LOCKS=1 -D CONFIG_DISABLE_HAL_LOCKS=1
-O2 -O2
-I variants/betafpv_900_tx_nano -I variants/esp32/betafpv_900_tx_nano
board_build.f_cpu = 240000000L board_build.f_cpu = 240000000L
upload_protocol = esptool upload_protocol = esptool
;upload_port = /dev/ttyUSB0 ;upload_port = /dev/ttyUSB0
upload_speed = 460800 upload_speed = 460800
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}

View File

@ -5,7 +5,7 @@ board = esp32doit-devkit-v1
build_flags = build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D CHATTER_2 -D CHATTER_2
-I variants/chatter2 -I variants/esp32/chatter2
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}

View File

@ -0,0 +1,11 @@
; Port to Disaster Radio's ESP32-v3 Dev Board
[env:meshtastic-dr-dev]
extends = esp32_base
board = esp32doit-devkit-v1
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 532480
build_flags =
${esp32_base.build_flags}
-D DR_DEV
-D EBYTE_E22
-I variants/esp32/diy/dr-dev

View File

@ -0,0 +1,8 @@
; Hydra - Meshtastic DIY v1 hardware with some specific changes
[env:hydra]
extends = esp32_base
board = esp32doit-devkit-v1
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-I variants/esp32/diy/hydra

View File

@ -0,0 +1,10 @@
; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module
[env:meshtastic-diy-v1]
extends = esp32_base
board = esp32doit-devkit-v1
board_check = true
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-D EBYTE_E22
-I variants/esp32/diy/v1

View File

@ -0,0 +1,10 @@
; Meshtastic DIY v1.1 new schematic based on ESP32-WROOM-32 & SX1262/SX1268 modules
[env:meshtastic-diy-v1_1]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
build_flags =
${esp32_base.build_flags}
-D DIY_V1
-D EBYTE_E22
-I variants/esp32/diy/v1_1

View File

@ -5,7 +5,7 @@ board_level = extra
build_flags = build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D PRIVATE_HW -D PRIVATE_HW
-I variants/hackerboxes_esp32_io -I variants/esp32/hackerboxes_esp32_io
monitor_speed = 115200 monitor_speed = 115200
upload_protocol = esptool upload_protocol = esptool
;upload_port = /dev/ttyUSB0 ;upload_port = /dev/ttyUSB0

View File

@ -4,4 +4,6 @@ extends = esp32_base
board_level = extra board_level = extra
board = heltec_wifi_lora_32 board = heltec_wifi_lora_32
build_flags = build_flags =
${esp32_base.build_flags} -D HELTEC_V1 -I variants/heltec_v1 ${esp32_base.build_flags}
-D HELTEC_V1
-I variants/esp32/heltec_v1

View File

@ -4,5 +4,7 @@ board_level = extra
extends = esp32_base extends = esp32_base
board = heltec_wifi_lora_32_V2 board = heltec_wifi_lora_32_V2
build_flags = build_flags =
${esp32_base.build_flags} -D HELTEC_V2_1 -I variants/heltec_v2.1 ${esp32_base.build_flags}
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D HELTEC_V2_1
-I variants/esp32/heltec_v2.1
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.

View File

@ -4,4 +4,6 @@ board_level = extra
extends = esp32_base extends = esp32_base
board = heltec_wifi_lora_32_V2 board = heltec_wifi_lora_32_V2
build_flags = build_flags =
${esp32_base.build_flags} -D HELTEC_V2_0 -I variants/heltec_v2 ${esp32_base.build_flags}
-D HELTEC_V2_0
-I variants/esp32/heltec_v2

View File

@ -4,7 +4,7 @@ extends = esp32_base
board = heltec_wifi_lora_32 board = heltec_wifi_lora_32
build_flags = build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-I variants/heltec_wireless_bridge -I variants/esp32/heltec_wireless_bridge
-D HELTEC_WIRELESS_BRIDGE -D HELTEC_WIRELESS_BRIDGE
-D BOARD_HAS_PSRAM -D BOARD_HAS_PSRAM
-D RADIOLIB_EXCLUDE_LR11X0=1 -D RADIOLIB_EXCLUDE_LR11X0=1

View File

@ -3,5 +3,7 @@ extends = esp32_base
board = heltec_wireless_stick_lite board = heltec_wireless_stick_lite
board_level = extra board_level = extra
build_flags = build_flags =
${esp32_base.build_flags} -D PRIVATE_HW -I variants/heltec_wsl_v2.1 ${esp32_base.build_flags}
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D PRIVATE_HW
-I variants/esp32/heltec_wsl_v2.1
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.

View File

@ -5,7 +5,8 @@ monitor_filters = esp32_exception_decoder
build_src_filter = build_src_filter =
${esp32_base.build_src_filter} ${esp32_base.build_src_filter}
build_flags = build_flags =
${esp32_base.build_flags} -I variants/m5stack_core ${esp32_base.build_flags}
-I variants/esp32/m5stack_core
-DILI9341_DRIVER -DILI9341_DRIVER
-DM5STACK -DM5STACK
-DUSER_SETUP_LOADED -DUSER_SETUP_LOADED

View File

@ -5,7 +5,8 @@ board_check = true
build_src_filter = build_src_filter =
${esp32_base.build_src_filter} ${esp32_base.build_src_filter}
build_flags = build_flags =
${esp32_base.build_flags} -I variants/m5stack_coreink ${esp32_base.build_flags}
-I variants/esp32/m5stack_coreink
;-D RADIOLIB_VERBOSE ;-D RADIOLIB_VERBOSE
-Ofast -Ofast
-D__MCUXPRESSO -D__MCUXPRESSO

View File

@ -5,4 +5,6 @@ board = ttgo-t-beam
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}
build_flags = build_flags =
${esp32_base.build_flags} -D NANO_G1_EXPLORER -I variants/nano-g1-explorer ${esp32_base.build_flags}
-D NANO_G1_EXPLORER
-I variants/esp32/nano-g1-explorer

View File

@ -5,4 +5,6 @@ board = ttgo-t-beam
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}
build_flags = build_flags =
${esp32_base.build_flags} -D NANO_G1 -I variants/nano-g1 ${esp32_base.build_flags}
-D NANO_G1
-I variants/esp32/nano-g1

View File

@ -8,7 +8,7 @@ build_flags =
-DCONFIG_DISABLE_HAL_LOCKS=1 -DCONFIG_DISABLE_HAL_LOCKS=1
-DHAS_STK8XXX=1 -DHAS_STK8XXX=1
-O2 -O2
-Ivariants/radiomaster_900_bandit -I variants/esp32/radiomaster_900_bandit
board_build.f_cpu = 240000000L board_build.f_cpu = 240000000L
upload_protocol = esptool upload_protocol = esptool
lib_deps = lib_deps =

View File

@ -12,8 +12,8 @@ build_flags =
-DVTABLES_IN_FLASH=1 -DVTABLES_IN_FLASH=1
-DCONFIG_DISABLE_HAL_LOCKS=1 -DCONFIG_DISABLE_HAL_LOCKS=1
-O2 -O2
-Ivariants/radiomaster_900_bandit_nano -I variants/esp32/radiomaster_900_bandit_nano
board_build.f_cpu = 240000000L board_build.f_cpu = 240000000L
upload_protocol = esptool upload_protocol = esptool
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}

View File

@ -7,8 +7,8 @@ build_flags =
-DVTABLES_IN_FLASH=1 -DVTABLES_IN_FLASH=1
-DCONFIG_DISABLE_HAL_LOCKS=1 -DCONFIG_DISABLE_HAL_LOCKS=1
-O2 -O2
-Ivariants/radiomaster_900_bandit_nano -I variants/esp32/radiomaster_900_bandit_nano
board_build.f_cpu = 240000000L board_build.f_cpu = 240000000L
upload_protocol = esptool upload_protocol = esptool
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}

View File

@ -3,5 +3,7 @@ extends = esp32_base
board = wiscore_rak11200 board = wiscore_rak11200
board_check = true board_check = true
build_flags = build_flags =
${esp32_base.build_flags} -D RAK_11200 -I variants/rak11200 ${esp32_base.build_flags}
upload_speed = 115200 -D RAK_11200
-I variants/esp32/rak11200
upload_speed = 115200

View File

@ -5,4 +5,6 @@ board = ttgo-t-beam
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}
build_flags = build_flags =
${esp32_base.build_flags} -D STATION_G1 -I variants/station-g1 ${esp32_base.build_flags}
-D STATION_G1
-I variants/esp32/station-g1

View File

@ -6,8 +6,10 @@ board_check = true
lib_deps = lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}
build_flags = build_flags =
${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam ${esp32_base.build_flags}
-D TBEAM_V10
-I variants/esp32/tbeam
-DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. -DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely.
-DBOARD_HAS_PSRAM -DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-issue
upload_speed = 921600 upload_speed = 921600

View File

@ -4,4 +4,6 @@ board_level = extra
extends = esp32_base extends = esp32_base
board = ttgo-t-beam board = ttgo-t-beam
build_flags = build_flags =
${esp32_base.build_flags} -D TBEAM_V07 -I variants/tbeam_v07 ${esp32_base.build_flags}
-D TBEAM_V07
-I variants/esp32/tbeam_v07

View File

@ -3,5 +3,7 @@ board_level = extra
extends = esp32_base extends = esp32_base
board = ttgo-lora32-v1 board = ttgo-lora32-v1
build_flags = build_flags =
${esp32_base.build_flags} -D TLORA_V1 -I variants/tlora_v1 ${esp32_base.build_flags}
upload_speed = 115200 -D TLORA_V1
-I variants/esp32/tlora_v1
upload_speed = 115200

View File

@ -3,5 +3,5 @@ board_level = extra
extends = esp32_base extends = esp32_base
board = ttgo-lora32-v1 board = ttgo-lora32-v1
build_flags = build_flags =
${esp32_base.build_flags} -D TLORA_V1_3 -I variants/tlora_v1_3 ${esp32_base.build_flags} -D TLORA_V1_3 -I variants/esp32/tlora_v1_3
upload_speed = 115200 upload_speed = 115200

View File

@ -3,4 +3,6 @@ board_level = extra
extends = esp32_base extends = esp32_base
board = ttgo-lora32-v1 board = ttgo-lora32-v1
build_flags = build_flags =
${esp32_base.build_flags} -D TLORA_V2 -I variants/tlora_v2 ${esp32_base.build_flags}
-D TLORA_V2
-I variants/esp32/tlora_v2

View File

@ -3,6 +3,6 @@ extends = esp32_base
board = ttgo-lora32-v21 board = ttgo-lora32-v21
board_check = true board_check = true
build_flags = build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/tlora_v2_1_16 ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
upload_speed = 115200 upload_speed = 115200

View File

@ -5,7 +5,7 @@ board = ttgo-lora32-v21
build_flags = build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D TLORA_V2_1_16 -D TLORA_V2_1_16
-I variants/tlora_v2_1_16 -I variants/esp32/tlora_v2_1_16
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-D LORA_TCXO_GPIO=33 -D LORA_TCXO_GPIO=33
upload_speed = 115200 upload_speed = 115200

View File

@ -4,4 +4,6 @@ board_level = extra
board = ttgo-lora32-v21 board = ttgo-lora32-v21
build_flags = build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18 ${esp32_base.build_flags}
-D TLORA_V2_1_18
-I variants/esp32/tlora_v2_1_18

View File

@ -4,7 +4,7 @@ board = ttgo-lora32-v21
build_flags = build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D TLORA_V2_1_16 -D TLORA_V2_1_16
-I variants/tlora_v2_1_16 -I variants/esp32/tlora_v2_1_16
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-D LORA_TCXO_GPIO=12 -D LORA_TCXO_GPIO=12
-D BUTTON_PIN=0 -D BUTTON_PIN=0

Some files were not shown because too many files have changed in this diff Show More