Commit Graph
247 Commits
Author SHA1 Message Date
TomandGitHub 2024bb8384 Arrival time fix perhaps (#11274)
* Add explicit presence for MeshPacket.rx_time (arrival time)

rx_time is now proto3 optional with a has_rx_time presence bit, matching
the rx_rssi treatment. A node with no GPS and no phone connected yet has
no time source at all, so a bare 0 was indistinguishable from a genuine
1970-01-01 reading; downstream consumers (replay packets, JSON
serialization) now check has_rx_time instead of the value.

* Dedupe rx_time stamping into a shared helper; trim a debug log string

Extract the repeated haveTime/rx_time/has_rx_time stamp logic (5 call
sites across Router.cpp, MeshBeaconModule.cpp, MeshService.cpp) into
Router::computeRxTimeStamp()/stampRxTime(). Also shorten the new RTC.cpp
LOG_DEBUG string. Saves 48 bytes of flash on rak4631 (measured), no
behavior change.

* Fix has_rx_rssi presence carried unconditionally through StoreForward replay

preparePayload() set has_rx_rssi = true unconditionally on replay, regardless
of whether the packet's rx_rssi at store time was a genuine measurement (e.g.
MQTT-relayed packets carry no real RSSI). Store the presence bit alongside
rx_rssi in PacketHistoryStruct and restore it on replay instead.

Flagged by Copilot on #11271 (same root cause the has_rx_time explicit
presence work fixes) but never addressed before that PR merged.

* Trim comment blocks to the repo's 1-2 line guideline

.github/copilot-instructions.md:338 caps code comments at 1-2 lines; several
blocks added across the rx_time explicit-presence work ran well past that.
Also consolidates Time.cpp's file-level doc comment into Time.h, where the
rest of the Time:: API contract already lives.

No behavior change.

* Add rx_time explicit-presence test coverage

- test_meshpacket_serializer: has_rx_time=false fixture plus tests asserting
  JsonSerialize/JsonSerializeEncrypted emit 0 rather than leaking the
  millis() placeholder, alongside the has_rx_time=true baseline.
- test_stream_api: two tests driving a real PhoneAPI handshake (want_config_id
  through STATE_SEND_PACKETS) that simulate a phone time-giving transaction
  arriving before vs. after a queued packet is drained - covering both the
  reconciled and the ships-with-placeholder-absent paths of
  MeshService::reconcilePendingRxTimes().

* Fix three correctness issues flagged in review

- Time.h: drop the reserved-identifier include guard (_MT_TIME_H); pragma
  once already covers it, matching convention elsewhere (e.g. RTC.h).
- Time.cpp: rebase getMillis64()'s wrap accumulator when the test seam
  swaps clock sources, so a real<->injected clock jump isn't miscounted
  as a genuine 32-bit wrap.
- NodeInfoModule: the 12h reply-suppression window is a local dedup
  duration, not a wall-clock reading - switch it to Time::getMillis64()
  so RTC-quality jumps and replayed packets' stale rx_time can't perturb
  it.
- StoreForwardModule: has_rx_time was derived from *current* RTC quality
  at replay time rather than stored at capture time, so a history entry
  saved while time-blind could be misreported as a valid epoch once the
  clock later improved. Persist the presence bit in PacketHistoryStruct
  instead.

* tryfix CI

* post review fixes

* more test fixes
2026-07-29 14:03:25 +00:00
TomandGitHub 2c57a17124 Phantom node fix perhaps (#11271)
* trying to fix phantom nodes

* fix comment spam

* oops - missed one
2026-07-28 18:32:18 +00:00
1e982fa78c Sign plaintext packets in licensed mode (#10969)
* feat: sign licensed plaintext packets

Preserve and publish identity keys in licensed mode so existing XEdDSA signatures can authenticate plaintext traffic. Sign licensed broadcasts and direct messages when they fit, while keeping PKI encryption disabled and normal routing behavior unchanged.

* fix(security): persist licensed channel sanitation

* fix(security): close licensed migration lifecycle gaps

* fix(security): address licensed signing review feedback

* test: restore signing globals from Unity teardown

* fix(baseui): allow confirmed ham region selection

* fix(baseui): guard region picker validation

* style: trunk fmt

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Austin <vidplace7@gmail.com>
2026-07-27 02:57:15 +00:00
TomandGitHub b8b5582943 Regioninfo (#11056)
* advertise a superset of EU regional presets to client devices.

* trunk
2026-07-19 06:22:39 -05:00
36bfb86937 Remove UA_868 as obsolete (#10994)
Decree of the Cabinet of Ministers of Ukraine dated February 25, 2026,*
No. 262, on amendments to Section 2 of the Plan for the Allocation and
Use of the Radio Frequency Spectrum in Ukraine, has harmonised
Ukrainian regulations on the 868 MHz spectrum with the EU's, thereby
making UA_868 legally obsolete.

* https://zakon.rada.gov.ua/laws/show/262-2026-п

Co-authored-by: Tom <116762865+NomDeTom@users.noreply.github.com>
2026-07-16 08:52:50 -05:00
Ben MeadorsandGitHub c5355641d3 Add MEDIUM_TURBO modem preset (#10988)
* Protobufs

* Wire up MEDIUM_TURBO modem preset

MEDIUM_TURBO (500 kHz, SF9, CR 4/5) already existed in the protobuf enum but
was never wired into firmware, so selecting it silently fell through to the
LONG_FAST default and rendered an "Invalid" display name.

Add its bw/sf/cr mapping (modemPresetToParams), display name (MediumTurbo/MedT),
PRESETS_STD membership (standard regions only — 500 kHz does not fit EU868's
250 kHz band, so it stays out of PRESETS_EU_868 and is rejected/clamped there),
and the MEDIUM SNR-grading bucket. Includes positive coverage in test_radio,
EU868-reject + US-accept coverage in test_admin_radio and test_mesh_beacon,
the STD preset count 9->10, an extended fuzz range, and the client-spec doc.

* Address review feedback on MEDIUM_TURBO tests

- test_mesh_beacon: assert has_mesh_beacon before checking the invalid preset was
  cleared, so the EU868-cleared test can't pass on a dropped message (matches the
  existing SHORT_TURBO test).
- test_fuzz_packets: draw modem presets from _ModemPreset_ARRAYSIZE instead of a
  hard-coded 17 so the fuzz range tracks future enum additions automatically.
2026-07-11 08:24:35 -05:00
ManuelandGitHub f52e2ea8ef fix SPI1 instances (#10983) 2026-07-10 15:00:32 -05:00
Ben MeadorsandGitHub 97302f1845 Add Meshnology W10 AIOT Dev Kit (SX1262 via MCP23017 I2C expander) (#10911)
* Add software LoRa IRQ polling and an MCP23017 expander HAL for radios behind an I2C expander

Some boards route the SX126x control lines (NRESET/DIO1/BUSY) through an I2C
GPIO expander instead of native GPIOs, and don't wire the expander's /INT to
the MCU, so RadioLib cannot take a hardware DIO1 interrupt.

Two reusable pieces, both gated behind USE_MCP23017 / LORA_DIO1_SOFTWARE_POLL
so builds that don't define them are unaffected:

- ExtensionIOMCP23017 + MCP23017LockingArduinoHal: a RadioLib HAL that maps
  virtual pins (MCP23017_VPIN_BASE .. +15) onto an MCP23017's GPIO, so
  RESET/BUSY/DIO1 reads and writes become I2C transactions while the real SPI
  GPIOs (SCK/MOSI/MISO/CS) pass straight through. A failed I2C read skips the
  read-modify-write rather than clobbering the rest of the bank.
- LORA_DIO1_SOFTWARE_POLL: with no DIO1 interrupt available, the SX126x
  interface polls the radio IRQ status register from the radio thread and
  synthesizes the ISR_TX/ISR_RX events, filtering noisy preamble/header IRQs so
  they can't starve TX. A 1 ms ISR_POLL_TICK drives the poll; TX timers may
  overwrite the pending tick (pollMissedIrqs() is the backup that bounds the
  latency of the busy-Rx contention window). Behaviour is unchanged on all
  boards that keep the hardware interrupt.

* Add Meshnology W10 AIOT Dev Kit variant (SX1262 via MCP23017 expander)

ESP32-S3R8 + EBYTE E22-900MM22S (SX1262) + AXP2101 PMIC + Quectel L76KB GPS +
SPI TFT, with the radio's RESET/DIO1/BUSY and the LCD reset routed through an
MCP23017 I2C expander at 0x20. The expander's /INT is not wired to the ESP32,
so DIO1 uses the software poll. Pins come from the board schematic and the
vendor firmware; the expander is an MCP23017 despite the V1.1 schematic's stale
'TCA9555' label (the V1.2 placement diagram and all vendor code use the MCP23017
register map).

A local pins_arduino.h shadows the generic esp32s3 variant to drop RGB_BUILTIN,
which otherwise pulls the Arduino RMT HAL into the link and fails against this
build's trimmed FreeRTOS config.

Reports HardwareModel 140 (MESHNOLOGY_W10, already present in the protobufs).

Hardware-verified on a real W10 AIOT Dev Kit: AXP2101 PMU, MCP23017, SX1262
init + a full over-the-air TX/RX round trip through the expander, PCF85063 RTC,
SHT41 and QMI8658 auto-detected, and an L76KB GPS fix.

* meshnology-w10: enable ES8311 speaker for notification tones

Bring up the ES8311 codec (I2C 0x18) -> NS4150 amp -> speaker so the board can
play notification tones / ringtones over the I2S buzzer path (the
use_i2s_as_buzzer external-notification option). Codec2 voice stays out of
scope: it is SX1280-only and this is a sub-GHz board.

- variant.h: HAS_I2S + DAC_I2S pins (MCLK=1, BCK=2, WS=4, DOUT=5, DIN=3)
- platformio.ini: arduino-audio-driver + ESP8266Audio + ESP8266SAM
- extra_variants/meshnology_w10/variant.cpp: lateInitVariant() configures the
  ES8311, mirroring the other Meshtastic ES8311 boards. Kept codec-only (no
  main.h) so the audio driver's 'using namespace audio_driver' does not pull a
  conflicting GpioPin into scope alongside Meshtastic's class GpioPin.
- AudioThread.h: toggle the NS4150 amp (MCP23017 EXIO_PA_CTRL) around playback.

Verified on hardware: a test tune played audibly through the speaker.

* meshnology-w10: address review feedback on the MCP23017 driver

- ExtensionIOMCP23017: serialize register access with a mutex, since the radio
  HAL (BUSY/DIO1/RESET) and AudioThread (amp enable) now reach the expander from
  different threads and the read-modify-write paths are not atomic.
- digitalRead: return a fail-safe HIGH on a failed read instead of LOW, so a
  transient I2C error on the LoRa BUSY line can't look like 'ready' and let
  RadioLib start an SPI transaction early. (DIO1 is polled via the radio IRQ
  register, not this pin.)
- enablePinChangeInterrupt: use the checked readReg() overload and skip on a
  failed read, matching the other read-modify-write helpers.
- meshnology_w10 variant.cpp: log a warning if an ES8311 register write NACKs
  instead of silently leaving the codec half-configured.
- RadioInterface.cpp: guard the MCP23017 HAL branch with ARCH_ESP32 to match the
  include and driver-file guards.

* Replace board-model audio/sleep ifdefs with reusable variant capability macros

Two shared-code spots keyed off specific hardware models; move the board-specific
detail into opt-in macros the variants define, so the core code stays generic and
new boards can opt into the behavior class without touching shared files.

- AudioThread amp control: drop the T_LORA_PAGER / MESHNOLOGY_W10 ifdefs. A board
  with an I2S amp now defines AUDIO_AMP_ENABLE(on) in its variant.h (T-LoRa Pager
  and Meshnology W10 do), and AudioThread just calls it around playback. The
  expander includes are keyed on USE_XL9555 / USE_MCP23017 (capabilities) instead
  of the model name.

- Light-sleep / DIO1 wakeup: drop the SENSECAP_INDICATOR check. Boards whose
  LORA_DIO1 is an expander pin (not an ESP32 GPIO) define LORA_DIO1_EXTENDED_IO
  (SenseCAP Indicator and Meshnology W10), and sleep.cpp keys off that for both
  the light-sleep skip and the DIO1 GPIO-wakeup skip. This also fixes a latent
  issue on the SenseCAP: it previously reached the GPIO-wakeup path and called
  gpio_pulldown_en() on a virtual expander pin; it now skips that cleanly.

Builds verified on meshnology_w10, tlora-pager, and seeed-sensecap-indicator.

* meshnology-w10: silence cppcheck constParameterPointer on the ISR-callback helper

isIsrTxCallback() takes a function pointer it only compares; cppcheck's
constParameterPointer wants it 'pointer to const', which is meaningless for a
function pointer (the codebase already globally suppresses the sibling
constParameterCallback). Inline-suppress it to keep the check green.

* HopScaling: qualify the member assignment as this->count

cppcheck (CI's version) flags 'count = newCount;' at the end of trimIfNeeded()
as uselessAssignmentArg ('assignment of function parameter has no effect') - a
false positive, since count is a member that outlives the call. Write it as
this->count (matching the Step-1 assignment above) so the analyzer sees a member
write. This finding comes in via the develop merge, not this board; fixing it
here to unblock the PR's cppcheck check.
2026-07-07 09:58:54 -05:00
d846780a9b More fuzz tests and small fixes for the findings (#10864)
* first pass tests

* more tests

* Fix two crafted-admin-packet crashes found by the E5 fuzzer

Both are reachable from an authorized admin (local from==0, admin channel,
or PKC) - remote DoS:

1. SIGFPE in LoRa config validation. A set_config LoRaConfig with
   use_preset=false and bandwidth=0 makes freqSlotWidth 0, so numFreqSlots
   is 0 and `hash(name) % numFreqSlots` (RadioInterface.cpp) divides by
   zero. Guard the modulo; the existing channel_num check then rejects/
   clamps the config.

2. Stack overflow in Channels::getKey. A SECONDARY channel at the primary
   slot with an empty PSK recursed into getKey(primaryIndex) forever. Skip
   the primary-key borrow when chIndex == primaryIndex.

Re-enable the E5 admin fuzzer to hit both triggers again (use_preset both
ways incl. bandwidth 0, plus the set_channel tag) as regression guards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Correct fuzz-test invariants after the crash fixes

- E5 admin fuzz: node eviction under a filling NodeDB is legitimate, so
  assert only the bounded-count invariant, not that a specific seed node
  survives 6000 mutating ops.
- TMM blitz: scope off the nodeinfo direct-response send path (it needs a
  fully-wired MeshService/phone queue the fixture doesn't provide; the
  deterministic directResponse tests cover it). The crafted-nodenum
  rate/unknown/position cache stress is unchanged.

clod helped too

* realistic tests

* test: dedup fuzz RNG into shared test/support/DeterministicRng.h

The four in-tree fuzz suites (test_fuzz_decode, test_fuzz_packets,
test_hop_scaling, test_traffic_management) each carried a byte-identical
copy of the seeded 64-bit LCG (rngSeed/rngNext/rngByte/rngRange). Hoist
it into one shared header so there is a single generator to reason about
and no risk of the copies drifting. static inline keeps per-suite state
per translation unit and avoids -Wunused-function for suites that don't
use every helper. Also corrects a stale comment in test_traffic_management
(the blitz's nodeinfo direct-response path is intentionally left off).

No behavioral change: same constants, same per-suite seeds.

clod helped too

* test: fuzz uncovered ProtobufModule handlers and the MQTT downlink ingress

Extend the in-tree fuzz coverage to packet sources that previously had
none:

- test_fuzz_packets E8/E9/E10: drive PositionModule, DeviceTelemetryModule
  and NeighborInfoModule at handleReceivedProtobuf directly (via using-shims,
  bypassing the ProtobufModule reply/send path so no router is needed). The
  fixture already stands up nodeDB/service/channels, and nodeStatus/powerStatus
  are auto-initialized in main.cpp, so no new globals are required. Adds a
  shared fuzzRxHeader() helper for crafting adversarial RX packet headers.
- test_fuzz_decode: add meshtastic_KeyVerification to the decode table. The
  KeyVerification and StoreForward handler paths are documented as decode-level
  only, with the concrete reason each is intrinsic (private-state gating /
  PSRAM + self-pointer wiring), not a fixture gap.
- test_mqtt: test_receiveFuzzServiceEnvelope blitzes the non-RF broker-push
  ingress (onReceiveProto) two ways - raw garbage bytes that must fail envelope
  decode cleanly, and a well-formed ServiceEnvelope wrapping a crafted inner
  MeshPacket over crafted channel_id/gateway_id - exercising the channel match,
  isFromUs, XEdDSA receive policy and perhapsDecode chain. Adds a deliverRaw()
  passthrough to MQTTUnitTest.

All under the coverage env (ASan/LSan). No firmware/src changes. Full sweep
GREEN 27/27, 544 cases.

clod helped too

* Harden LoRa/channel config against crafted admin messages; consolidate test helpers

Production (review findings on the hot-fuzz crash fixes):
- Clamp bandwidth at the source (clampBandwidthKHz) in checkOrClampConfigLora
  and applyModemConfig so numFreqSlots can never be 0 for any consumer; a
  bandwidth-0 set_config previously passed validation and re-armed the SIGFPE
  on the next applyModemConfig.
- Guard applyModemConfig's hash % numFreqSlots (the validator's sibling modulo
  was fixed earlier but this one was still unguarded).
- Enforce the primary-channel invariant in Channels::onConfigChanged: a config
  demoting every slot now re-promotes the stale SECONDARY slot (keeping its
  key) or restores the default channel if the slot is DISABLED, instead of
  leaving every getPrimaryIndex() reader on a non-primary slot. The getKey
  recursion guard stays as defense-in-depth.

Tests:
- New test/support/MockMeshService.h and AdminModuleTestShim.h replace four
  byte-identical mocks and three divergent admin shims (test_mqtt's capturing
  mock is genuinely different and stays).
- DeterministicRng.h: add rngFill() (replaces 14 hand-rolled fill loops) and
  rngEdgeNodeNum() (unifies the three NodeNum boundary pools).
- Extract fuzzChannelSettings() shared by the set_channel case and fuzzBeacon.
- fuzzBeacon: the un-terminated branch now fills the whole buffer with non-NUL
  bytes so the strnlen bound is actually stressed (~50% of iterations, not ~4%).
- E6 beacon fuzz: replace the TEST_ASSERT_TRUE(true) tautology with real
  invariants (handler never consumes; offers land in lastReceivedOffer keyed
  to the sender).
- Trim the seven over-long comment blocks flagged against the 1-2 line rule;
  the FINDINGS trailer moves to this commit message (see production notes).

Full native suite GREEN 27/27 under the coverage (ASan/LSan) env.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Clamp UTF-8 char length in the emote walkers; add test_fuzz_emotes

A TEXT_MESSAGE payload is opaque protobuf bytes, so PB_VALIDATE_UTF8 never
screens it - invalid UTF-8 and truncated multi-byte lead bytes reach the
emote/width render path verbatim. EmoteRenderer's walkers advanced by
utf8CharLen(lead) without clamping to the bytes actually remaining, so a
truncated lead (e.g. a lone 0xF0, which claims 4 bytes) near the end of the
buffer made getUtf8ChunkWidth's memcpy read past the string. ASan confirms a
heap-buffer-overflow READ from measureStringWithEmotes.

Add utf8CharLenClamped() and use it at every walk site (width measure,
truncation cut-loop, and the draw-path text-run/chunk builders); the one
already-guarded site (matchAtIgnoringModifiers) is unchanged.

New test/test_fuzz_emotes drives measureStringWithEmotes and truncateToWidth
over adversarial byte strings (biased to embed/end in truncated multi-byte
leads) in exact-sized heap buffers so any over-read is a hard ASan fault. Its
headless display uses a synthetic font (firstChar 0, fontData centered in a
large buffer) so the stock OLEDDisplay::getStringWidth - which indexes the
font jump table with a signed char and over-reads for any byte >= 0x80 - does
not mask the finding. native-suite-count bumped 27 -> 28.

Full native suite GREEN 28/28 under the coverage (ASan/LSan) env.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Keep emote width measurement in-bounds for non-ASCII bytes

OLEDDisplay::getStringWidth (the utf8=false path EmoteRenderer uses on default
builds) indexes the font jump table by (c - firstChar) with a signed char and
no bounds check, so any byte outside printable ASCII - high bytes from UTF-8
text, but also a stray control byte like 0x0A - reads outside the font array.
On-device this reads adjacent flash and returns a garbage width; under ASan the
test_fuzz_emotes fuzzer flags it as a global-buffer-overflow, and it made the
non-ASCII width measurement meaningless either way.

The OLED driver is a pinned upstream dependency, so guard it firmware-side in
EmoteRenderer's getStringWidth helper: measure a sanitized copy where any byte
outside [0x20, 0x7E] counts as a '?' placeholder. Printable ASCII is unchanged
and the UA/RU lookup path is untouched.

test_fuzz_emotes now drives a real ArialMT font instead of the synthetic
in-bounds font it needed before this fix, so the suite exercises the true
production width path (utf8CharLen clamp + this sanitizer) end to end. The same
fuzzer tripped the global-buffer-overflow before this change.

Full native suite GREEN 28/28 under the coverage (ASan/LSan) env.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 13:19:01 -05:00
TomandGitHub c8f2ea16f0 ugh (#10874) 2026-07-03 18:57:42 -05:00
AustinandGitHub 397ff8523a Add 70cm amateur radio region support (#10627) 2026-07-03 10:00:14 +02:00
TomandGitHub 3becaf2d95 emdashes begone (#10847) 2026-07-01 19:01:27 -05:00
TomandGitHub fd62322876 Log tidy (#10798)
* clarify channel number formatting and fix the fixed-width padded nodeIDs

* use the explicit 0x%08x for packets and nodeIDs throughout

* LLM instructions
2026-06-30 12:44:25 -05:00
Ben MeadorsandGitHub dd1ec9d462 Lora region preset map (#10736)
* Added lora region and preset maps

* Protos

* Address PR review feedback

- Log (and break/skip) when the region preset map exceeds its array bounds
  instead of silently dropping regions
- Derive test bounds from the generated nanopb array sizes via sizeof()
  instead of hard-coded magic numbers
- Fix want_config sequence comment (missing comma, STATE_SEND_MODULECONFIG)
- Specify a language on the spec's fenced code blocks (markdownlint MD040)

* Fix want_config stall: handle STATE_SEND_REGION_PRESETS in PhoneAPI::available()

available() had a separate per-state switch that wasn't updated for the new
state, so it returned false ('unexpected state 5') and getFromRadio() was
never called - the config handshake stalled after metadata and the client
timed out. Verified via the native simulator integration test.
2026-06-19 19:56:24 -05:00
Jonathan BennettandBen Meadors bede05356d Lora led rx (#10674)
* add optional LED_LORA to indicate LoRa TX

* Briefly flash LED_LORA on packet RX

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-06-13 12:18:22 -05:00
TomandGitHub ab882c5619 EU regions merge (#10675)
* stronger together

* validate 2.4ghz regions

* less noise

* you're right, and that shapens the analysis significantly

* sassy rejoinder
2026-06-10 18:37:14 +01:00
AustinandGitHub 57f678240d Add 1.25 Meter '125cm' amateur radio region support (#10638) 2026-06-06 07:43:49 -05:00
AustinandGitHub ef51c7ec11 Add 2 Meter (~144mhz) Amateur Radio Regions (#10623)
Default slots:
ITU1_2M: Slot 26 (144.510 MHz)
ITU2_2M: Slot 51 (145.010 MHz)
ITU3_2M: Slot 33 (144.650 MHz)
2026-06-03 18:05:03 -04:00
AustinandGitHub 3e873c51b7 Add TinyFast and TinySlow presets to modem configuration and menu actions (#10597) 2026-06-03 16:42:39 +01:00
nomdetom 5d55353939 Some fixes and tidies for testing both online and in unit_tests 2026-06-03 02:47:23 +01:00
vidplace7andCopilot 178ae0a7f1 Move overrideSlot from RegionProfile to RegionInfo (override per-region)
Move default frequency (slot) override from RegionProfile to RegionInfo (set per-region).

This is usually set to `0`, but will be especially useful for Ham modes where each region default must fit within a band plan.

Co-authored-by: Copilot <copilot@github.com>
2026-05-30 16:20:17 -04:00
5e69bc6c3f Enable Narrow and Lite regions for EU (#10120)
* Enable Lite and Narrow regions and introduce getEffectiveDutyCycle for Lite profiles

* Add TrafficType enum and extend getConfiguredOrDefaultMsScaled to manage based on regionProfile settings

* Refactor telemetry modules to include TrafficType in getConfiguredOrDefaultMsScaled calls

* Update submodule protobufs to latest commit

* Add support for new region presets and modem presets in menu options

* Add new LoRa region codes and modem presets for EU bands

* boof

* Add modem presets for LITE and NARROW configurations

* Update subproject commit reference in protobufs

* Update protobufs

* Refactor modem preset definitions to use macro for consistency and clarity

* Refactor modem preset cases to use PRESET macro for consistency

* fix: update LoRa region code for EU 868 narrowband configuration

Co-authored-by: Copilot <copilot@github.com>

* Fix test suite failure

Co-authored-by: Copilot <copilot@github.com>

* Add override slot override - for when one override isn't enough.

Co-authored-by: Copilot <copilot@github.com>

* address copilot comments

---------

Co-authored-by: Copilot <copilot@github.com>
2026-05-21 10:20:09 -05:00
5e2ca8aed4 LR2021 radio on NRF_Promicro (#10401)
* LR2021 radio on NRF_Promicro

Co-authored-by: Copilot <copilot@github.com>

* Refactor LR2021 interface includes and conditional compilation for improved clarity

Co-authored-by: Copilot <copilot@github.com>

* Refactor LR20x0 interface: remove unused includes and update comments for clarity

* Fix LR2021 max power definitions and add radio type detection tests

* remove potato radio type detection tests

* Include placeholder for DCDC - currently requires godmode

* Added godmode features - not enabled by default

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-05-07 20:24:39 -05:00
TomandGitHub a3b49b9028 Add powerlimits to reconfigured radio settings as well as init settings. (#10025)
* Add powerlimits to reconfigured radio settings as well as init settings.

* Refactor preamble length handling for wide LoRa configurations

* Moved the preamble setting to the main class and made the references static
2026-04-09 16:18:05 -05:00
Ben Meadors 1116f06139 Merge remote-tracking branch 'origin/master' into develop 2026-04-08 13:37:25 -05:00
222d3e6b62 Fix zero CR and add unit tests for applyModemConfig coding rate behavior (#10070)
* Fix zero CR and add unit tests for applyModemConfig coding rate behavior

* Apply suggestion from @Copilot

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

* fix: initialize region configuration in setUp for RadioInterface tests

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-04 08:27:39 +11:00
Kittiwut KhongkaeoandGitHub 7f0cd70c07 Align 920–925 MHz limits as per NBTC in Thailand (27 dBm, 10% duty cycle) (#9827) 2026-04-03 08:27:36 +11:00
22d63fa69c Lora settings expansion and validation logic improvement (#9878)
* Enhance LoRa configuration with modem presets and validation logic

* Rename bootstrapLoRaConfigFromPreset tests to validateModemConfig for clarity and consistency

* additional tidy-ups to the validateModemConfig - still fundamentally broken at this point

* Enhance region validation by adding numPresets to RegionInfo and implementing validateRegionConfig in RadioInterface

* Add validation for modem configuration in applyModemConfig

* Fix region unset handling and improve modem config validation in handleSetConfig

* Refactor LoRa configuration validation methods and introduce clamping method for invalid settings

* Update handleSetConfig to use fromOthers parameter to either correct or reject invalid settings

* Fix some of the copilot review comments for LoRa configuration validation and clamping methods; add tests for region and preset handling

* Redid the slot default checking and calculation. Should resolve the outstanding comments.

* Add bandwidth calculation for LoRa modem preset fallback in clampConfigLora

* Remove unused preset name variable in validateConfigLora and fix default frequency slot check in applyModemConfig

* update tests for region handling

* Got the synthetic colleague to add mock service for testing

* Flash savings... hopefully

* Refactor modem preset handling to use sentinel values and improve default preset retrieval

* Refactor region handling to use profile structures for modem presets and channel calculations

* added comments for clarity on parameters

* Add shadow table tests and validateConfigLora enhancements for region presets

* Add isFromUs tests for preset validation in AdminModule

* Respond to copilot github review

* address copilot comments

* address null poointers

* fix build errors

* Fix the fix, undo the silly suggestions from synthetic reviewer.

* we all float here

* Fix include path for AdminModule in test_main.cpp

* Potential fix for pull request finding

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

* More suggestion fixes

* admin module merge conflicts

* admin module fixes from merge hell

* fix: initialize default frequency slot and custom channel name; update LNA mode handling

* save some bytes...

* fix: simplify error logging for bandwidth checks in LoRa configuration

* Update src/mesh/MeshRadio.h

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

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-20 07:43:47 -05:00
5ced739a57 Add heltec-v4.3 board (#9753)
* Add heltec-v4.3 board

* Modify LNA control display content

* Fix Heltec Tracker v2 FEM control

* Use trunk to fix formatting issues.

* Optimize the fem initialization control logic.

* Update src/mesh/RadioInterface.h change #ifdef to #if

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

* Change LORA_PA_EN to LORA_GC1109_PA_EN.

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

* Remove the NodeDB.h include.

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

* Change tx_gain to a const variable.

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

* Fixed the issue where ARCH_PORTDUINO lacked the NUM_PA_POINTS macro.

* Remove the comment.

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

* Move #pragma once to the first line.

* Remove the FEM LNA control menu.

* Add description for KCT8103L.

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-03-04 06:27:12 -06:00
b7bf251798 Scaling tweaks (#9653)
* refactor: update throttling factor calculation and add unit tests for scaling behavior

* refactor: adjust throttling factor calculation for improved accuracy in different configurations

* Update src/mesh/Default.h

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

* Update src/mesh/Default.h

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

* refactor: enhance throttling factor calculation and introduce pow_of_2 utility function

* refactor: improve expected ms calculation in unit tests for Default::getConfiguredOrDefaultMsScaled

* refactor: improve scaling logic for routers and sensors in computeExpectedMs function

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-04 05:59:42 -06:00
Thomas GöttgensandGitHub 56fd9c7813 fix a lot of low level cppcheck warnings (#9623)
* simplify the observer pattern, since all the called functions are const getters.
* use arduino macro over std: for numerical values and refactor local variables in drawScrollbar()
* oh, so Cppcheck actually complained about const pointers not being const.
* slowly getting out of ifdef hell
* fix inkHUD warnings as well
* last 2 check warnings
* git checks should fail on low defects from now on
2026-02-16 12:28:07 +01:00
JorropoandGitHub ff485d5ff8 replace delete in RadioInterface.cpp with std::unique_ptr (#9645)
Is part of the unique_ptr modernization effort.
2026-02-14 21:39:26 +01:00
Thomas GöttgensandGitHub f96a8593f2 fix some random compiler warnings (#9596) 2026-02-11 06:43:05 -06:00
Jonathan Bennett eeb7373043 Remove errant symbol 2026-01-29 13:23:49 -06:00
Ben Meadors 0770f25e79 Merge remote-tracking branch 'origin/master' into develop 2026-01-26 08:56:38 -06:00
Jonathan BennettandGitHub 8a9830282a Move Lora Init code into LoraInit.cpp/h (#9435)
* Move Lora Init code into LoraInit.cpp/h

* Add missed extern definition

* More carefully check for nullptr in LoraInit.cpp

* STM32 fixes

* Add extern SPI1 for HW_SPI1_DEVICE

* Move initLora to RadioInterface.h
2026-01-25 20:54:17 -06:00
8894a0b711 Consolidate LoRa params / preset logic and fix display of preset values (#9413)
* Consolidate LoRa params / preset logic and fix display of preset values

* Move preset coercion logic to RadioInterface

* Fix some warnings

* Fix warnings

* STM32 fix

* Add unit tests

* Update src/mesh/RadioInterface.h

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-25 18:02:26 -06:00
d8d02cd6ec Implement setting TX_GAIN_LORA for portduino (#8501)
* Implement setting TX_GAIN_LORA for portduino

* use std::size instead of sizeof

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-22 07:08:43 -06:00
Jonathan Bennett 792e930e45 Trunk 2026-01-08 12:07:14 -06:00
Bob ReeseandGitHub ba9d0e6fa3 RadioInterface::getRetransmissionMsec now handles encrypted packets correctly (#9184) 2026-01-06 12:34:48 -06:00
JorropoandGitHub beb268ff25 Revert "add a .clang-format file (#9154)" (#9172)
I thought git would be smart enough to understand all the whitespace changes but even with all the flags I know to make it ignore theses it still blows up if there are identical changes on both sides.

I have a solution but it require creating a new commit at the merge base for each conflicting PR and merging it into develop.

I don't think blowing up all PRs is worth for now, maybe if we can coordinate this for V3 let's say.

This reverts commit 0d11331d18.
2026-01-04 05:15:53 -06:00
JorropoandGitHub 0d11331d18 add a .clang-format file (#9154) 2026-01-03 14:19:24 -06:00
Jonathan BennettandGitHub f63dadd19e Add custom coding rate configuration for LoRa (#9155) 2026-01-02 16:23:01 -06:00
Tom FifieldandGitHub a2ce4c7f18 KZ_863 is not wide lora (#9075)
KZ_863 was set to wide_lora = true. This was a mistake, induced because the
regulations would allow SHORT_TURBO. However, that interpretation of the code
was incorrect and wide_lora has a different meaning.

Fixes https://github.com/meshtastic/firmware/issues/9054
2026-01-02 09:03:05 +11:00
ee6449746b CLIENT_BASE: Act like ROUTER_LATE for fav'd nodes, instead of like ROUTER (#8567)
* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2025-12-19 07:45:35 -06:00
Ben MeadorsandGitHub 8e0547e76d Implement Long Turbo preset (#8985)
* Implement Long_Turbo preset

* Oops

* Start to DRY up menu handler by actually using OO concepts instead of jank separate arrays

* Move the implementation back into the method

* Dummy comment

* Listen to copilot feedback and prevent dangling pointer

* Static and optional
2025-12-16 11:42:13 -06:00
korbinianbauerandGitHub 39780656ef Don't assign negative SNR to unsigned int type
SNR-based contention windows are broken on systems with 64-bit long integers.
Fixes #8430
2025-10-23 16:15:12 +02:00
130833b5be Fix erroneous limiting of power in Ham Mode (#8322)
Ham Mode ignores region regulatory limits, so regardless of whether
we set a single TX_GAIN_LORA or an array with a non-linear PA,
we shouldn't limit the power.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2025-10-13 07:50:57 -05:00
GUVWAFandGitHub e8296914a5 Calculate airtime of transmitted and received packets separately (#8205) 2025-10-04 05:29:25 -05:00
Ben MeadorsandGitHub af83670376 Merge pull request #8179 from meshtastic/develop
Develop -> master
2025-10-01 15:30:57 -05:00