Merge branch 'meshtastic:develop' into moar_nodes_esp32_s3

This commit is contained in:
Clive Blackledge 2025-09-30 15:03:33 -07:00 committed by GitHub
commit c457a83e57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 73 additions and 51 deletions

View File

@ -9,7 +9,7 @@ plugins:
lint:
enabled:
- checkov@3.2.471
- renovate@41.127.2
- renovate@41.130.1
- prettier@3.6.2
- trufflehog@3.90.8
- yamllint@1.37.1

@ -1 +1 @@
Subproject commit 46b81e822af1b8e408f437092337f129dee693e6
Subproject commit 082bb7cfeb2cba9d41be139cd324c4b43a14b3f9

View File

@ -117,6 +117,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SX126X_MAX_POWER 22
#endif
#ifdef HELTEC_V4
// Power Amps are often non-linear, so we can use an array of values for the power curve
#define NUM_PA_POINTS 22
#define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7
#endif
// Default system gain to 0 if not defined
#ifndef TX_GAIN_LORA
#define TX_GAIN_LORA 0

View File

@ -284,7 +284,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
int iconX = iconRightEdge - mute_symbol_big_width;
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
if (isInverted) {
if (isInverted && !force_no_invert) {
display->setColor(WHITE);
display->fillRect(iconX - 1, iconY - 1, mute_symbol_big_width + 2, mute_symbol_big_height + 2);
display->setColor(BLACK);

View File

@ -852,24 +852,31 @@ void menuHandler::GPSFormatMenu()
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == 1) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else if (selected == 2) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_DMS;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else if (selected == 3) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_UTM;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else if (selected == 4) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_MGRS;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else if (selected == 5) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_OLC;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else if (selected == 6) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_OSGR;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else if (selected == 7) {
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS;
saveUIConfig();
service->reloadConfig(SEGMENT_CONFIG);
} else {
menuQueue = position_base_menu;

View File

@ -1105,6 +1105,18 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
// === Fourth Row: Line 2 GPS Info ===
UIRenderer::drawGpsCoordinates(display, x, getTextPositions(display)[line++], gpsStatus, "line2");
}
// === Final Row: Altitude ===
char altitudeLine[32] = {0};
int32_t alt = (strcmp(displayLine, "Phone GPS") == 0 && ourNode && nodeDB->hasValidPosition(ourNode))
? ourNode->position.altitude
: geoCoord.getAltitude();
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
snprintf(altitudeLine, sizeof(altitudeLine), "Alt: %.0fft", alt * METERS_TO_FEET);
} else {
snprintf(altitudeLine, sizeof(altitudeLine), "Alt: %.0im", alt);
}
display->drawString(x, getTextPositions(display)[line++], altitudeLine);
}
#if !defined(M5STACK_UNITC6L)
// === Draw Compass if heading is valid ===

View File

@ -54,6 +54,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
// We already enqueued the improved copy, so make sure the incoming packet stops here.
return true;
}
// No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid
// delivering the same packet to applications/phone twice with different hop limits.
seenRecently = true;
}
if (seenRecently) {

View File

@ -64,6 +64,10 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
// We already enqueued the improved copy, so make sure the incoming packet stops here.
return true;
}
// No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid
// delivering the same packet to applications/phone twice with different hop limits.
seenRecently = true;
}
if (seenRecently) {

View File

@ -834,7 +834,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#ifdef USERPREFS_NETWORK_ENABLED_PROTOCOLS
config.network.enabled_protocols = USERPREFS_NETWORK_ENABLED_PROTOCOLS;
#else
config.network.enabled_protocols = 1;
config.network.enabled_protocols = 0;
#endif
#endif
@ -1919,9 +1919,6 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
return false;
}
LOG_INFO("Public Key set for node, not updating!");
// we copy the key into the incoming packet, to prevent overwrite
p.public_key.size = 32;
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
} else if (p.public_key.size == 32) {
LOG_INFO("Update Node Pubkey!");
}

View File

@ -674,11 +674,25 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
power = maxPower;
}
#ifndef NUM_PA_POINTS
if (TX_GAIN_LORA > 0) {
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, TX_GAIN_LORA);
power -= TX_GAIN_LORA;
}
#else
// we have an array of PA gain values. Find the highest power setting that works.
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))) {
// 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];
break;
}
}
#endif
if (power > loraMaxPower) // Clamp power to maximum defined level
power = loraMaxPower;

View File

@ -108,7 +108,7 @@ bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
// For subsequent hops, check if previous relay is a favorite router
// Optimized search for favorite routers with matching last byte
// Check ordering optimized for IoT devices (cheapest checks first)
for (int i = 0; i < nodeDB->getNumMeshNodes(); i++) {
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
if (!node)
continue;
@ -123,7 +123,7 @@ bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
// Check 3: role check (moderate cost - multiple comparisons)
if (!IS_ONE_OF(node->user.role, meshtastic_Config_DeviceConfig_Role_ROUTER,
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_CLIENT_BASE)) {
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)) {
continue;
}
@ -501,35 +501,6 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p)
}
}
#if HAS_UDP_MULTICAST
// Fallback: for UDP multicast, try default preset names with default PSK if normal channel match failed
if (!decrypted && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MULTICAST_UDP) {
if (channels.setDefaultPresetCryptoForHash(p->channel)) {
memcpy(bytes, p->encrypted.bytes, rawSize);
crypto->decrypt(p->from, p->id, rawSize, bytes);
meshtastic_Data decodedtmp;
memset(&decodedtmp, 0, sizeof(decodedtmp));
if (pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &decodedtmp) &&
decodedtmp.portnum != meshtastic_PortNum_UNKNOWN_APP) {
p->decoded = decodedtmp;
p->which_payload_variant = meshtastic_MeshPacket_decoded_tag;
// Map to our local default channel index (name+PSK default), not necessarily primary
ChannelIndex defaultIndex = channels.getPrimaryIndex();
for (ChannelIndex i = 0; i < channels.getNumChannels(); ++i) {
if (channels.isDefaultChannel(i)) {
defaultIndex = i;
break;
}
}
chIndex = defaultIndex;
decrypted = true;
} else {
LOG_WARN("UDP fallback decode attempted but failed for hash 0x%x", p->channel);
}
}
}
#endif
if (decrypted) {
// parsing was successful
p->channel = chIndex; // change to store the index instead of the hash

View File

@ -80,6 +80,9 @@ template <typename T> bool SX126xInterface<T>::init()
RadioLibInterface::init();
limitPower(SX126X_MAX_POWER);
// Make sure we reach the minimum power supported to turn the chip on (-9dBm)
if (power < -9)
power = -9;
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO);
// \todo Display actual typename of the adapter, not just `SX126x`
@ -118,8 +121,8 @@ template <typename T> bool SX126xInterface<T>::init()
LOG_DEBUG("Set DIO2 as %sRF switch, result: %d", dio2AsRfSwitch ? "" : "not ", res);
}
// If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has
// no effect
// If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has
// no effect
#if ARCH_PORTDUINO
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", portduino_config.lora_rxen_pin.pin,

View File

@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size
#define meshtastic_ChannelSet_size 679
#define meshtastic_ChannelSet_size 695
#ifdef __cplusplus
} /* extern "C" */

View File

@ -97,6 +97,8 @@ typedef struct _meshtastic_ChannelSettings {
/* Per-channel module settings. */
bool has_module_settings;
meshtastic_ModuleSettings module_settings;
/* Whether or not we should receive notifactions / alerts through this channel */
bool mute;
} meshtastic_ChannelSettings;
/* A pair of a channel number, mode and the (sharable) settings for that channel */
@ -128,10 +130,10 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default}
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0}
#define meshtastic_ModuleSettings_init_default {0, 0}
#define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN}
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero}
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0}
#define meshtastic_ModuleSettings_init_zero {0, 0}
#define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN}
@ -145,6 +147,7 @@ extern "C" {
#define meshtastic_ChannelSettings_uplink_enabled_tag 5
#define meshtastic_ChannelSettings_downlink_enabled_tag 6
#define meshtastic_ChannelSettings_module_settings_tag 7
#define meshtastic_ChannelSettings_mute_tag 8
#define meshtastic_Channel_index_tag 1
#define meshtastic_Channel_settings_tag 2
#define meshtastic_Channel_role_tag 3
@ -157,7 +160,8 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \
X(a, STATIC, SINGULAR, FIXED32, id, 4) \
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \
X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7)
X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \
X(a, STATIC, SINGULAR, BOOL, mute, 8)
#define meshtastic_ChannelSettings_CALLBACK NULL
#define meshtastic_ChannelSettings_DEFAULT NULL
#define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings
@ -187,8 +191,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size
#define meshtastic_ChannelSettings_size 72
#define meshtastic_Channel_size 87
#define meshtastic_ChannelSettings_size 74
#define meshtastic_Channel_size 89
#define meshtastic_ModuleSettings_size 8
#ifdef __cplusplus

View File

@ -26,7 +26,8 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT = 3,
/* Description: Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list.
Technical Details: Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry
or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. */
or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate.
Deprecated in v2.7.11 because it creates "holes" in the mesh rebroadcast chain. */
meshtastic_Config_DeviceConfig_Role_REPEATER = 4,
/* Description: Broadcasts GPS position packets as priority.
Technical Details: Position Mesh packets will be prioritized higher and sent more frequently by default.

View File

@ -360,8 +360,8 @@ 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 2277
#define meshtastic_ChannelFile_size 718
#define meshtastic_BackupPreferences_size 2293
#define meshtastic_ChannelFile_size 734
#define meshtastic_DeviceState_size 1737
#define meshtastic_NodeInfoLite_size 196
#define meshtastic_PositionLite_size 28

View File

@ -224,7 +224,7 @@ extern struct portduino_config_struct {
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
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 << dio3_tcxo_voltage;
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
if (lora_usb_pid != 0x5512)
out << YAML::Key << "USB_PID" << YAML::Value << YAML::Hex << lora_usb_pid;
if (lora_usb_vid != 0x1A86)

View File

@ -8,4 +8,3 @@ build_flags =
-D HELTEC_V4
-I variants/esp32s3/heltec_v4
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-D SX126X_MAX_POWER=11