Compare commits

..

11 Commits

Author SHA1 Message Date
Ben Meadors
9d3f189d90 STM32 fix 2026-01-24 12:35:28 -06:00
Ben Meadors
a4875c234f Fix warnings 2026-01-24 05:23:32 -06:00
Ben Meadors
0c840440f8 Fix some warnings 2026-01-24 05:01:01 -06:00
Ben Meadors
3d605cec65 Merge branch 'master' into lora-params-bug 2026-01-23 19:17:48 -06:00
Jonathan Bennett
6d6a0734b0 Add pin sense to wake M6 on Solar Charge (#9416) 2026-01-23 15:37:16 -06:00
Ben Meadors
fdbd642e0e Move preset coercion logic to RadioInterface 2026-01-23 13:54:20 -06:00
Ben Meadors
9fbbb9aa9a Consolidate LoRa params / preset logic and fix display of preset values 2026-01-23 06:49:38 -06:00
renovate[bot]
3e3299f549 Update meshtastic/device-ui digest to 613c095 (#9383)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-22 09:07:23 +11:00
Ben Meadors
fb3bf783dd Implement graduated scaling for NodeInfo send timeout based on active mesh size (#9364)
* Implement graduated scaling for NodeInfo send timeout based on active mesh size

* Shorter timeout still needed for pubkey unkown and ad-hoc send

* Update src/modules/NodeInfoModule.cpp

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-19 20:00:41 -06:00
Ben Meadors
fc268d43d0 Add Meshtastic exclusion flags for webserver and paxcounter in platformio.ini 2026-01-19 16:57:21 -06:00
Jonathan Bennett
c38aff7e52 Add interrupt for external charge detection (#9332)
Tested on Thinknode m4, m6, and T1000-e
2026-01-19 15:39:24 -06:00
26 changed files with 210 additions and 262 deletions

View File

@@ -43,11 +43,13 @@ class Esp32C3ExceptionDecoder(DeviceMonitorFilterBase):
self.enabled = self.setup_paths()
if self.config.get("env:" + self.environment, "build_type") != "debug":
print("""
print(
"""
Please build project in debug configuration to get more details about an exception.
See https://docs.platformio.org/page/projectconf/build_configurations.html
""")
"""
)
return self

View File

@@ -119,7 +119,7 @@ lib_deps =
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/3480b731d28b10d73414cf0dd7975bff745de8cf.zip
https://github.com/meshtastic/device-ui/archive/613c0953313bbd236f4ddc5ede447e9edf8e890a.zip
; Common libs for environmental measurements in telemetry module
[environmental_base]

View File

@@ -723,6 +723,16 @@ bool Power::setup()
runASAP = true;
},
CHANGE);
#endif
#ifdef EXT_CHRG_DETECT
attachInterrupt(
EXT_CHRG_DETECT,
[]() {
power->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
},
CHANGE);
#endif
enabled = found;
low_voltage_counter = 0;

View File

@@ -155,10 +155,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
// Default system gain to 0 if not defined
#ifndef NUM_PA_POINTS
#define NUM_PA_POINTS 1
#endif
#ifndef TX_GAIN_LORA
#define TX_GAIN_LORA 0
#endif

View File

@@ -397,7 +397,7 @@ uint32_t getValidTime(RTCQuality minQuality, bool local)
return (currentQuality >= minQuality) ? getTime(local) : 0;
}
time_t gm_mktime(struct tm *tm)
time_t gm_mktime(const struct tm *tm)
{
#if !MESHTASTIC_EXCLUDE_TZ
time_t result = 0;
@@ -413,8 +413,8 @@ time_t gm_mktime(struct tm *tm)
days_before_this_year -= 719162; // (1969 * 365 + 1969 / 4 - 1969 / 100 + 1969 / 400);
// Now, within this tm->year, compute the days *before* this tm->month starts.
int days_before_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // non-leap year
int days_this_year_before_this_month = days_before_month[tm->tm_mon]; // tm->tm_mon is 0..11
static const int days_before_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // non-leap year
int days_this_year_before_this_month = days_before_month[tm->tm_mon]; // tm->tm_mon is 0..11
// If this is a leap year, and we're past February, add a day:
if (tm->tm_mon >= 2 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
@@ -435,6 +435,7 @@ time_t gm_mktime(struct tm *tm)
return result;
#else
return mktime(tm);
struct tm tmCopy = *tm;
return mktime(&tmCopy);
#endif
}

View File

@@ -54,7 +54,7 @@ uint32_t getValidTime(RTCQuality minQuality, bool local = false);
RTCSetResult readFromRTC();
time_t gm_mktime(struct tm *tm);
time_t gm_mktime(const struct tm *tm);
#define SEC_PER_DAY 86400
#define SEC_PER_HOUR 3600

View File

@@ -266,52 +266,8 @@ void menuHandler::FrequencySlotPicker()
// Calculate number of channels (copied from RadioInterface::applyModemConfig())
meshtastic_Config_LoRaConfig &loraConfig = config.lora;
double bw = loraConfig.bandwidth;
if (loraConfig.use_preset) {
switch (loraConfig.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
bw = (myRegion->wideLora) ? 1625.0 : 500;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
bw = (myRegion->wideLora) ? 1625.0 : 500;
break;
default:
bw = (myRegion->wideLora) ? 812.5 : 250;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
bw = (myRegion->wideLora) ? 406.25 : 125;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
bw = (myRegion->wideLora) ? 406.25 : 125;
break;
}
} else {
bw = loraConfig.bandwidth;
if (bw == 31) // This parameter is not an integer
bw = 31.25;
if (bw == 62) // Fix for 62.5Khz bandwidth
bw = 62.5;
if (bw == 200)
bw = 203.125;
if (bw == 400)
bw = 406.25;
if (bw == 800)
bw = 812.5;
if (bw == 1600)
bw = 1625.0;
}
double bw = loraConfig.use_preset ? modemPresetToBwKHz(loraConfig.modem_preset, myRegion->wideLora)
: bwCodeToKHz(loraConfig.bandwidth);
uint32_t numChannels = 0;
if (myRegion) {

View File

@@ -140,7 +140,7 @@ struct ScreenColor {
uint8_t b;
bool useVariant;
ScreenColor(uint8_t rIn = 0, uint8_t gIn = 0, uint8_t bIn = 0, bool variantIn = false)
explicit ScreenColor(uint8_t rIn = 0, uint8_t gIn = 0, uint8_t bIn = 0, bool variantIn = false)
: r(rIn), g(gIn), b(bIn), useVariant(variantIn)
{
}

View File

@@ -22,4 +22,99 @@ struct RegionInfo {
extern const RegionInfo regions[];
extern const RegionInfo *myRegion;
extern void initRegion();
extern void initRegion();
static inline float bwCodeToKHz(uint16_t bwCode)
{
if (bwCode == 31)
return 31.25f;
if (bwCode == 62)
return 62.5f;
if (bwCode == 200)
return 203.125f;
if (bwCode == 400)
return 406.25f;
if (bwCode == 800)
return 812.5f;
if (bwCode == 1600)
return 1625.0f;
return (float)bwCode;
}
static inline uint16_t bwKHzToCode(float bwKHz)
{
if (bwKHz > 31.24f && bwKHz < 31.26f)
return 31;
if (bwKHz > 62.49f && bwKHz < 62.51f)
return 62;
if (bwKHz > 203.12f && bwKHz < 203.13f)
return 200;
if (bwKHz > 406.24f && bwKHz < 406.26f)
return 400;
if (bwKHz > 812.49f && bwKHz < 812.51f)
return 800;
if (bwKHz > 1624.99f && bwKHz < 1625.01f)
return 1600;
return (uint16_t)(bwKHz + 0.5f);
}
static inline void modemPresetToParams(meshtastic_Config_LoRaConfig_ModemPreset preset, bool wideLora, float &bwKHz, uint8_t &sf,
uint8_t &cr)
{
switch (preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
bwKHz = wideLora ? 1625.0f : 500.0f;
cr = 5;
sf = 7;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
bwKHz = wideLora ? 812.5f : 250.0f;
cr = 5;
sf = 7;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bwKHz = wideLora ? 812.5f : 250.0f;
cr = 5;
sf = 8;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bwKHz = wideLora ? 812.5f : 250.0f;
cr = 5;
sf = 9;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bwKHz = wideLora ? 812.5f : 250.0f;
cr = 5;
sf = 10;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
bwKHz = wideLora ? 1625.0f : 500.0f;
cr = 8;
sf = 11;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
bwKHz = wideLora ? 406.25f : 125.0f;
cr = 8;
sf = 11;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
bwKHz = wideLora ? 406.25f : 125.0f;
cr = 8;
sf = 12;
break;
default: // LONG_FAST (or illegal)
bwKHz = wideLora ? 812.5f : 250.0f;
cr = 5;
sf = 11;
break;
}
}
static inline float modemPresetToBwKHz(meshtastic_Config_LoRaConfig_ModemPreset preset, bool wideLora)
{
float bwKHz = 0;
uint8_t sf = 0;
uint8_t cr = 0;
modemPresetToParams(preset, wideLora, bwKHz, sf, cr);
return bwKHz;
}

View File

@@ -13,6 +13,7 @@
#include "PacketHistory.h"
#include "PowerFSM.h"
#include "RTC.h"
#include "RadioInterface.h"
#include "Router.h"
#include "SPILock.h"
#include "SafeFile.h"
@@ -1297,6 +1298,13 @@ void NodeDB::loadFromDisk()
LOG_INFO("Loaded saved config version %d", config.version);
}
}
// Coerce LoRa config fields derived from presets while bootstrapping.
// Some clients/UI components display bandwidth/spread_factor directly from config even in preset mode.
if (config.has_lora && config.lora.use_preset) {
RadioInterface::bootstrapLoRaConfigFromPreset(config.lora);
}
if (backupSecurity.private_key.size > 0) {
LOG_DEBUG("Restoring backup of security config");
config.security = backupSecurity;

View File

@@ -220,6 +220,34 @@ void initRegion()
myRegion = r;
}
void RadioInterface::bootstrapLoRaConfigFromPreset(meshtastic_Config_LoRaConfig &loraConfig)
{
if (!loraConfig.use_preset) {
return;
}
// Find region info to determine whether "wide" LoRa is permitted (2.4 GHz uses wider bandwidth codes).
const RegionInfo *r = regions;
for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != loraConfig.region; r++)
;
const bool regionWideLora = r->wideLora;
float bwKHz = 0;
uint8_t sf = 0;
uint8_t cr = 0;
modemPresetToParams(loraConfig.modem_preset, regionWideLora, bwKHz, sf, cr);
// If selected preset requests a bandwidth larger than the region span, fall back to LONG_FAST.
if (r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && (r->freqEnd - r->freqStart) < (bwKHz / 1000.0f)) {
loraConfig.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
modemPresetToParams(loraConfig.modem_preset, regionWideLora, bwKHz, sf, cr);
}
loraConfig.bandwidth = bwKHzToCode(bwKHz);
loraConfig.spread_factor = sf;
}
/**
* ## LoRaWAN for North America
@@ -474,54 +502,7 @@ void RadioInterface::applyModemConfig()
bool validConfig = false; // We need to check for a valid configuration
while (!validConfig) {
if (loraConfig.use_preset) {
switch (loraConfig.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
bw = (myRegion->wideLora) ? 1625.0 : 500;
cr = 5;
sf = 7;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 5;
sf = 7;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 5;
sf = 8;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 5;
sf = 9;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 5;
sf = 10;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
bw = (myRegion->wideLora) ? 1625.0 : 500;
cr = 8;
sf = 11;
break;
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 5;
sf = 11;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
bw = (myRegion->wideLora) ? 406.25 : 125;
cr = 8;
sf = 11;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
bw = (myRegion->wideLora) ? 406.25 : 125;
cr = 8;
sf = 12;
break;
}
modemPresetToParams(loraConfig.modem_preset, myRegion->wideLora, bw, sf, cr);
if (loraConfig.coding_rate >= 5 && loraConfig.coding_rate <= 8 && loraConfig.coding_rate != cr) {
cr = loraConfig.coding_rate;
LOG_INFO("Using custom Coding Rate %u", cr);
@@ -529,20 +510,7 @@ void RadioInterface::applyModemConfig()
} else {
sf = loraConfig.spread_factor;
cr = loraConfig.coding_rate;
bw = loraConfig.bandwidth;
if (bw == 31) // This parameter is not an integer
bw = 31.25;
if (bw == 62) // Fix for 62.5Khz bandwidth
bw = 62.5;
if (bw == 200)
bw = 203.125;
if (bw == 400)
bw = 406.25;
if (bw == 800)
bw = 812.5;
if (bw == 1600)
bw = 1625.0;
bw = bwCodeToKHz(loraConfig.bandwidth);
}
if ((myRegion->freqEnd - myRegion->freqStart) < bw / 1000) {
@@ -666,24 +634,18 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
power = maxPower;
}
#ifdef ARCH_PORTDUINO
size_t num_pa_points = portduino_config.num_pa_points;
const uint16_t *tx_gain = portduino_config.tx_gain_lora;
#ifndef NUM_PA_POINTS
if (TX_GAIN_LORA > 0 && !devicestate.owner.is_licensed) {
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, TX_GAIN_LORA);
power -= TX_GAIN_LORA;
}
#else
size_t num_pa_points = NUM_PA_POINTS;
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
#endif
if (num_pa_points == 1) {
if (tx_gain[0] > 0 && !devicestate.owner.is_licensed) {
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[0]);
power -= tx_gain[0];
}
} else if (!devicestate.owner.is_licensed) {
if (!devicestate.owner.is_licensed) {
// we have an array of PA gain values. Find the highest power setting that works.
for (int radio_dbm = 0; radio_dbm < num_pa_points; radio_dbm++) {
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) {
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
((radio_dbm == (num_pa_points - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
// we've exceeded the power limit, or hit the max we can do
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
power -= tx_gain[radio_dbm];
@@ -691,7 +653,7 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
}
}
}
#endif
if (power > loraMaxPower) // Clamp power to maximum defined level
power = loraMaxPower;

View File

@@ -7,6 +7,9 @@
#include "airtime.h"
#include "error.h"
// Forward decls to avoid pulling generated config headers into this widely-included file.
typedef struct _meshtastic_Config_LoRaConfig meshtastic_Config_LoRaConfig;
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
#define MAX_LORA_PAYLOAD_LEN 255 // max length of 255 per Semtech's datasheets on SX12xx
@@ -115,6 +118,12 @@ class RadioInterface
virtual ~RadioInterface() {}
/**
* Coerce LoRa config fields (bandwidth/spread_factor) derived from presets.
* This is used during early bootstrapping so UIs that display these fields directly remain consistent.
*/
static void bootstrapLoRaConfigFromPreset(meshtastic_Config_LoRaConfig &loraConfig);
/**
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
*

View File

@@ -77,9 +77,7 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11,
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG = 12,
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG = 13
meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG = 12
} meshtastic_AdminMessage_ModuleConfigType;
typedef enum _meshtastic_AdminMessage_BackupLocation {
@@ -325,8 +323,8 @@ extern "C" {
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG+1))
#define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG+1))
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG+1))
#define _meshtastic_AdminMessage_BackupLocation_MIN meshtastic_AdminMessage_BackupLocation_FLASH
#define _meshtastic_AdminMessage_BackupLocation_MAX meshtastic_AdminMessage_BackupLocation_SD

View File

@@ -361,7 +361,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
/* Maximum encoded size of messages (where known) */
/* meshtastic_NodeDatabase_size depends on runtime parameters */
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
#define meshtastic_BackupPreferences_size 2362
#define meshtastic_BackupPreferences_size 2279
#define meshtastic_ChannelFile_size 718
#define meshtastic_DeviceState_size 1737
#define meshtastic_NodeInfoLite_size 196

View File

@@ -87,9 +87,6 @@ typedef struct _meshtastic_LocalModuleConfig {
/* Paxcounter Config */
bool has_paxcounter;
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
/* StatusMessage Config */
bool has_statusmessage;
meshtastic_ModuleConfig_StatusMessageConfig statusmessage;
} meshtastic_LocalModuleConfig;
@@ -99,9 +96,9 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0, false, meshtastic_Config_SecurityConfig_init_default}
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default, false, meshtastic_ModuleConfig_PaxcounterConfig_init_default, false, meshtastic_ModuleConfig_StatusMessageConfig_init_default}
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default, false, meshtastic_ModuleConfig_PaxcounterConfig_init_default}
#define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0, false, meshtastic_Config_SecurityConfig_init_zero}
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero, false, meshtastic_ModuleConfig_PaxcounterConfig_init_zero, false, meshtastic_ModuleConfig_StatusMessageConfig_init_zero}
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero, false, meshtastic_ModuleConfig_PaxcounterConfig_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_LocalConfig_device_tag 1
@@ -127,7 +124,6 @@ extern "C" {
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13
#define meshtastic_LocalModuleConfig_paxcounter_tag 14
#define meshtastic_LocalModuleConfig_statusmessage_tag 15
/* Struct field encoding specification for nanopb */
#define meshtastic_LocalConfig_FIELDLIST(X, a) \
@@ -165,8 +161,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) \
X(a, STATIC, OPTIONAL, MESSAGE, ambient_lighting, 12) \
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13) \
X(a, STATIC, OPTIONAL, MESSAGE, paxcounter, 14) \
X(a, STATIC, OPTIONAL, MESSAGE, statusmessage, 15)
X(a, STATIC, OPTIONAL, MESSAGE, paxcounter, 14)
#define meshtastic_LocalModuleConfig_CALLBACK NULL
#define meshtastic_LocalModuleConfig_DEFAULT NULL
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
@@ -182,7 +177,6 @@ X(a, STATIC, OPTIONAL, MESSAGE, statusmessage, 15)
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
#define meshtastic_LocalModuleConfig_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
#define meshtastic_LocalModuleConfig_statusmessage_MSGTYPE meshtastic_ModuleConfig_StatusMessageConfig
extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
@@ -192,9 +186,9 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size
#define meshtastic_LocalConfig_size 749
#define meshtastic_LocalModuleConfig_size 758
#define meshtastic_LocalModuleConfig_size 675
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -2,6 +2,7 @@
#include "Default.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "NodeStatus.h"
#include "RTC.h"
#include "Router.h"
#include "configuration.h"
@@ -129,14 +130,17 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
LOG_DEBUG("Skip send NodeInfo > 40%% ch. util");
return NULL;
}
// If we sent our NodeInfo less than 5 min. ago, don't send it again as it may be still underway.
if (!shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 5 * 60 * 1000)) {
LOG_DEBUG("Skip send NodeInfo since we sent it <5min ago");
// Use graduated scaling based on active mesh size (10 minute base, scales with congestion coefficient)
uint32_t timeoutMs = Default::getConfiguredOrDefaultMsScaled(0, 10 * 60, nodeStatus->getNumOnline());
if (!shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, timeoutMs)) {
LOG_DEBUG("Skip send NodeInfo since we sent it <%us ago", timeoutMs / 1000);
ignoreRequest = true; // Mark it as ignored for MeshModule
return NULL;
} else if (shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 60 * 1000)) {
// For interactive/urgent requests (e.g., user-triggered or implicit requests), use a shorter 60s timeout
LOG_DEBUG("Skip send NodeInfo since we sent it <60s ago");
ignoreRequest = true; // Mark it as ignored for MeshModule
ignoreRequest = true;
return NULL;
} else {
ignoreRequest = false; // Don't ignore requests anymore

View File

@@ -61,12 +61,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
switch (key) {
case 'p':
if (sscanf(arg, "%d", &TCPPort) < 1) {
if (sscanf(arg, "%d", &TCPPort) < 1)
return ARGP_ERR_UNKNOWN;
} else {
else
checkConfigPort = false;
printf("Using config file %d\n", TCPPort);
}
break;
case 'c':
configPath = arg;
@@ -650,19 +649,6 @@ bool loadConfig(const char *configPath)
if (yamlConfig["Lora"]["RF95_MAX_POWER"])
portduino_config.rf95_max_power = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20);
if (yamlConfig["Lora"]["TX_GAIN_LORA"]) {
YAML::Node tx_gain_node = yamlConfig["Lora"]["TX_GAIN_LORA"];
if (tx_gain_node.IsSequence() && tx_gain_node.size() != 0) {
portduino_config.num_pa_points = min(tx_gain_node.size(), std::size(portduino_config.tx_gain_lora));
for (int i = 0; i < portduino_config.num_pa_points; i++) {
portduino_config.tx_gain_lora[i] = tx_gain_node[i].as<int>();
}
} else {
portduino_config.num_pa_points = 1;
portduino_config.tx_gain_lora[0] = tx_gain_node.as<int>(0);
}
}
if (portduino_config.lora_module != use_autoconf && portduino_config.lora_module != use_simradio &&
!portduino_config.force_simradio) {
portduino_config.dio2_as_rf_switch = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
@@ -888,8 +874,10 @@ bool loadConfig(const char *configPath)
}
if (checkConfigPort) {
portduino_config.api_port = (yamlConfig["General"]["APIPort"]).as<int>(-1);
if (portduino_config.api_port != -1 && portduino_config.api_port > 1023 && portduino_config.api_port < 65536) {
TCPPort = (portduino_config.api_port);
if (portduino_config.api_port != -1 &&
portduino_config.api_port > 1023 &&
portduino_config.api_port < 65536) {
TCPPort = (portduino_config.api_port);
}
}
portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as<std::string>("");

View File

@@ -91,8 +91,6 @@ extern struct portduino_config_struct {
int lora_usb_pid = 0x5512;
int lora_usb_vid = 0x1A86;
int spiSpeed = 2000000;
int num_pa_points = 1; // default to 1 point, with 0 gain
uint16_t tx_gain_lora[22] = {0};
pinMapping lora_cs_pin = {"Lora", "CS"};
pinMapping lora_irq_pin = {"Lora", "IRQ"};
pinMapping lora_busy_pin = {"Lora", "Busy"};
@@ -233,17 +231,6 @@ extern struct portduino_config_struct {
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
if (rf95_max_power != 20)
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
if (num_pa_points > 1) {
out << YAML::Key << "TX_GAIN_LORA" << YAML::Value << YAML::Flow << YAML::BeginSeq;
for (int i = 0; i < num_pa_points; i++) {
out << YAML::Value << tx_gain_lora[i];
}
out << YAML::EndSeq;
} else if (tx_gain_lora[0] != 0) {
out << YAML::Key << "TX_GAIN_LORA" << YAML::Value << tx_gain_lora[0];
}
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
if (dio3_tcxo_voltage != 0)
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;

View File

@@ -6,6 +6,8 @@ build_flags =
${esp32_base.build_flags}
-D CHATTER_2
-I variants/esp32/chatter2
-DMESHTASTIC_EXCLUDE_WEBSERVER=1
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
lib_deps =
${esp32_base.lib_deps}

View File

@@ -16,6 +16,8 @@ build_flags =
${esp32_base.build_flags}
-I variants/esp32/m5stack_core
-DM5STACK
-DMESHTASTIC_EXCLUDE_WEBSERVER=1
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
-DUSER_SETUP_LOADED
-DTFT_SDA_READ
-DTFT_DRIVER=0x9341

View File

@@ -8,8 +8,7 @@
// DIO6 -> RFSW1_V2
// DIO7 -> not connected on E80 module - note that GNSS and Wifi scanning are not possible.
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_NC,
RADIOLIB_NC};
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_NC, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[] = {
// mode DIO5 DIO6 DIO7

View File

@@ -67,4 +67,8 @@ void variant_shutdown()
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense1);
nrf_gpio_cfg_input(EXT_CHRG_DETECT, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
nrf_gpio_pin_sense_t sense2 = NRF_GPIO_PIN_SENSE_LOW;
nrf_gpio_cfg_sense_set(EXT_CHRG_DETECT, sense2);
}

View File

@@ -1,21 +0,0 @@
; Russell is a board designed to mount on an ER34615/IFR32700 cell and go Up! on a balloon
; Hardware repository: https://github.com/Meshtastic-Malaysia/russell
; - RAK3172 STM32WLE5CCU6 MCU + integrated SX1262 LoRa
; - CDtop CD-PA1010D GPS
; - Bosch Sensortec BME280 sensor
; - Consonance CN3158 LiFePO4 solar charger
[env:russell]
extends = stm32_base
board = wiscore_rak3172
board_level = extra
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
build_flags =
${stm32_base.build_flags}
-Ivariants/stm32/russell
-DPRIVATE_HW
lib_deps =
${stm32_base.lib_deps}
# renovate: datasource=custom.pio depName=Adafruit BME280 packageName=adafruit/library/Adafruit BME280 Library
adafruit/Adafruit BME280 Library@2.3.0
upload_port = stlink

View File

@@ -1,7 +0,0 @@
// Pins from https://forum.rakwireless.com/t/rak3172-internal-schematic/4557/2
// PB8, PC13
static const RADIOLIB_PIN_TYPE rfswitch_pins[5] = {PB8, PC13, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[4] = {
{STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE};

View File

@@ -1,41 +0,0 @@
#ifndef _VARIANT_RUSSELL_
#define _VARIANT_RUSSELL_
#define USE_STM32WLx
// I/O
#define LED_PIN PA0 // Red LED
#define LED_STATE_ON 1
#define BUTTON_PIN PH3 // Shared with BOOT0
#define BUTTON_NEED_PULLUP
// Charger IC charge/standby pins are open-drain with no hardware pull-up:
// Internal pull-up is needed on STM32 (TODO)
// #define EXT_CHRG_DETECT PA5
// #define EXT_PWR_DETECT PA4
// Bosch Sensortec BME280
#define HAS_SENSOR 1
// CDtop CD-PA1010D
#define ENABLE_HWSERIAL1
#define PIN_SERIAL1_RX PB7
#define PIN_SERIAL1_TX PB6
#define HAS_GPS 1
#define PIN_GPS_STANDBY PA15
#define GPS_RX_PIN PB7
#define GPS_TX_PIN PB6
// LoRa
/*
* RAK3172 (-2085°C) -> No TCXO
* RAK3172-T (-4085°C) -> 3.0V TCXO
* https://github.com/RAKWireless/RAK-STM32-RUI/blob/e5a28be8fab1a492bd9223dd425ca33a8a297d90/variants/WisDuo_RAK3172-T_Board/radio_conf.h#L91
*/
#define TCXO_OPTIONAL
#define SX126X_DIO3_TCXO_VOLTAGE 3.0
// Required to avoid Serial1 conflicts due to board definition here:
// https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U/variant_RAK3172_MODULE.h
#define RAK3172
#endif