mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-28 15:22:55 +00:00
Merge branch 'develop' of https://github.com/meshtastic/firmware into 8139-root-topic
This commit is contained in:
commit
17863e96e2
@ -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.471
|
- checkov@3.2.473
|
||||||
- renovate@41.130.1
|
- renovate@41.132.5
|
||||||
- prettier@3.6.2
|
- prettier@3.6.2
|
||||||
- trufflehog@3.90.8
|
- trufflehog@3.90.8
|
||||||
- yamllint@1.37.1
|
- yamllint@1.37.1
|
||||||
- bandit@1.8.6
|
- bandit@1.8.6
|
||||||
- trivy@0.66.0
|
- trivy@0.67.0
|
||||||
- taplo@0.10.0
|
- taplo@0.10.0
|
||||||
- ruff@0.13.1
|
- ruff@0.13.2
|
||||||
- isort@6.0.1
|
- isort@6.0.1
|
||||||
- markdownlint@0.45.0
|
- markdownlint@0.45.0
|
||||||
- oxipng@9.1.5
|
- oxipng@9.1.5
|
||||||
|
|||||||
52
boards/r1-neo.json
Normal file
52
boards/r1-neo.json
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A", "0x8029"],
|
||||||
|
["0x239A", "0x0029"],
|
||||||
|
["0x239A", "0x002A"],
|
||||||
|
["0x239A", "0x802A"]
|
||||||
|
],
|
||||||
|
"usb_product": "Muzi R1 Neo",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "r1-neo",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B6"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": ["bluetooth"],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"svd_path": "nrf52840.svd",
|
||||||
|
"openocd_target": "nrf52840-mdk-rs"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "freertos"],
|
||||||
|
"name": "WisCore RAK4631 Board",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 248832,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "https://muzi.works/",
|
||||||
|
"vendor": "Muzi Works"
|
||||||
|
}
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 394268b02ebbc7797de31b09fe72fe2a7bdbbcab
|
Subproject commit 60c3e6600a2f4e6f49e45aeb47aafd8291a0015c
|
||||||
@ -11,6 +11,11 @@
|
|||||||
#include <AudioOutputI2S.h>
|
#include <AudioOutputI2S.h>
|
||||||
#include <ESP8266SAM.h>
|
#include <ESP8266SAM.h>
|
||||||
|
|
||||||
|
#ifdef USE_XL9555
|
||||||
|
#include "ExtensionIOXL9555.hpp"
|
||||||
|
extern ExtensionIOXL9555 io;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define AUDIO_THREAD_INTERVAL_MS 100
|
#define AUDIO_THREAD_INTERVAL_MS 100
|
||||||
|
|
||||||
class AudioThread : public concurrency::OSThread
|
class AudioThread : public concurrency::OSThread
|
||||||
@ -20,6 +25,9 @@ class AudioThread : public concurrency::OSThread
|
|||||||
|
|
||||||
void beginRttl(const void *data, uint32_t len)
|
void beginRttl(const void *data, uint32_t len)
|
||||||
{
|
{
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
||||||
|
#endif
|
||||||
setCPUFast(true);
|
setCPUFast(true);
|
||||||
rtttlFile = new AudioFileSourcePROGMEM(data, len);
|
rtttlFile = new AudioFileSourcePROGMEM(data, len);
|
||||||
i2sRtttl = new AudioGeneratorRTTTL();
|
i2sRtttl = new AudioGeneratorRTTTL();
|
||||||
@ -46,6 +54,9 @@ class AudioThread : public concurrency::OSThread
|
|||||||
rtttlFile = nullptr;
|
rtttlFile = nullptr;
|
||||||
|
|
||||||
setCPUFast(false);
|
setCPUFast(false);
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
io.digitalWrite(EXPANDS_AMP_EN, LOW);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void readAloud(const char *text)
|
void readAloud(const char *text)
|
||||||
@ -56,10 +67,16 @@ class AudioThread : public concurrency::OSThread
|
|||||||
i2sRtttl = nullptr;
|
i2sRtttl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
||||||
|
#endif
|
||||||
ESP8266SAM *sam = new ESP8266SAM;
|
ESP8266SAM *sam = new ESP8266SAM;
|
||||||
sam->Say(audioOut, text);
|
sam->Say(audioOut, text);
|
||||||
delete sam;
|
delete sam;
|
||||||
setCPUFast(false);
|
setCPUFast(false);
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
io.digitalWrite(EXPANDS_AMP_EN, LOW);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@ -76,9 +76,6 @@ const char *DisplayFormatters::getDeviceRole(meshtastic_Config_DeviceConfig_Role
|
|||||||
case meshtastic_Config_DeviceConfig_Role_ROUTER_LATE:
|
case meshtastic_Config_DeviceConfig_Role_ROUTER_LATE:
|
||||||
return "Router Late";
|
return "Router Late";
|
||||||
break;
|
break;
|
||||||
case meshtastic_Config_DeviceConfig_Role_REPEATER:
|
|
||||||
return "Repeater";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -25,8 +25,8 @@ ScanI2C::FoundDevice ScanI2C::firstScreen() const
|
|||||||
|
|
||||||
ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||||
{
|
{
|
||||||
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563};
|
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563, RTC_RX8130CE};
|
||||||
return firstOfOrNONE(2, types);
|
return firstOfOrNONE(3, types);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||||
|
|||||||
@ -14,6 +14,7 @@ class ScanI2C
|
|||||||
SCREEN_ST7567,
|
SCREEN_ST7567,
|
||||||
RTC_RV3028,
|
RTC_RV3028,
|
||||||
RTC_PCF8563,
|
RTC_PCF8563,
|
||||||
|
RTC_RX8130CE,
|
||||||
CARDKB,
|
CARDKB,
|
||||||
TDECKKB,
|
TDECKKB,
|
||||||
BBQ10KB,
|
BBQ10KB,
|
||||||
|
|||||||
@ -197,6 +197,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
#ifdef PCF8563_RTC
|
#ifdef PCF8563_RTC
|
||||||
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address)
|
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address)
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RX8130CE_RTC
|
||||||
|
SCAN_SIMPLE_CASE(RX8130CE_RTC, RTC_RX8130CE, "RX8130CE", (uint8_t)addr.address)
|
||||||
|
#endif
|
||||||
|
|
||||||
case CARDKB_ADDR:
|
case CARDKB_ADDR:
|
||||||
// Do we have the RAK14006 instead?
|
// Do we have the RAK14006 instead?
|
||||||
|
|||||||
@ -1104,11 +1104,6 @@ int32_t GPS::runOnce()
|
|||||||
publishUpdate();
|
publishUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeaters have no need for GPS
|
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
return disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (whileActive()) {
|
if (whileActive()) {
|
||||||
// if we have received valid NMEA claim we are connected
|
// if we have received valid NMEA claim we are connected
|
||||||
setConnected();
|
setConnected();
|
||||||
|
|||||||
@ -109,6 +109,35 @@ RTCSetResult readFromRTC()
|
|||||||
}
|
}
|
||||||
return RTCSetResultSuccess;
|
return RTCSetResultSuccess;
|
||||||
}
|
}
|
||||||
|
#elif defined(RX8130CE_RTC)
|
||||||
|
if (rtc_found.address == RX8130CE_RTC) {
|
||||||
|
uint32_t now = millis();
|
||||||
|
ArtronShop_RX8130CE rtc(&Wire);
|
||||||
|
tm t;
|
||||||
|
if (rtc.getTime(&t)) {
|
||||||
|
tv.tv_sec = gm_mktime(&t);
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||||
|
LOG_DEBUG("Read RTC time from RX8130CE getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900,
|
||||||
|
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
|
||||||
|
#ifdef BUILD_EPOCH
|
||||||
|
if (tv.tv_sec < BUILD_EPOCH) {
|
||||||
|
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||||
|
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||||
|
lastTimeValidationWarning = millis();
|
||||||
|
}
|
||||||
|
return RTCSetResultInvalidTime;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (currentQuality == RTCQualityNone) {
|
||||||
|
timeStartMsec = now;
|
||||||
|
zeroOffsetSecs = tv.tv_sec;
|
||||||
|
currentQuality = RTCQualityDevice;
|
||||||
|
}
|
||||||
|
return RTCSetResultSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (!gettimeofday(&tv, NULL)) {
|
if (!gettimeofday(&tv, NULL)) {
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
@ -214,6 +243,17 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
|||||||
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||||
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
|
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
|
||||||
}
|
}
|
||||||
|
#elif defined(RX8130CE_RTC)
|
||||||
|
if (rtc_found.address == RX8130CE_RTC) {
|
||||||
|
ArtronShop_RX8130CE rtc(&Wire);
|
||||||
|
tm *t = gmtime(&tv->tv_sec);
|
||||||
|
if (rtc.setTime(*t)) {
|
||||||
|
LOG_DEBUG("RX8130CE setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1,
|
||||||
|
t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
|
||||||
|
} else {
|
||||||
|
LOG_WARN("Failed to set time for RX8130CE");
|
||||||
|
}
|
||||||
|
}
|
||||||
#elif defined(ARCH_ESP32)
|
#elif defined(ARCH_ESP32)
|
||||||
settimeofday(tv, NULL);
|
settimeofday(tv, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -4,6 +4,10 @@
|
|||||||
#include "sys/time.h"
|
#include "sys/time.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#ifdef RX8130CE_RTC
|
||||||
|
#include <ArtronShop_RX8130CE.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
enum RTCQuality {
|
enum RTCQuality {
|
||||||
|
|
||||||
/// We haven't had our RTC set yet
|
/// We haven't had our RTC set yet
|
||||||
|
|||||||
@ -100,7 +100,7 @@ namespace graphics
|
|||||||
#define NUM_EXTRA_FRAMES 3 // text message and debug frame
|
#define NUM_EXTRA_FRAMES 3 // text message and debug frame
|
||||||
// if defined a pixel will blink to show redraws
|
// if defined a pixel will blink to show redraws
|
||||||
// #define SHOW_REDRAWS
|
// #define SHOW_REDRAWS
|
||||||
|
#define ASCII_BELL '\x07'
|
||||||
// A text message frame + debug frame + all the node infos
|
// A text message frame + debug frame + all the node infos
|
||||||
FrameCallback *normalFrames;
|
FrameCallback *normalFrames;
|
||||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||||
@ -1458,28 +1458,36 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
|||||||
}
|
}
|
||||||
// === Prepare banner content ===
|
// === Prepare banner content ===
|
||||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from);
|
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from);
|
||||||
|
const meshtastic_Channel channel =
|
||||||
|
channels.getByIndex(packet->channel ? packet->channel : channels.getPrimaryIndex());
|
||||||
const char *longName = (node && node->has_user) ? node->user.long_name : nullptr;
|
const char *longName = (node && node->has_user) ? node->user.long_name : nullptr;
|
||||||
|
|
||||||
const char *msgRaw = reinterpret_cast<const char *>(packet->decoded.payload.bytes);
|
const char *msgRaw = reinterpret_cast<const char *>(packet->decoded.payload.bytes);
|
||||||
|
|
||||||
char banner[256];
|
char banner[256];
|
||||||
|
|
||||||
// Check for bell character in message to determine alert type
|
|
||||||
bool isAlert = false;
|
bool isAlert = false;
|
||||||
for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) {
|
|
||||||
if (msgRaw[i] == '\x07') {
|
|
||||||
isAlert = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (moduleConfig.external_notification.alert_bell || moduleConfig.external_notification.alert_bell_vibra ||
|
||||||
|
moduleConfig.external_notification.alert_bell_buzzer)
|
||||||
|
// Check for bell character to determine if this message is an alert
|
||||||
|
for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) {
|
||||||
|
if (msgRaw[i] == ASCII_BELL) {
|
||||||
|
isAlert = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlike generic messages, alerts (when enabled via the ext notif module) ignore any
|
||||||
|
// 'mute' preferences set to any specific node or channel.
|
||||||
if (isAlert) {
|
if (isAlert) {
|
||||||
if (longName && longName[0]) {
|
if (longName && longName[0]) {
|
||||||
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
||||||
} else {
|
} else {
|
||||||
strcpy(banner, "Alert Received");
|
strcpy(banner, "Alert Received");
|
||||||
}
|
}
|
||||||
} else {
|
screen->showSimpleBanner(banner, 3000);
|
||||||
|
} else if (!channel.settings.mute) {
|
||||||
if (longName && longName[0]) {
|
if (longName && longName[0]) {
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
strcpy(banner, "New Message");
|
strcpy(banner, "New Message");
|
||||||
@ -1490,20 +1498,21 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
|||||||
} else {
|
} else {
|
||||||
strcpy(banner, "New Message");
|
strcpy(banner, "New Message");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
screen->showSimpleBanner(banner, 1500);
|
screen->showSimpleBanner(banner, 1500);
|
||||||
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
||||||
(isAlert && moduleConfig.external_notification.alert_bell_buzzer) || (!isBroadcast(packet->to) && isToUs(p))) {
|
(isAlert && moduleConfig.external_notification.alert_bell_buzzer) ||
|
||||||
// Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either
|
(!isBroadcast(packet->to) && isToUs(p))) {
|
||||||
// - packet contains an alert and alert bell buzzer is enabled
|
// Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either
|
||||||
// - packet is a non-broadcast that is addressed to this node
|
// - packet contains an alert and alert bell buzzer is enabled
|
||||||
playLongBeep();
|
// - packet is a non-broadcast that is addressed to this node
|
||||||
}
|
playLongBeep();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
screen->showSimpleBanner(banner, 3000);
|
screen->showSimpleBanner(banner, 3000);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -279,7 +279,7 @@ int32_t ButtonThread::runOnce()
|
|||||||
if (!userButton.isIdle() || waitingForLongPress) {
|
if (!userButton.isIdle() || waitingForLongPress) {
|
||||||
return 50;
|
return 50;
|
||||||
}
|
}
|
||||||
return INT32_MAX;
|
return 100; // FIXME: Why can't we rely on interrupts and use INT32_MAX here?
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -3,16 +3,66 @@
|
|||||||
|
|
||||||
InputBroker *inputBroker = nullptr;
|
InputBroker *inputBroker = nullptr;
|
||||||
|
|
||||||
InputBroker::InputBroker(){};
|
InputBroker::InputBroker()
|
||||||
|
{
|
||||||
|
#ifdef HAS_FREE_RTOS
|
||||||
|
inputEventQueue = xQueueCreate(5, sizeof(InputEvent));
|
||||||
|
pollSoonQueue = xQueueCreate(5, sizeof(InputPollable *));
|
||||||
|
xTaskCreate(pollSoonWorker, "input-pollSoon", 2 * 1024, this, 10, &pollSoonTask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void InputBroker::registerSource(Observable<const InputEvent *> *source)
|
void InputBroker::registerSource(Observable<const InputEvent *> *source)
|
||||||
{
|
{
|
||||||
this->inputEventObserver.observe(source);
|
this->inputEventObserver.observe(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_FREE_RTOS
|
||||||
|
void InputBroker::requestPollSoon(InputPollable *pollable)
|
||||||
|
{
|
||||||
|
if (xPortInIsrContext() == pdTRUE) {
|
||||||
|
xQueueSendFromISR(pollSoonQueue, &pollable, NULL);
|
||||||
|
} else {
|
||||||
|
xQueueSend(pollSoonQueue, &pollable, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputBroker::queueInputEvent(const InputEvent *event)
|
||||||
|
{
|
||||||
|
if (xPortInIsrContext() == pdTRUE) {
|
||||||
|
xQueueSendFromISR(inputEventQueue, event, NULL);
|
||||||
|
} else {
|
||||||
|
xQueueSend(inputEventQueue, event, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputBroker::processInputEventQueue()
|
||||||
|
{
|
||||||
|
InputEvent event;
|
||||||
|
while (xQueueReceive(inputEventQueue, &event, 0)) {
|
||||||
|
handleInputEvent(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int InputBroker::handleInputEvent(const InputEvent *event)
|
int InputBroker::handleInputEvent(const InputEvent *event)
|
||||||
{
|
{
|
||||||
powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release
|
powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release
|
||||||
this->notifyObservers(event);
|
this->notifyObservers(event);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_FREE_RTOS
|
||||||
|
void InputBroker::pollSoonWorker(void *p)
|
||||||
|
{
|
||||||
|
InputBroker *instance = (InputBroker *)p;
|
||||||
|
while (true) {
|
||||||
|
InputPollable *pollable = NULL;
|
||||||
|
xQueueReceive(instance->pollSoonQueue, &pollable, portMAX_DELAY);
|
||||||
|
if (pollable) {
|
||||||
|
pollable->pollOnce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
|
#include "freertosinc.h"
|
||||||
|
|
||||||
enum input_broker_event {
|
enum input_broker_event {
|
||||||
INPUT_BROKER_NONE = 0,
|
INPUT_BROKER_NONE = 0,
|
||||||
@ -41,6 +43,13 @@ typedef struct _InputEvent {
|
|||||||
uint16_t touchX;
|
uint16_t touchX;
|
||||||
uint16_t touchY;
|
uint16_t touchY;
|
||||||
} InputEvent;
|
} InputEvent;
|
||||||
|
|
||||||
|
class InputPollable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void pollOnce() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class InputBroker : public Observable<const InputEvent *>
|
class InputBroker : public Observable<const InputEvent *>
|
||||||
{
|
{
|
||||||
CallbackObserver<InputBroker, const InputEvent *> inputEventObserver =
|
CallbackObserver<InputBroker, const InputEvent *> inputEventObserver =
|
||||||
@ -50,9 +59,22 @@ class InputBroker : public Observable<const InputEvent *>
|
|||||||
InputBroker();
|
InputBroker();
|
||||||
void registerSource(Observable<const InputEvent *> *source);
|
void registerSource(Observable<const InputEvent *> *source);
|
||||||
void injectInputEvent(const InputEvent *event) { handleInputEvent(event); }
|
void injectInputEvent(const InputEvent *event) { handleInputEvent(event); }
|
||||||
|
#ifdef HAS_FREE_RTOS
|
||||||
|
void requestPollSoon(InputPollable *pollable);
|
||||||
|
void queueInputEvent(const InputEvent *event);
|
||||||
|
void processInputEventQueue();
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int handleInputEvent(const InputEvent *event);
|
int handleInputEvent(const InputEvent *event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef HAS_FREE_RTOS
|
||||||
|
QueueHandle_t inputEventQueue;
|
||||||
|
QueueHandle_t pollSoonQueue;
|
||||||
|
TaskHandle_t pollSoonTask;
|
||||||
|
static void pollSoonWorker(void *p);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern InputBroker *inputBroker;
|
extern InputBroker *inputBroker;
|
||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
RotaryEncoderImpl *rotaryEncoderImpl;
|
RotaryEncoderImpl *rotaryEncoderImpl;
|
||||||
|
|
||||||
RotaryEncoderImpl::RotaryEncoderImpl() : concurrency::OSThread(ORIGIN_NAME), originName(ORIGIN_NAME)
|
RotaryEncoderImpl::RotaryEncoderImpl()
|
||||||
{
|
{
|
||||||
rotary = nullptr;
|
rotary = nullptr;
|
||||||
}
|
}
|
||||||
@ -18,7 +18,6 @@ bool RotaryEncoderImpl::init()
|
|||||||
if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 ||
|
if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 ||
|
||||||
moduleConfig.canned_message.inputbroker_pin_b == 0) {
|
moduleConfig.canned_message.inputbroker_pin_b == 0) {
|
||||||
// Input device is disabled.
|
// Input device is disabled.
|
||||||
disable();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +29,11 @@ bool RotaryEncoderImpl::init()
|
|||||||
moduleConfig.canned_message.inputbroker_pin_press);
|
moduleConfig.canned_message.inputbroker_pin_press);
|
||||||
rotary->resetButton();
|
rotary->resetButton();
|
||||||
|
|
||||||
inputBroker->registerSource(this);
|
interruptInstance = this;
|
||||||
|
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
|
||||||
|
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
|
||||||
|
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
|
||||||
|
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
|
||||||
|
|
||||||
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
||||||
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
||||||
@ -38,36 +41,36 @@ bool RotaryEncoderImpl::init()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RotaryEncoderImpl::runOnce()
|
void RotaryEncoderImpl::pollOnce()
|
||||||
{
|
{
|
||||||
InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0};
|
InputEvent e{ORIGIN_NAME, INPUT_BROKER_NONE, 0, 0, 0};
|
||||||
|
|
||||||
static uint32_t lastPressed = millis();
|
static uint32_t lastPressed = millis();
|
||||||
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
||||||
if (lastPressed + 200 < millis()) {
|
if (lastPressed + 200 < millis()) {
|
||||||
LOG_DEBUG("Rotary event Press");
|
LOG_DEBUG("Rotary event Press");
|
||||||
lastPressed = millis();
|
lastPressed = millis();
|
||||||
e.inputEvent = this->eventPressed;
|
e.inputEvent = this->eventPressed;
|
||||||
}
|
inputBroker->queueInputEvent(&e);
|
||||||
} else {
|
|
||||||
switch (rotary->process()) {
|
|
||||||
case RotaryEncoder::DIRECTION_CW:
|
|
||||||
LOG_DEBUG("Rotary event CW");
|
|
||||||
e.inputEvent = this->eventCw;
|
|
||||||
break;
|
|
||||||
case RotaryEncoder::DIRECTION_CCW:
|
|
||||||
LOG_DEBUG("Rotary event CCW");
|
|
||||||
e.inputEvent = this->eventCcw;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.inputEvent != INPUT_BROKER_NONE) {
|
switch (rotary->process()) {
|
||||||
this->notifyObservers(&e);
|
case RotaryEncoder::DIRECTION_CW:
|
||||||
|
LOG_DEBUG("Rotary event CW");
|
||||||
|
e.inputEvent = this->eventCw;
|
||||||
|
inputBroker->queueInputEvent(&e);
|
||||||
|
break;
|
||||||
|
case RotaryEncoder::DIRECTION_CCW:
|
||||||
|
LOG_DEBUG("Rotary event CCW");
|
||||||
|
e.inputEvent = this->eventCcw;
|
||||||
|
inputBroker->queueInputEvent(&e);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// This is a non-interrupt version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library)
|
// This is a version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library)
|
||||||
|
|
||||||
#include "InputBroker.h"
|
#include "InputBroker.h"
|
||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
@ -8,21 +8,21 @@
|
|||||||
|
|
||||||
class RotaryEncoder;
|
class RotaryEncoder;
|
||||||
|
|
||||||
class RotaryEncoderImpl : public Observable<const InputEvent *>, public concurrency::OSThread
|
class RotaryEncoderImpl : public InputPollable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RotaryEncoderImpl();
|
RotaryEncoderImpl();
|
||||||
bool init(void);
|
bool init(void);
|
||||||
|
virtual void pollOnce() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int32_t runOnce() override;
|
static RotaryEncoderImpl *interruptInstance;
|
||||||
|
|
||||||
input_broker_event eventCw = INPUT_BROKER_NONE;
|
input_broker_event eventCw = INPUT_BROKER_NONE;
|
||||||
input_broker_event eventCcw = INPUT_BROKER_NONE;
|
input_broker_event eventCcw = INPUT_BROKER_NONE;
|
||||||
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
||||||
|
|
||||||
RotaryEncoder *rotary;
|
RotaryEncoder *rotary;
|
||||||
const char *originName;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
||||||
|
|||||||
23
src/main.cpp
23
src/main.cpp
@ -297,6 +297,12 @@ void printInfo()
|
|||||||
#ifndef PIO_UNIT_TESTING
|
#ifndef PIO_UNIT_TESTING
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
#if defined(R1_NEO)
|
||||||
|
pinMode(DCDC_EN_HOLD, OUTPUT);
|
||||||
|
digitalWrite(DCDC_EN_HOLD, HIGH);
|
||||||
|
pinMode(NRF_ON, OUTPUT);
|
||||||
|
digitalWrite(NRF_ON, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(PIN_POWER_EN)
|
#if defined(PIN_POWER_EN)
|
||||||
pinMode(PIN_POWER_EN, OUTPUT);
|
pinMode(PIN_POWER_EN, OUTPUT);
|
||||||
@ -375,7 +381,7 @@ void setup()
|
|||||||
io.pinMode(EXPANDS_DRV_EN, OUTPUT);
|
io.pinMode(EXPANDS_DRV_EN, OUTPUT);
|
||||||
io.digitalWrite(EXPANDS_DRV_EN, HIGH);
|
io.digitalWrite(EXPANDS_DRV_EN, HIGH);
|
||||||
io.pinMode(EXPANDS_AMP_EN, OUTPUT);
|
io.pinMode(EXPANDS_AMP_EN, OUTPUT);
|
||||||
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
io.digitalWrite(EXPANDS_AMP_EN, LOW);
|
||||||
io.pinMode(EXPANDS_LORA_EN, OUTPUT);
|
io.pinMode(EXPANDS_LORA_EN, OUTPUT);
|
||||||
io.digitalWrite(EXPANDS_LORA_EN, HIGH);
|
io.digitalWrite(EXPANDS_LORA_EN, HIGH);
|
||||||
io.pinMode(EXPANDS_GPS_EN, OUTPUT);
|
io.pinMode(EXPANDS_GPS_EN, OUTPUT);
|
||||||
@ -793,14 +799,7 @@ void setup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If we're taking on the repeater role, use NextHopRouter and turn off 3V3_S rail because peripherals are not needed
|
router = new ReliableRouter();
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
router = new NextHopRouter();
|
|
||||||
#ifdef PIN_3V3_EN
|
|
||||||
digitalWrite(PIN_3V3_EN, LOW);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
router = new ReliableRouter();
|
|
||||||
|
|
||||||
// only play start melody when role is not tracker or sensor
|
// only play start melody when role is not tracker or sensor
|
||||||
if (config.power.is_power_saving == true &&
|
if (config.power.is_power_saving == true &&
|
||||||
@ -926,8 +925,7 @@ void setup()
|
|||||||
if (sensor_detected == false) {
|
if (sensor_detected == false) {
|
||||||
#endif
|
#endif
|
||||||
if (HAS_GPS) {
|
if (HAS_GPS) {
|
||||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
|
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
|
||||||
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
|
|
||||||
gps = GPS::createGps();
|
gps = GPS::createGps();
|
||||||
if (gps) {
|
if (gps) {
|
||||||
gpsStatus->observe(&gps->newStatus);
|
gpsStatus->observe(&gps->newStatus);
|
||||||
@ -1602,6 +1600,9 @@ void loop()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
service->loop();
|
service->loop();
|
||||||
|
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && defined(HAS_FREE_RTOS)
|
||||||
|
inputBroker->processInputEventQueue();
|
||||||
|
#endif
|
||||||
#if defined(LGFX_SDL)
|
#if defined(LGFX_SDL)
|
||||||
if (screen) {
|
if (screen) {
|
||||||
auto dispdev = screen->getDisplayDevice();
|
auto dispdev = screen->getDisplayDevice();
|
||||||
|
|||||||
@ -85,9 +85,8 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
|||||||
bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p)
|
bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p)
|
||||||
{
|
{
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER ||
|
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) {
|
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) {
|
||||||
// ROUTER, REPEATER, ROUTER_LATE should never cancel relaying a packet (i.e. we should always rebroadcast),
|
// ROUTER, ROUTER_LATE should never cancel relaying a packet (i.e. we should always rebroadcast),
|
||||||
// even if we've heard another station rebroadcast it already.
|
// even if we've heard another station rebroadcast it already.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -106,7 +105,7 @@ bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p)
|
|||||||
void FloodingRouter::perhapsCancelDupe(const meshtastic_MeshPacket *p)
|
void FloodingRouter::perhapsCancelDupe(const meshtastic_MeshPacket *p)
|
||||||
{
|
{
|
||||||
if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA && roleAllowsCancelingDupe(p)) {
|
if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA && roleAllowsCancelingDupe(p)) {
|
||||||
// cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
|
// cancel rebroadcast of this message *if* there was already one, unless we're a router!
|
||||||
// But only LoRa packets should be able to trigger this.
|
// But only LoRa packets should be able to trigger this.
|
||||||
if (Router::cancelSending(p->from, p->id))
|
if (Router::cancelSending(p->from, p->id))
|
||||||
txRelayCanceled++;
|
txRelayCanceled++;
|
||||||
|
|||||||
@ -59,7 +59,7 @@ class FloodingRouter : public Router
|
|||||||
*/
|
*/
|
||||||
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
|
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
|
||||||
|
|
||||||
// Return false for roles like ROUTER or REPEATER which should always rebroadcast even when we've heard another rebroadcast of
|
// Return false for roles like ROUTER which should always rebroadcast even when we've heard another rebroadcast of
|
||||||
// the same packet
|
// the same packet
|
||||||
bool roleAllowsCancelingDupe(const meshtastic_MeshPacket *p);
|
bool roleAllowsCancelingDupe(const meshtastic_MeshPacket *p);
|
||||||
|
|
||||||
|
|||||||
@ -85,12 +85,11 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
|
|||||||
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
|
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
|
||||||
|
|
||||||
nodeDB->updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
nodeDB->updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||||
bool isPreferredRebroadcaster =
|
bool isPreferredRebroadcaster = config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER;
|
||||||
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER, meshtastic_Config_DeviceConfig_Role_REPEATER);
|
|
||||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
|
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
|
||||||
mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) {
|
mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) {
|
||||||
LOG_DEBUG("Received telemetry response. Skip sending our NodeInfo"); // because this potentially a Repeater which will
|
LOG_DEBUG("Received telemetry response. Skip sending our NodeInfo");
|
||||||
// ignore our request for its NodeInfo
|
// ignore our request for its NodeInfo
|
||||||
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
|
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
|
||||||
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
|
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
|
||||||
if (airTime->isTxAllowedChannelUtil(true)) {
|
if (airTime->isTxAllowedChannelUtil(true)) {
|
||||||
|
|||||||
@ -174,7 +174,6 @@ bool NextHopRouter::perhapsRelay(const meshtastic_MeshPacket *p)
|
|||||||
*/
|
*/
|
||||||
uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node)
|
uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node)
|
||||||
{
|
{
|
||||||
// When we're a repeater router->sniffReceived will call NextHopRouter directly without checking for broadcast
|
|
||||||
if (isBroadcast(to))
|
if (isBroadcast(to))
|
||||||
return NO_NEXT_HOP_PREFERENCE;
|
return NO_NEXT_HOP_PREFERENCE;
|
||||||
|
|
||||||
@ -212,7 +211,7 @@ bool NextHopRouter::roleAllowsCancelingFromTxQueue(const meshtastic_MeshPacket *
|
|||||||
{
|
{
|
||||||
// Return true if we're allowed to cancel a packet in the txQueue (so we may never transmit it even once)
|
// Return true if we're allowed to cancel a packet in the txQueue (so we may never transmit it even once)
|
||||||
|
|
||||||
// Return false for roles like ROUTER, REPEATER, ROUTER_LATE which should always transmit the packet at least once.
|
// Return false for roles like ROUTER, ROUTER_LATE which should always transmit the packet at least once.
|
||||||
|
|
||||||
return roleAllowsCancelingDupe(p); // same logic as FloodingRouter::roleAllowsCancelingDupe
|
return roleAllowsCancelingDupe(p); // same logic as FloodingRouter::roleAllowsCancelingDupe
|
||||||
}
|
}
|
||||||
@ -225,7 +224,7 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key)
|
|||||||
/* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue
|
/* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue
|
||||||
to avoid canceling a transmission if it was ACKed super fast via MQTT */
|
to avoid canceling a transmission if it was ACKed super fast via MQTT */
|
||||||
if (old->numRetransmissions < NUM_RELIABLE_RETX - 1) {
|
if (old->numRetransmissions < NUM_RELIABLE_RETX - 1) {
|
||||||
// We only cancel it if we are the original sender or if we're not a router(_late)/repeater
|
// We only cancel it if we are the original sender or if we're not a router(_late)
|
||||||
if (isFromUs(p) || roleAllowsCancelingFromTxQueue(p)) {
|
if (isFromUs(p) || roleAllowsCancelingFromTxQueue(p)) {
|
||||||
// remove the 'original' (identified by originator and packet->id) from the txqueue and free it
|
// remove the 'original' (identified by originator and packet->id) from the txqueue and free it
|
||||||
cancelSending(getFrom(p), p->id);
|
cancelSending(getFrom(p), p->id);
|
||||||
|
|||||||
@ -554,10 +554,9 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USERPREFS_CONFIG_DEVICE_ROLE
|
#ifdef USERPREFS_CONFIG_DEVICE_ROLE
|
||||||
// Restrict ROUTER*, LOST AND FOUND, and REPEATER roles for security reasons
|
// Restrict ROUTER*, LOST AND FOUND roles for security reasons
|
||||||
if (IS_ONE_OF(USERPREFS_CONFIG_DEVICE_ROLE, meshtastic_Config_DeviceConfig_Role_ROUTER,
|
if (IS_ONE_OF(USERPREFS_CONFIG_DEVICE_ROLE, meshtastic_Config_DeviceConfig_Role_ROUTER,
|
||||||
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_REPEATER,
|
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND)) {
|
||||||
meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND)) {
|
|
||||||
LOG_WARN("ROUTER roles are restricted, falling back to CLIENT role");
|
LOG_WARN("ROUTER roles are restricted, falling back to CLIENT role");
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
||||||
} else {
|
} else {
|
||||||
@ -906,11 +905,6 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
|
|||||||
moduleConfig.telemetry.device_update_interval = ONE_DAY;
|
moduleConfig.telemetry.device_update_interval = ONE_DAY;
|
||||||
owner.has_is_unmessagable = true;
|
owner.has_is_unmessagable = true;
|
||||||
owner.is_unmessagable = true;
|
owner.is_unmessagable = true;
|
||||||
} else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
owner.has_is_unmessagable = true;
|
|
||||||
owner.is_unmessagable = true;
|
|
||||||
config.display.screen_on_secs = 1;
|
|
||||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY;
|
|
||||||
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
|
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
|
||||||
owner.has_is_unmessagable = true;
|
owner.has_is_unmessagable = true;
|
||||||
owner.is_unmessagable = true;
|
owner.is_unmessagable = true;
|
||||||
@ -1603,9 +1597,18 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
|
|||||||
void NodeDB::addFromContact(meshtastic_SharedContact contact)
|
void NodeDB::addFromContact(meshtastic_SharedContact contact)
|
||||||
{
|
{
|
||||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(contact.node_num);
|
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(contact.node_num);
|
||||||
if (!info) {
|
if (!info || !contact.has_user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// If the local node has this node marked as manually verified
|
||||||
|
// and the client does not, do not allow the client to update the
|
||||||
|
// saved public key.
|
||||||
|
if ((info->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK) && !contact.manually_verified) {
|
||||||
|
if (contact.user.public_key.size != info->user.public_key.size ||
|
||||||
|
memcmp(contact.user.public_key.bytes, info->user.public_key.bytes, info->user.public_key.size) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
info->num = contact.node_num;
|
info->num = contact.node_num;
|
||||||
info->has_user = true;
|
info->has_user = true;
|
||||||
info->user = TypeConversions::ConvertToUserLite(contact.user);
|
info->user = TypeConversions::ConvertToUserLite(contact.user);
|
||||||
@ -1620,10 +1623,12 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact)
|
|||||||
} else {
|
} else {
|
||||||
info->last_heard = getValidTime(RTCQualityNTP);
|
info->last_heard = getValidTime(RTCQualityNTP);
|
||||||
info->is_favorite = true;
|
info->is_favorite = true;
|
||||||
info->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
// As the clients will begin sending the contact with DMs, we want to strictly check if the node is manually verified
|
||||||
|
if (contact.manually_verified) {
|
||||||
|
info->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||||
|
}
|
||||||
// Mark the node's key as manually verified to indicate trustworthiness.
|
// Mark the node's key as manually verified to indicate trustworthiness.
|
||||||
updateGUIforNode = info;
|
updateGUIforNode = info;
|
||||||
// powerFSM.trigger(EVENT_NODEDB_UPDATED); This event has been retired
|
|
||||||
sortMeshDB();
|
sortMeshDB();
|
||||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||||
}
|
}
|
||||||
|
|||||||
@ -710,6 +710,13 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
|
|||||||
// sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds");
|
// sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upgrade traceroute requests from phone to use reliable delivery, matching TraceRouteModule
|
||||||
|
if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && !isBroadcast(p.to)) {
|
||||||
|
// Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo)
|
||||||
|
p.want_ack = true;
|
||||||
|
}
|
||||||
|
|
||||||
lastPortNumToRadio[p.decoded.portnum] = millis();
|
lastPortNumToRadio[p.decoded.portnum] = millis();
|
||||||
service->handleToRadio(p);
|
service->handleToRadio(p);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -317,9 +317,8 @@ uint32_t RadioInterface::getTxDelayMsecWeightedWorst(float snr)
|
|||||||
/** Returns true if we should rebroadcast early like a ROUTER */
|
/** Returns true if we should rebroadcast early like a ROUTER */
|
||||||
bool RadioInterface::shouldRebroadcastEarlyLikeRouter(meshtastic_MeshPacket *p)
|
bool RadioInterface::shouldRebroadcastEarlyLikeRouter(meshtastic_MeshPacket *p)
|
||||||
{
|
{
|
||||||
// If we are a ROUTER or REPEATER, we always rebroadcast early
|
// If we are a ROUTER, we always rebroadcast early
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) {
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,10 +103,20 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
|||||||
/* A response may be set to want_ack for retransmissions, but we don't need to ACK a response if it received
|
/* A response may be set to want_ack for retransmissions, but we don't need to ACK a response if it received
|
||||||
an implicit ACK already. If we received it directly or via NextHopRouter, only ACK with a hop limit of 0 to
|
an implicit ACK already. If we received it directly or via NextHopRouter, only ACK with a hop limit of 0 to
|
||||||
make sure the other side stops retransmitting. */
|
make sure the other side stops retransmitting. */
|
||||||
if (!p->decoded.request_id && !p->decoded.reply_id) {
|
|
||||||
|
if (shouldSuccessAckWithWantAck(p)) {
|
||||||
|
// If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we
|
||||||
|
// do that unconditionally.
|
||||||
|
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
||||||
|
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit), true);
|
||||||
|
} else if (!p->decoded.request_id && !p->decoded.reply_id) {
|
||||||
|
// If it's not an ACK or a reply, send an ACK.
|
||||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
||||||
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
|
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
|
||||||
} else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
|
} else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
|
||||||
|
// If we received the packet directly from the original sender, send a 0-hop ACK since the original sender
|
||||||
|
// won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to
|
||||||
|
// stop the immediate relayer's retransmissions.
|
||||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0);
|
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0);
|
||||||
}
|
}
|
||||||
} else if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag && p->channel == 0 &&
|
} else if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag && p->channel == 0 &&
|
||||||
@ -152,4 +162,36 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
|||||||
|
|
||||||
// handle the packet as normal
|
// handle the packet as normal
|
||||||
isBroadcast(p->to) ? FloodingRouter::sniffReceived(p, c) : NextHopRouter::sniffReceived(p, c);
|
isBroadcast(p->to) ? FloodingRouter::sniffReceived(p, c) : NextHopRouter::sniffReceived(p, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we ACK this packet, should we set want_ack=true on the ACK for reliable delivery of the ACK packet?
|
||||||
|
*/
|
||||||
|
bool ReliableRouter::shouldSuccessAckWithWantAck(const meshtastic_MeshPacket *p)
|
||||||
|
{
|
||||||
|
// Don't ACK-with-want-ACK outgoing packets
|
||||||
|
if (isFromUs(p))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only ACK-with-want-ACK if the original packet asked for want_ack
|
||||||
|
if (!p->want_ack)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only ACK-with-want-ACK packets to us (not broadcast)
|
||||||
|
if (!isToUs(p))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Special case for text message DMs:
|
||||||
|
bool isTextMessage =
|
||||||
|
(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) &&
|
||||||
|
IS_ONE_OF(p->decoded.portnum, meshtastic_PortNum_TEXT_MESSAGE_APP, meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP);
|
||||||
|
|
||||||
|
if (isTextMessage) {
|
||||||
|
// If it's a non-broadcast text message, and the original asked for want_ack,
|
||||||
|
// let's send an ACK that is itself want_ack to improve reliability of confirming delivery back to the sender.
|
||||||
|
// This should include all DMs regardless of whether or not reply_id is set.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
@ -31,4 +31,10 @@ class ReliableRouter : public NextHopRouter
|
|||||||
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
||||||
*/
|
*/
|
||||||
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override;
|
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Should this packet be ACKed with a want_ack for reliable delivery?
|
||||||
|
*/
|
||||||
|
bool shouldSuccessAckWithWantAck(const meshtastic_MeshPacket *p);
|
||||||
};
|
};
|
||||||
@ -198,9 +198,10 @@ meshtastic_MeshPacket *Router::allocForSending()
|
|||||||
/**
|
/**
|
||||||
* Send an ack or a nak packet back towards whoever sent idFrom
|
* Send an ack or a nak packet back towards whoever sent idFrom
|
||||||
*/
|
*/
|
||||||
void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit)
|
void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit,
|
||||||
|
bool ackWantsAck)
|
||||||
{
|
{
|
||||||
routingModule->sendAckNak(err, to, idFrom, chIndex, hopLimit);
|
routingModule->sendAckNak(err, to, idFrom, chIndex, hopLimit, ackWantsAck);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p)
|
void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p)
|
||||||
@ -399,10 +400,6 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p)
|
|||||||
{
|
{
|
||||||
concurrency::LockGuard g(cryptLock);
|
concurrency::LockGuard g(cryptLock);
|
||||||
|
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER &&
|
|
||||||
config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING)
|
|
||||||
return DecodeState::DECODE_FAILURE;
|
|
||||||
|
|
||||||
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY &&
|
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY &&
|
||||||
(nodeDB->getMeshNode(p->from) == NULL || !nodeDB->getMeshNode(p->from)->has_user)) {
|
(nodeDB->getMeshNode(p->from) == NULL || !nodeDB->getMeshNode(p->from)->has_user)) {
|
||||||
LOG_DEBUG("Node 0x%x not in nodeDB-> Rebroadcast mode KNOWN_ONLY will ignore packet", p->from);
|
LOG_DEBUG("Node 0x%x not in nodeDB-> Rebroadcast mode KNOWN_ONLY will ignore packet", p->from);
|
||||||
|
|||||||
@ -125,7 +125,8 @@ class Router : protected concurrency::OSThread, protected PacketHistory
|
|||||||
/**
|
/**
|
||||||
* Send an ack or a nak packet back towards whoever sent idFrom
|
* Send an ack or a nak packet back towards whoever sent idFrom
|
||||||
*/
|
*/
|
||||||
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0);
|
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
|
||||||
|
bool ackWantsAck = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -132,6 +132,8 @@ typedef struct _meshtastic_SharedContact {
|
|||||||
meshtastic_User user;
|
meshtastic_User user;
|
||||||
/* Add this contact to the blocked / ignored list */
|
/* Add this contact to the blocked / ignored list */
|
||||||
bool should_ignore;
|
bool should_ignore;
|
||||||
|
/* Set the IS_KEY_MANUALLY_VERIFIED bit */
|
||||||
|
bool manually_verified;
|
||||||
} meshtastic_SharedContact;
|
} meshtastic_SharedContact;
|
||||||
|
|
||||||
/* This message is used by a client to initiate or complete a key verification */
|
/* This message is used by a client to initiate or complete a key verification */
|
||||||
@ -319,13 +321,13 @@ extern "C" {
|
|||||||
#define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0}
|
#define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0}
|
||||||
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
|
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}}
|
#define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}}
|
||||||
#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0}
|
#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0}
|
||||||
#define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0}
|
#define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0}
|
||||||
#define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}}
|
#define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}}
|
||||||
#define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0}
|
#define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0}
|
||||||
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
|
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}}
|
#define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}}
|
||||||
#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0}
|
#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0}
|
||||||
#define meshtastic_KeyVerificationAdmin_init_zero {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0}
|
#define meshtastic_KeyVerificationAdmin_init_zero {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
@ -341,6 +343,7 @@ extern "C" {
|
|||||||
#define meshtastic_SharedContact_node_num_tag 1
|
#define meshtastic_SharedContact_node_num_tag 1
|
||||||
#define meshtastic_SharedContact_user_tag 2
|
#define meshtastic_SharedContact_user_tag 2
|
||||||
#define meshtastic_SharedContact_should_ignore_tag 3
|
#define meshtastic_SharedContact_should_ignore_tag 3
|
||||||
|
#define meshtastic_SharedContact_manually_verified_tag 4
|
||||||
#define meshtastic_KeyVerificationAdmin_message_type_tag 1
|
#define meshtastic_KeyVerificationAdmin_message_type_tag 1
|
||||||
#define meshtastic_KeyVerificationAdmin_remote_nodenum_tag 2
|
#define meshtastic_KeyVerificationAdmin_remote_nodenum_tag 2
|
||||||
#define meshtastic_KeyVerificationAdmin_nonce_tag 3
|
#define meshtastic_KeyVerificationAdmin_nonce_tag 3
|
||||||
@ -504,7 +507,8 @@ X(a, STATIC, REPEATED, MESSAGE, node_remote_hardware_pins, 1)
|
|||||||
#define meshtastic_SharedContact_FIELDLIST(X, a) \
|
#define meshtastic_SharedContact_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, node_num, 1) \
|
X(a, STATIC, SINGULAR, UINT32, node_num, 1) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
|
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, should_ignore, 3)
|
X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, manually_verified, 4)
|
||||||
#define meshtastic_SharedContact_CALLBACK NULL
|
#define meshtastic_SharedContact_CALLBACK NULL
|
||||||
#define meshtastic_SharedContact_DEFAULT NULL
|
#define meshtastic_SharedContact_DEFAULT NULL
|
||||||
#define meshtastic_SharedContact_user_MSGTYPE meshtastic_User
|
#define meshtastic_SharedContact_user_MSGTYPE meshtastic_User
|
||||||
@ -539,7 +543,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg;
|
|||||||
#define meshtastic_HamParameters_size 31
|
#define meshtastic_HamParameters_size 31
|
||||||
#define meshtastic_KeyVerificationAdmin_size 25
|
#define meshtastic_KeyVerificationAdmin_size 25
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_size 496
|
#define meshtastic_NodeRemoteHardwarePinsResponse_size 496
|
||||||
#define meshtastic_SharedContact_size 125
|
#define meshtastic_SharedContact_size 127
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@ -611,10 +611,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
}
|
}
|
||||||
config.device = c.payload_variant.device;
|
config.device = c.payload_variant.device;
|
||||||
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_NONE &&
|
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_NONE &&
|
||||||
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER,
|
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) {
|
||||||
meshtastic_Config_DeviceConfig_Role_REPEATER)) {
|
|
||||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
|
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
|
||||||
const char *warning = "Rebroadcast mode can't be set to NONE for a router or repeater";
|
const char *warning = "Rebroadcast mode can't be set to NONE for a router";
|
||||||
LOG_WARN(warning);
|
LOG_WARN(warning);
|
||||||
sendWarning(warning);
|
sendWarning(warning);
|
||||||
}
|
}
|
||||||
@ -627,8 +626,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d", min_node_info_broadcast_secs);
|
LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d", min_node_info_broadcast_secs);
|
||||||
config.device.node_info_broadcast_secs = min_node_info_broadcast_secs;
|
config.device.node_info_broadcast_secs = min_node_info_broadcast_secs;
|
||||||
}
|
}
|
||||||
// Router Client is deprecated; Set it to client
|
// Router Client and Repeater deprecated; Set it to client
|
||||||
if (c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT) {
|
if (IS_ONE_OF(c.payload_variant.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT,
|
||||||
|
meshtastic_Config_DeviceConfig_Role_REPEATER)) {
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
||||||
if (moduleConfig.store_forward.enabled && !moduleConfig.store_forward.is_server) {
|
if (moduleConfig.store_forward.enabled && !moduleConfig.store_forward.is_server) {
|
||||||
moduleConfig.store_forward.is_server = true;
|
moduleConfig.store_forward.is_server = true;
|
||||||
@ -637,10 +637,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if USERPREFS_EVENT_MODE
|
#if USERPREFS_EVENT_MODE
|
||||||
// If we're in event mode, nobody is a Router or Repeater
|
// If we're in event mode, nobody is a Router or Router Late
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE ||
|
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) {
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -707,20 +706,40 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
#endif
|
#endif
|
||||||
config.display = c.payload_variant.display;
|
config.display = c.payload_variant.display;
|
||||||
break;
|
break;
|
||||||
case meshtastic_Config_lora_tag:
|
|
||||||
|
case meshtastic_Config_lora_tag: {
|
||||||
|
// Wrap the entire case in a block to scope variables and avoid crossing initialization
|
||||||
|
auto oldLoraConfig = config.lora;
|
||||||
|
auto validatedLora = c.payload_variant.lora;
|
||||||
|
|
||||||
LOG_INFO("Set config: LoRa");
|
LOG_INFO("Set config: LoRa");
|
||||||
config.has_lora = true;
|
config.has_lora = true;
|
||||||
|
|
||||||
|
if (validatedLora.coding_rate < 4 || validatedLora.coding_rate > 8) {
|
||||||
|
LOG_WARN("Invalid coding_rate %d, setting to 5", validatedLora.coding_rate);
|
||||||
|
validatedLora.coding_rate = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validatedLora.spread_factor < 7 || validatedLora.spread_factor > 12) {
|
||||||
|
LOG_WARN("Invalid spread_factor %d, setting to 11", validatedLora.spread_factor);
|
||||||
|
validatedLora.spread_factor = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validatedLora.bandwidth == 0) {
|
||||||
|
int originalBandwidth = validatedLora.bandwidth;
|
||||||
|
validatedLora.bandwidth = myRegion->wideLora ? 800 : 250;
|
||||||
|
LOG_WARN("Invalid bandwidth %d, setting to default", originalBandwidth);
|
||||||
|
}
|
||||||
|
|
||||||
// If no lora radio parameters change, don't need to reboot
|
// If no lora radio parameters change, don't need to reboot
|
||||||
if (config.lora.use_preset == c.payload_variant.lora.use_preset && config.lora.region == c.payload_variant.lora.region &&
|
if (oldLoraConfig.use_preset == validatedLora.use_preset && oldLoraConfig.region == validatedLora.region &&
|
||||||
config.lora.modem_preset == c.payload_variant.lora.modem_preset &&
|
oldLoraConfig.modem_preset == validatedLora.modem_preset && oldLoraConfig.bandwidth == validatedLora.bandwidth &&
|
||||||
config.lora.bandwidth == c.payload_variant.lora.bandwidth &&
|
oldLoraConfig.spread_factor == validatedLora.spread_factor &&
|
||||||
config.lora.spread_factor == c.payload_variant.lora.spread_factor &&
|
oldLoraConfig.coding_rate == validatedLora.coding_rate && oldLoraConfig.tx_power == validatedLora.tx_power &&
|
||||||
config.lora.coding_rate == c.payload_variant.lora.coding_rate &&
|
oldLoraConfig.frequency_offset == validatedLora.frequency_offset &&
|
||||||
config.lora.tx_power == c.payload_variant.lora.tx_power &&
|
oldLoraConfig.override_frequency == validatedLora.override_frequency &&
|
||||||
config.lora.frequency_offset == c.payload_variant.lora.frequency_offset &&
|
oldLoraConfig.channel_num == validatedLora.channel_num &&
|
||||||
config.lora.override_frequency == c.payload_variant.lora.override_frequency &&
|
oldLoraConfig.sx126x_rx_boosted_gain == validatedLora.sx126x_rx_boosted_gain) {
|
||||||
config.lora.channel_num == c.payload_variant.lora.channel_num &&
|
|
||||||
config.lora.sx126x_rx_boosted_gain == c.payload_variant.lora.sx126x_rx_boosted_gain) {
|
|
||||||
requiresReboot = false;
|
requiresReboot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,7 +758,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
digitalWrite(RF95_FAN_EN, HIGH ^ 0);
|
digitalWrite(RF95_FAN_EN, HIGH ^ 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
config.lora = c.payload_variant.lora;
|
config.lora = validatedLora;
|
||||||
// If we're setting region for the first time, init the region and regenerate the keys
|
// If we're setting region for the first time, init the region and regenerate the keys
|
||||||
if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||||
if (!owner.is_licensed) {
|
if (!owner.is_licensed) {
|
||||||
@ -784,6 +803,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG;
|
changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case meshtastic_Config_bluetooth_tag:
|
case meshtastic_Config_bluetooth_tag:
|
||||||
LOG_INFO("Set config: Bluetooth");
|
LOG_INFO("Set config: Bluetooth");
|
||||||
config.has_bluetooth = true;
|
config.has_bluetooth = true;
|
||||||
|
|||||||
@ -442,7 +442,7 @@ ExternalNotificationModule::ExternalNotificationModule()
|
|||||||
|
|
||||||
ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp)
|
ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||||
{
|
{
|
||||||
if (moduleConfig.external_notification.enabled && !isMuted) {
|
if (moduleConfig.external_notification.enabled && !isSilenced) {
|
||||||
#ifdef T_WATCH_S3
|
#ifdef T_WATCH_S3
|
||||||
drv.setWaveform(0, 75);
|
drv.setWaveform(0, 75);
|
||||||
drv.setWaveform(1, 56);
|
drv.setWaveform(1, 56);
|
||||||
@ -453,12 +453,13 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
||||||
auto &p = mp.decoded;
|
auto &p = mp.decoded;
|
||||||
bool containsBell = false;
|
bool containsBell = false;
|
||||||
for (int i = 0; i < p.payload.size; i++) {
|
for (size_t i = 0; i < p.payload.size; i++) {
|
||||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||||
containsBell = true;
|
containsBell = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meshtastic_Channel ch = channels.getByIndex(mp.channel ? mp.channel : channels.getPrimaryIndex());
|
||||||
if (moduleConfig.external_notification.alert_bell) {
|
if (moduleConfig.external_notification.alert_bell) {
|
||||||
if (containsBell) {
|
if (containsBell) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Bell");
|
LOG_INFO("externalNotificationModule - Notification Bell");
|
||||||
@ -509,7 +510,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_message) {
|
if (moduleConfig.external_notification.alert_message && !ch.settings.mute) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Module");
|
LOG_INFO("externalNotificationModule - Notification Module");
|
||||||
isNagging = true;
|
isNagging = true;
|
||||||
setExternalState(0, true);
|
setExternalState(0, true);
|
||||||
@ -520,7 +521,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_message_vibra) {
|
if (moduleConfig.external_notification.alert_message_vibra && !ch.settings.mute) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
|
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
|
||||||
isNagging = true;
|
isNagging = true;
|
||||||
setExternalState(1, true);
|
setExternalState(1, true);
|
||||||
@ -531,7 +532,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_message_buzzer) {
|
if (moduleConfig.external_notification.alert_message_buzzer && !ch.settings.mute) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
|
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
|
||||||
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
||||||
(!isBroadcast(mp.to) && isToUs(&mp))) {
|
(!isBroadcast(mp.to) && isToUs(&mp))) {
|
||||||
|
|||||||
@ -43,8 +43,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
|||||||
void setExternalState(uint8_t index = 0, bool on = false);
|
void setExternalState(uint8_t index = 0, bool on = false);
|
||||||
bool getExternal(uint8_t index = 0);
|
bool getExternal(uint8_t index = 0);
|
||||||
|
|
||||||
void setMute(bool mute) { isMuted = mute; }
|
void setMute(bool mute) { isSilenced = mute; }
|
||||||
bool getMute() { return isMuted; }
|
bool getMute() { return isSilenced; }
|
||||||
|
|
||||||
bool canBuzz();
|
bool canBuzz();
|
||||||
bool nagging();
|
bool nagging();
|
||||||
@ -67,7 +67,7 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
|||||||
|
|
||||||
bool isNagging = false;
|
bool isNagging = false;
|
||||||
|
|
||||||
bool isMuted = false;
|
bool isSilenced = false;
|
||||||
|
|
||||||
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
||||||
meshtastic_AdminMessage *request,
|
meshtastic_AdminMessage *request,
|
||||||
|
|||||||
@ -112,204 +112,191 @@
|
|||||||
*/
|
*/
|
||||||
void setupModules()
|
void setupModules()
|
||||||
{
|
{
|
||||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
|
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
inputBroker = new InputBroker();
|
inputBroker = new InputBroker();
|
||||||
systemCommandsModule = new SystemCommandsModule();
|
systemCommandsModule = new SystemCommandsModule();
|
||||||
buzzerFeedbackThread = new BuzzerFeedbackThread();
|
buzzerFeedbackThread = new BuzzerFeedbackThread();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||||
adminModule = new AdminModule();
|
adminModule = new AdminModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_NODEINFO
|
#if !MESHTASTIC_EXCLUDE_NODEINFO
|
||||||
nodeInfoModule = new NodeInfoModule();
|
nodeInfoModule = new NodeInfoModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_GPS
|
#if !MESHTASTIC_EXCLUDE_GPS
|
||||||
positionModule = new PositionModule();
|
positionModule = new PositionModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_WAYPOINT
|
#if !MESHTASTIC_EXCLUDE_WAYPOINT
|
||||||
waypointModule = new WaypointModule();
|
waypointModule = new WaypointModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_TEXTMESSAGE
|
#if !MESHTASTIC_EXCLUDE_TEXTMESSAGE
|
||||||
textMessageModule = new TextMessageModule();
|
textMessageModule = new TextMessageModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_TRACEROUTE
|
#if !MESHTASTIC_EXCLUDE_TRACEROUTE
|
||||||
traceRouteModule = new TraceRouteModule();
|
traceRouteModule = new TraceRouteModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
|
#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
|
||||||
if (moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled) {
|
if (moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled) {
|
||||||
neighborInfoModule = new NeighborInfoModule();
|
neighborInfoModule = new NeighborInfoModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
|
#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
|
||||||
if (moduleConfig.has_detection_sensor && moduleConfig.detection_sensor.enabled) {
|
if (moduleConfig.has_detection_sensor && moduleConfig.detection_sensor.enabled) {
|
||||||
detectionSensorModule = new DetectionSensorModule();
|
detectionSensorModule = new DetectionSensorModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_ATAK
|
#if !MESHTASTIC_EXCLUDE_ATAK
|
||||||
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK,
|
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK, meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) {
|
||||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) {
|
atakPluginModule = new AtakPluginModule();
|
||||||
atakPluginModule = new AtakPluginModule();
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_PKI
|
#if !MESHTASTIC_EXCLUDE_PKI
|
||||||
keyVerificationModule = new KeyVerificationModule();
|
keyVerificationModule = new KeyVerificationModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||||
dropzoneModule = new DropzoneModule();
|
dropzoneModule = new DropzoneModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
||||||
new GenericThreadModule();
|
new GenericThreadModule();
|
||||||
#endif
|
#endif
|
||||||
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
|
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
|
||||||
// to a global variable.
|
// to a global variable.
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE
|
#if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE
|
||||||
new RemoteHardwareModule();
|
new RemoteHardwareModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_POWERSTRESS
|
#if !MESHTASTIC_EXCLUDE_POWERSTRESS
|
||||||
new PowerStressModule();
|
new PowerStressModule();
|
||||||
#endif
|
#endif
|
||||||
// Example: Put your module here
|
// Example: Put your module here
|
||||||
// new ReplyModule();
|
// new ReplyModule();
|
||||||
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
|
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
||||||
if (!rotaryEncoderInterruptImpl1->init()) {
|
if (!rotaryEncoderInterruptImpl1->init()) {
|
||||||
delete rotaryEncoderInterruptImpl1;
|
delete rotaryEncoderInterruptImpl1;
|
||||||
rotaryEncoderInterruptImpl1 = nullptr;
|
rotaryEncoderInterruptImpl1 = nullptr;
|
||||||
}
|
}
|
||||||
#ifdef T_LORA_PAGER
|
#ifdef T_LORA_PAGER
|
||||||
// use a special FSM based rotary encoder version for T-LoRa Pager
|
// use a special FSM based rotary encoder version for T-LoRa Pager
|
||||||
rotaryEncoderImpl = new RotaryEncoderImpl();
|
rotaryEncoderImpl = new RotaryEncoderImpl();
|
||||||
if (!rotaryEncoderImpl->init()) {
|
if (!rotaryEncoderImpl->init()) {
|
||||||
delete rotaryEncoderImpl;
|
delete rotaryEncoderImpl;
|
||||||
rotaryEncoderImpl = nullptr;
|
rotaryEncoderImpl = nullptr;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
||||||
if (!upDownInterruptImpl1->init()) {
|
if (!upDownInterruptImpl1->init()) {
|
||||||
delete upDownInterruptImpl1;
|
delete upDownInterruptImpl1;
|
||||||
upDownInterruptImpl1 = nullptr;
|
upDownInterruptImpl1 = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
cardKbI2cImpl = new CardKbI2cImpl();
|
cardKbI2cImpl = new CardKbI2cImpl();
|
||||||
cardKbI2cImpl->init();
|
cardKbI2cImpl->init();
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
i2cButton = new i2cButtonThread("i2cButtonThread");
|
i2cButton = new i2cButtonThread("i2cButtonThread");
|
||||||
#endif
|
#endif
|
||||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||||
kbMatrixImpl = new KbMatrixImpl();
|
kbMatrixImpl = new KbMatrixImpl();
|
||||||
kbMatrixImpl->init();
|
kbMatrixImpl->init();
|
||||||
#endif // INPUTBROKER_MATRIX_TYPE
|
#endif // INPUTBROKER_MATRIX_TYPE
|
||||||
#ifdef INPUTBROKER_SERIAL_TYPE
|
#ifdef INPUTBROKER_SERIAL_TYPE
|
||||||
aSerialKeyboardImpl = new SerialKeyboardImpl();
|
aSerialKeyboardImpl = new SerialKeyboardImpl();
|
||||||
aSerialKeyboardImpl->init();
|
aSerialKeyboardImpl->init();
|
||||||
#endif // INPUTBROKER_MATRIX_TYPE
|
#endif // INPUTBROKER_MATRIX_TYPE
|
||||||
}
|
}
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
seesawRotary = new SeesawRotary("SeesawRotary");
|
seesawRotary = new SeesawRotary("SeesawRotary");
|
||||||
if (!seesawRotary->init()) {
|
if (!seesawRotary->init()) {
|
||||||
delete seesawRotary;
|
delete seesawRotary;
|
||||||
seesawRotary = nullptr;
|
seesawRotary = nullptr;
|
||||||
}
|
|
||||||
aLinuxInputImpl = new LinuxInputImpl();
|
|
||||||
aLinuxInputImpl->init();
|
|
||||||
}
|
}
|
||||||
|
aLinuxInputImpl = new LinuxInputImpl();
|
||||||
|
aLinuxInputImpl->init();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
|
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||||
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
|
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
|
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
|
||||||
expressLRSFiveWayInput = new ExpressLRSFiveWay();
|
expressLRSFiveWayInput = new ExpressLRSFiveWay();
|
||||||
#endif
|
#endif
|
||||||
#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
|
#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
cannedMessageModule = new CannedMessageModule();
|
cannedMessageModule = new CannedMessageModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
new HostMetricsModule();
|
new HostMetricsModule();
|
||||||
#endif
|
#endif
|
||||||
#if HAS_TELEMETRY
|
#if HAS_TELEMETRY
|
||||||
new DeviceTelemetryModule();
|
new DeviceTelemetryModule();
|
||||||
#endif
|
#endif
|
||||||
#if HAS_TELEMETRY && HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if HAS_TELEMETRY && HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
if (moduleConfig.has_telemetry &&
|
if (moduleConfig.has_telemetry &&
|
||||||
(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) {
|
(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) {
|
||||||
new EnvironmentTelemetryModule();
|
new EnvironmentTelemetryModule();
|
||||||
}
|
}
|
||||||
#if __has_include("Adafruit_PM25AQI.h")
|
#if __has_include("Adafruit_PM25AQI.h")
|
||||||
if (moduleConfig.has_telemetry && moduleConfig.telemetry.air_quality_enabled &&
|
if (moduleConfig.has_telemetry && moduleConfig.telemetry.air_quality_enabled &&
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
|
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
|
||||||
new AirQualityTelemetryModule();
|
new AirQualityTelemetryModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY
|
#if !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY
|
||||||
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 ||
|
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 ||
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) {
|
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) {
|
||||||
new HealthTelemetryModule();
|
new HealthTelemetryModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
if (moduleConfig.has_telemetry &&
|
if (moduleConfig.has_telemetry &&
|
||||||
(moduleConfig.telemetry.power_measurement_enabled || moduleConfig.telemetry.power_screen_enabled)) {
|
(moduleConfig.telemetry.power_measurement_enabled || moduleConfig.telemetry.power_screen_enabled)) {
|
||||||
new PowerTelemetryModule();
|
new PowerTelemetryModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
#if !MESHTASTIC_EXCLUDE_SERIAL
|
#if !MESHTASTIC_EXCLUDE_SERIAL
|
||||||
if (moduleConfig.has_serial && moduleConfig.serial.enabled &&
|
if (moduleConfig.has_serial && moduleConfig.serial.enabled &&
|
||||||
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
new SerialModule();
|
new SerialModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
// Only run on an esp32 based device.
|
// Only run on an esp32 based device.
|
||||||
#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
|
#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
|
||||||
audioModule = new AudioModule();
|
audioModule = new AudioModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||||
if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) {
|
if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) {
|
||||||
paxcounterModule = new PaxcounterModule();
|
paxcounterModule = new PaxcounterModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||||
if (moduleConfig.has_store_forward && moduleConfig.store_forward.enabled) {
|
if (moduleConfig.has_store_forward && moduleConfig.store_forward.enabled) {
|
||||||
storeForwardModule = new StoreForwardModule();
|
storeForwardModule = new StoreForwardModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||||
externalNotificationModule = new ExternalNotificationModule();
|
externalNotificationModule = new ExternalNotificationModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
|
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
|
||||||
if (moduleConfig.has_range_test && moduleConfig.range_test.enabled)
|
if (moduleConfig.has_range_test && moduleConfig.range_test.enabled)
|
||||||
new RangeTestModule();
|
new RangeTestModule();
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
|
||||||
adminModule = new AdminModule();
|
|
||||||
#endif
|
|
||||||
#if HAS_TELEMETRY
|
|
||||||
new DeviceTelemetryModule();
|
|
||||||
#endif
|
|
||||||
#if !MESHTASTIC_EXCLUDE_TRACEROUTE
|
|
||||||
traceRouteModule = new TraceRouteModule();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra
|
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra
|
||||||
// acks
|
// acks
|
||||||
routingModule = new RoutingModule();
|
routingModule = new RoutingModule();
|
||||||
|
|||||||
@ -94,11 +94,6 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
|
|||||||
u.public_key.bytes[0] = 0;
|
u.public_key.bytes[0] = 0;
|
||||||
u.public_key.size = 0;
|
u.public_key.size = 0;
|
||||||
}
|
}
|
||||||
// Coerce unmessagable for Repeater role
|
|
||||||
if (u.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
||||||
u.has_is_unmessagable = true;
|
|
||||||
u.is_unmessagable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name);
|
LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name);
|
||||||
lastSentToMesh = millis();
|
lastSentToMesh = millis();
|
||||||
|
|||||||
@ -42,17 +42,19 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh
|
|||||||
|
|
||||||
meshtastic_MeshPacket *RoutingModule::allocReply()
|
meshtastic_MeshPacket *RoutingModule::allocReply()
|
||||||
{
|
{
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
|
|
||||||
return NULL;
|
|
||||||
assert(currentRequest);
|
assert(currentRequest);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit)
|
void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit,
|
||||||
|
bool ackWantsAck)
|
||||||
{
|
{
|
||||||
auto p = allocAckNak(err, to, idFrom, chIndex, hopLimit);
|
auto p = allocAckNak(err, to, idFrom, chIndex, hopLimit);
|
||||||
|
|
||||||
|
// Allow the caller to set want_ack on this ACK packet if it's important that the ACK be delivered reliably
|
||||||
|
p->want_ack = ackWantsAck;
|
||||||
|
|
||||||
router->sendLocal(p); // we sometimes send directly to the local node
|
router->sendLocal(p); // we sometimes send directly to the local node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,8 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
|
|||||||
*/
|
*/
|
||||||
RoutingModule();
|
RoutingModule();
|
||||||
|
|
||||||
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
|
||||||
uint8_t hopLimit = 0);
|
bool ackWantsAck = false);
|
||||||
|
|
||||||
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
||||||
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
||||||
|
|||||||
@ -26,7 +26,6 @@ int32_t DeviceTelemetryModule::runOnce()
|
|||||||
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
||||||
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
|
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
|
||||||
airTime->isTxAllowedChannelUtil(!isImpoliteRole) && airTime->isTxAllowedAirUtil() &&
|
airTime->isTxAllowedChannelUtil(!isImpoliteRole) && airTime->isTxAllowedAirUtil() &&
|
||||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
|
|
||||||
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
||||||
sendTelemetry();
|
sendTelemetry();
|
||||||
lastSentToMesh = uptimeLastMs;
|
lastSentToMesh = uptimeLastMs;
|
||||||
@ -44,10 +43,6 @@ int32_t DeviceTelemetryModule::runOnce()
|
|||||||
|
|
||||||
bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||||
{
|
{
|
||||||
// Don't worry about storing telemetry in NodeDB if we're a repeater
|
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (t->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
if (t->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||||
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
||||||
const char *sender = getSenderShortName(mp);
|
const char *sender = getSenderShortName(mp);
|
||||||
|
|||||||
@ -22,10 +22,6 @@ int32_t HostMetricsModule::runOnce()
|
|||||||
|
|
||||||
bool HostMetricsModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
bool HostMetricsModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||||
{
|
{
|
||||||
// Don't worry about storing telemetry in NodeDB if we're a repeater
|
|
||||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (t->which_variant == meshtastic_Telemetry_host_metrics_tag) {
|
if (t->which_variant == meshtastic_Telemetry_host_metrics_tag) {
|
||||||
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
||||||
const char *sender = getSenderShortName(mp);
|
const char *sender = getSenderShortName(mp);
|
||||||
|
|||||||
@ -419,6 +419,9 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
p->decoded.portnum = meshtastic_PortNum_TRACEROUTE_APP;
|
p->decoded.portnum = meshtastic_PortNum_TRACEROUTE_APP;
|
||||||
p->decoded.want_response = true;
|
p->decoded.want_response = true;
|
||||||
|
|
||||||
|
// Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo)
|
||||||
|
p->want_ack = true;
|
||||||
|
|
||||||
// Manually encode the RouteDiscovery payload
|
// Manually encode the RouteDiscovery payload
|
||||||
p->decoded.payload.size =
|
p->decoded.payload.size =
|
||||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, &req);
|
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, &req);
|
||||||
@ -532,6 +535,9 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
p->decoded.portnum = meshtastic_PortNum_TRACEROUTE_APP;
|
p->decoded.portnum = meshtastic_PortNum_TRACEROUTE_APP;
|
||||||
p->decoded.want_response = true;
|
p->decoded.want_response = true;
|
||||||
|
|
||||||
|
// Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo)
|
||||||
|
p->want_ack = true;
|
||||||
|
|
||||||
p->decoded.payload.size =
|
p->decoded.payload.size =
|
||||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, &req);
|
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, &req);
|
||||||
|
|
||||||
|
|||||||
@ -335,7 +335,8 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke
|
|||||||
meshtastic::BluetoothStatus newStatus(textkey);
|
meshtastic::BluetoothStatus newStatus(textkey);
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
|
|
||||||
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
#if HAS_SCREEN && \
|
||||||
|
!defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||||
if (screen) {
|
if (screen) {
|
||||||
screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||||
char btPIN[16] = "888888";
|
char btPIN[16] = "888888";
|
||||||
|
|||||||
@ -98,6 +98,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK
|
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK
|
||||||
#elif defined(SEEED_WIO_TRACKER_L1)
|
#elif defined(SEEED_WIO_TRACKER_L1)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1
|
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1
|
||||||
|
#elif defined(R1_NEO)
|
||||||
|
#define HW_VENDOR meshtastic_HardwareModel_MUZI_R1_NEO
|
||||||
#elif defined(HELTEC_MESH_SOLAR)
|
#elif defined(HELTEC_MESH_SOLAR)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR
|
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR
|
||||||
#else
|
#else
|
||||||
@ -149,3 +151,6 @@
|
|||||||
// No serial ports on this board - ONLY use segger in memory console
|
// No serial ports on this board - ONLY use segger in memory console
|
||||||
#define USE_SEGGER
|
#define USE_SEGGER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Detect if running in ISR context (ARM Cortex-M4)
|
||||||
|
#define xPortInIsrContext() ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) == 0 ? pdFALSE : pdTRUE)
|
||||||
|
|||||||
@ -35,4 +35,7 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_RP2040_FEATHER_RFM95
|
#define HW_VENDOR meshtastic_HardwareModel_RP2040_FEATHER_RFM95
|
||||||
#elif defined(PRIVATE_HW)
|
#elif defined(PRIVATE_HW)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
|
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Detect if running in ISR context (ARM Cortex-M33 / RISC-V)
|
||||||
|
#define xPortInIsrContext() (__get_current_exception() == 0 ? pdFALSE : pdTRUE)
|
||||||
|
|||||||
@ -34,6 +34,8 @@
|
|||||||
#define OCV_ARRAY 4200, 3876, 3826, 3763, 3713, 3660, 3573, 3485, 3422, 3359, 3300
|
#define OCV_ARRAY 4200, 3876, 3826, 3763, 3713, 3660, 3573, 3485, 3422, 3359, 3300
|
||||||
#elif defined(SEEED_SOLAR_NODE)
|
#elif defined(SEEED_SOLAR_NODE)
|
||||||
#define OCV_ARRAY 4200, 3986, 3922, 3812, 3734, 3645, 3527, 3420, 3281, 3087, 2786
|
#define OCV_ARRAY 4200, 3986, 3922, 3812, 3734, 3645, 3527, 3420, 3281, 3087, 2786
|
||||||
|
#elif defined(R1_NEO)
|
||||||
|
#define OCV_ARRAY 4330, 4292, 4254, 4216, 4178, 4140, 4102, 4064, 4026, 3988, 3950
|
||||||
#else // LiIon
|
#else // LiIon
|
||||||
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
|
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -532,8 +532,7 @@ void enableModemSleep()
|
|||||||
|
|
||||||
bool shouldLoraWake(uint32_t msecToWake)
|
bool shouldLoraWake(uint32_t msecToWake)
|
||||||
{
|
{
|
||||||
return msecToWake < portMAX_DELAY && (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
return msecToWake < portMAX_DELAY && (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER);
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void enableLoraInterrupt()
|
void enableLoraInterrupt()
|
||||||
|
|||||||
@ -83,8 +83,8 @@ class MockNodeDB : public NodeDB
|
|||||||
class MockRoutingModule : public RoutingModule
|
class MockRoutingModule : public RoutingModule
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
|
||||||
uint8_t hopLimit = 0) override
|
bool ackWantsAck = false) override
|
||||||
{
|
{
|
||||||
ackNacks_.emplace_back(err, to, idFrom, chIndex, hopLimit);
|
ackNacks_.emplace_back(err, to, idFrom, chIndex, hopLimit);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
// "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US",
|
// "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US",
|
||||||
// "USERPREFS_CONFIG_OWNER_LONG_NAME": "My Long Name",
|
// "USERPREFS_CONFIG_OWNER_LONG_NAME": "My Long Name",
|
||||||
// "USERPREFS_CONFIG_OWNER_SHORT_NAME": "MLN",
|
// "USERPREFS_CONFIG_OWNER_SHORT_NAME": "MLN",
|
||||||
// "USERPREFS_CONFIG_DEVICE_ROLE": "meshtastic_Config_DeviceConfig_Role_CLIENT", // Defaults to CLIENT. ROUTER*, LOST AND FOUND, and REPEATER roles are restricted.
|
// "USERPREFS_CONFIG_DEVICE_ROLE": "meshtastic_Config_DeviceConfig_Role_CLIENT", // Defaults to CLIENT. ROUTER*, and LOST AND FOUND roles are restricted.
|
||||||
// "USERPREFS_EVENT_MODE": "1",
|
// "USERPREFS_EVENT_MODE": "1",
|
||||||
// "USERPREFS_FIRMWARE_EDITION": "meshtastic_FirmwareEdition_BURNING_MAN",
|
// "USERPREFS_FIRMWARE_EDITION": "meshtastic_FirmwareEdition_BURNING_MAN",
|
||||||
// "USERPREFS_FIXED_BLUETOOTH": "121212",
|
// "USERPREFS_FIXED_BLUETOOTH": "121212",
|
||||||
|
|||||||
@ -15,7 +15,7 @@ build_flags = ${esp32s3_base.build_flags}
|
|||||||
-D SDCARD_USE_SPI1
|
-D SDCARD_USE_SPI1
|
||||||
-D ENABLE_ROTARY_PULLUP
|
-D ENABLE_ROTARY_PULLUP
|
||||||
-D ENABLE_BUTTON_PULLUP
|
-D ENABLE_BUTTON_PULLUP
|
||||||
-D HALF_STEP
|
-D ROTARY_BUXTRONICS
|
||||||
|
|
||||||
lib_deps = ${esp32s3_base.lib_deps}
|
lib_deps = ${esp32s3_base.lib_deps}
|
||||||
lovyan03/LovyanGFX@1.2.7
|
lovyan03/LovyanGFX@1.2.7
|
||||||
@ -26,7 +26,7 @@ lib_deps = ${esp32s3_base.lib_deps}
|
|||||||
lewisxhe/SensorLib@0.3.1
|
lewisxhe/SensorLib@0.3.1
|
||||||
https://github.com/pschatzmann/arduino-audio-driver/archive/refs/tags/v0.1.3.zip
|
https://github.com/pschatzmann/arduino-audio-driver/archive/refs/tags/v0.1.3.zip
|
||||||
https://github.com/mverch67/BQ27220/archive/07d92be846abd8a0258a50c23198dac0858b22ed.zip
|
https://github.com/mverch67/BQ27220/archive/07d92be846abd8a0258a50c23198dac0858b22ed.zip
|
||||||
https://github.com/mverch67/RotaryEncoder/archive/25a59d5745a6645536f921427d80b08e78f886d4.zip
|
https://github.com/mverch67/RotaryEncoder/archive/da958a21389cbcd485989705df602a33e092dd88.zip
|
||||||
|
|
||||||
[env:tlora-pager-tft]
|
[env:tlora-pager-tft]
|
||||||
board_level = extra
|
board_level = extra
|
||||||
|
|||||||
19
variants/nrf52840/r1-neo/platformio.ini
Normal file
19
variants/nrf52840/r1-neo/platformio.ini
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
; The R1 Neo board
|
||||||
|
[env:r1-neo]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = r1-neo
|
||||||
|
board_check = true
|
||||||
|
build_flags = ${nrf52840_base.build_flags}
|
||||||
|
-Ivariants/nrf52840/r1-neo
|
||||||
|
-D R1_NEO
|
||||||
|
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||||
|
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||||
|
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||||
|
-DRADIOLIB_EXCLUDE_LR11X0=1
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/r1-neo> +<mesh/api/> +<mqtt/>
|
||||||
|
lib_deps =
|
||||||
|
${nrf52840_base.lib_deps}
|
||||||
|
${networking_base.lib_deps}
|
||||||
|
https://github.com/RAKWireless/RAK13800-W5100S/archive/1.0.2.zip
|
||||||
|
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
|
||||||
|
artronshop/ArtronShop_RX8130CE@1.0.0
|
||||||
45
variants/nrf52840/r1-neo/variant.cpp
Normal file
45
variants/nrf52840/r1-neo/variant.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "variant.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
// P0
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
|
||||||
|
// P1
|
||||||
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
// LED1 & LED2
|
||||||
|
pinMode(PIN_LED1, OUTPUT);
|
||||||
|
ledOff(PIN_LED1);
|
||||||
|
|
||||||
|
pinMode(PIN_LED2, OUTPUT);
|
||||||
|
ledOff(PIN_LED2);
|
||||||
|
|
||||||
|
// 3V3 Power Rail
|
||||||
|
// pinMode(PIN_3V3_EN, OUTPUT);
|
||||||
|
// digitalWrite(PIN_3V3_EN, HIGH);
|
||||||
|
}
|
||||||
149
variants/nrf52840/r1-neo/variant.h
Normal file
149
variants/nrf52840/r1-neo/variant.h
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VARIANT_R1NEO_
|
||||||
|
#define _VARIANT_R1NEO_
|
||||||
|
|
||||||
|
#define RAK4630
|
||||||
|
|
||||||
|
/** Master clock frequency */
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
|
||||||
|
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||||
|
// define USE_LFRC // Board uses RC for LF
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Headers
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// Number of pins defined in PinDescription array
|
||||||
|
#define PINS_COUNT (48)
|
||||||
|
#define NUM_DIGITAL_PINS (48)
|
||||||
|
#define NUM_ANALOG_INPUTS (1)
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
#define PIN_LED1 (32 + 4) // P1.04 Controls Green LED
|
||||||
|
#define PIN_LED2 (28) // P0.28 Controls Blue LED
|
||||||
|
|
||||||
|
#define LED_BUILTIN PIN_LED1
|
||||||
|
#define LED_CONN PIN_LED2
|
||||||
|
|
||||||
|
#define LED_GREEN PIN_LED1
|
||||||
|
#define LED_BLUE PIN_LED2
|
||||||
|
|
||||||
|
#define LED_STATE_ON 1 // State when LED is litted
|
||||||
|
|
||||||
|
// Button
|
||||||
|
#define PIN_BUTTON1 (26)
|
||||||
|
#define BUTTON_ACTIVE_LOW 0
|
||||||
|
#define BUTTON_ACTIVE_PULLUP 0
|
||||||
|
#define BUTTON_SENSE_TYPE INPUT_SENSE_HIGH
|
||||||
|
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
|
||||||
|
// Serial for GPS
|
||||||
|
#define PIN_SERIAL1_RX (25)
|
||||||
|
#define PIN_SERIAL1_TX (24)
|
||||||
|
|
||||||
|
// Connected to Jlink CDC
|
||||||
|
#define PIN_SERIAL2_RX (8)
|
||||||
|
#define PIN_SERIAL2_TX (6)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI Interfaces
|
||||||
|
*/
|
||||||
|
#define SPI_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_SPI_MISO (45)
|
||||||
|
#define PIN_SPI_MOSI (44)
|
||||||
|
#define PIN_SPI_SCK (43)
|
||||||
|
|
||||||
|
static const uint8_t SS = 42;
|
||||||
|
static const uint8_t MOSI = PIN_SPI_MOSI;
|
||||||
|
static const uint8_t MISO = PIN_SPI_MISO;
|
||||||
|
static const uint8_t SCK = PIN_SPI_SCK;
|
||||||
|
|
||||||
|
// R1 Neo Extras
|
||||||
|
#define DCDC_EN_HOLD (13) // P0.13 Keeps DCDC alive after user button is pressed
|
||||||
|
#define NRF_ON (29) // P0.29 Tells IO controller device is on
|
||||||
|
|
||||||
|
// RAKRGB
|
||||||
|
#define HAS_NCP5623
|
||||||
|
|
||||||
|
#define HAS_SCREEN 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wire Interfaces
|
||||||
|
*/
|
||||||
|
#define WIRE_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_WIRE_SDA (19) // P0.19 RTC_SDA
|
||||||
|
#define PIN_WIRE_SCL (20) // P0.20 RTC_SCL
|
||||||
|
|
||||||
|
#define PIN_BUZZER (0 + 3) // P0.03
|
||||||
|
|
||||||
|
#define USE_SX1262
|
||||||
|
#define SX126X_CS (42)
|
||||||
|
#define SX126X_DIO1 (47)
|
||||||
|
#define SX126X_BUSY (46)
|
||||||
|
#define SX126X_RESET (38)
|
||||||
|
#define SX126X_POWER_EN (37)
|
||||||
|
|
||||||
|
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
|
// Testing USB detection
|
||||||
|
#define NRF_APM
|
||||||
|
|
||||||
|
#define PIN_GPS_EN (32 + 1) // P1.01
|
||||||
|
#define PIN_GPS_PPS (2) // P0.02 Pulse per second input from the GPS
|
||||||
|
|
||||||
|
#define GPS_RX_PIN PIN_SERIAL1_RX
|
||||||
|
#define GPS_TX_PIN PIN_SERIAL1_TX
|
||||||
|
|
||||||
|
// Battery
|
||||||
|
#define BATTERY_PIN (0 + 31) // P0.31 ADC_VBAT
|
||||||
|
// and has 12 bit resolution
|
||||||
|
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||||
|
#define BATTERY_SENSE_RESOLUTION 4096.0
|
||||||
|
#undef AREF_VOLTAGE
|
||||||
|
#define AREF_VOLTAGE 3.0
|
||||||
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
|
#define ADC_MULTIPLIER 1.73
|
||||||
|
|
||||||
|
#define HAS_RTC 1
|
||||||
|
|
||||||
|
#define RX8130CE_RTC 0x32
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Arduino objects - C++ only
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user