Commit Graph
100 Commits
Author SHA1 Message Date
Thomas GöttgensandGitHub b46c8c9f80 Router: defer nested local sends to avoid handleReceived re-entrancy (#11191)
Prevents an nRF52 task-stack overflow on config save. Replaces draft #11155.
2026-07-24 19:30:48 +00:00
Thomas GöttgensandGitHub b9c7858fd0 enable autoLDRO on LR2021 (#11139) 2026-07-22 11:12:52 +02:00
Thomas GöttgensandGitHub f09f2b1366 Gate the PKI-decrypt key on signer-proven, not the opportunistic cache (#11116) 2026-07-22 11:12:06 +02:00
Thomas GöttgensandGitHub 11c510ff1b WIP: Big Display Node (#10926) 2026-07-22 09:35:36 +02:00
Thomas Göttgens dfee95c5c1 Consolidate per-area reports into testreport.xml for downstream consumers 2026-07-21 21:32:10 +02:00
Thomas Göttgens 4906f8a6d9 Run native PlatformIO tests by area for readable failures
The native test job ran every test_* suite in a single platformio invocation,
so a failure in the growing suite set could land past the viewable log limit.

Build the test programs once, then run the suites grouped by area in sequential
invocations, each with its own JUnit report and collapsible log. The runs share
one build dir, so gcov coverage still accumulates and a single capture holds the
union. Areas are ordered regex rules with a catch-all, so a new suite always runs.
2026-07-21 20:04:12 +02:00
Thomas GöttgensandGitHub d587f08481 Pin admin responses to the stored peer key and request id (#11092)
* Pin admin responses to the stored peer key and request id

noteOutgoingAdminRequest derived its PKC pin from p.public_key, which nothing
populates on the outgoing path, so keyValid was false for every client request
and the pin never engaged. The accepted-response predicate reduced to an
unauthenticated from plus variant and subtype.

Resolve the destination key from NodeDB the way perhapsEncode does, and pin it
only when the request would actually be PKC-encrypted. Extract that condition
from perhapsEncode as wouldEncryptWithPKC so both use one predicate. Also
record the request's packet id and require the response to echo it.

* Treat a zero request id as no pairing token
2026-07-21 07:16:22 -05:00
Thomas GöttgensandGitHub 7bdc2569e8 Budget the admin-key PKI decrypt fallback (#11100) 2026-07-21 09:48:09 +02:00
Thomas GöttgensandGitHub 6bff231d53 Throttle NodeInfo direct responses (#11104) 2026-07-21 09:12:02 +02:00
Thomas GöttgensandGitHub 077c6e72f4 Corroborate traceroute next-hop updates against the relaying node (#11108) 2026-07-21 09:11:05 +02:00
Thomas GöttgensandGitHub 40e583c102 Limit node database churn from unauthenticated packets (#11102) 2026-07-21 09:09:53 +02:00
Thomas GöttgensandGitHub b299cc2427 Honour which_payload_variant on MQTT client-proxy ingress (#11097) 2026-07-21 09:08:46 +02:00
Thomas GöttgensandGitHub 53e510199a Bound remote-initiated key verification sessions (#11101)
* Bound remote-initiated key verification sessions

Opening a session raises a 30 second banner and a client notification and
occupies the only verification slot, all before the peer has authenticated
anything, and nothing limited how often that could happen.

Adds an absolute session cap that incoming packets cannot refresh, a
cooldown between remote-initiated sessions measured from when the previous
one ended, and refreshes the idle deadline only when the protocol actually
advances rather than on any arriving packet.

The busy path now sets ignoreRequest so it no longer answers with a NAK.

Also replaces the getTime() - 60 timeout comparison, which underflowed
before the clock passed 60.

* Use elapsed-time comparison for the session timeout and condense comments
2026-07-20 20:29:56 -05:00
Thomas GöttgensandGitHub d9f8839241 Accept a pending key only for the key-verification exchange (#11107)
perhapsDecode fell back to the not-yet-verified key held during a key
verification handshake for any incoming PKI unicast. That key is supplied
by whoever opened the handshake and proves only that they hold it, not that
they are the node they claim to be, so until the session ended they could
send DMs on any port that decrypted and were marked pki_encrypted.

perhapsEncode already restricts the pending key to KEY_VERIFICATION_APP.
The receive path now applies the same rule.
2026-07-20 20:28:30 -05:00
Thomas GöttgensandGitHub b8fb42c065 Fix bell-append off-by-one write past payload buffer (#11099)
The send_bell append writes bytes[size] and bytes[size+1] while the guard only checked size < DATA_PAYLOAD_LEN, overrunning the 233-byte payload array by one when size == DATA_PAYLOAD_LEN - 1. Guard on size + 1.
2026-07-20 18:38:50 -05:00
Thomas GöttgensandGitHub 6f522aad17 Return the secret sentinel for remote admin config gets (#11093)
writeSecret is a setter, so calling it on the NETWORK_CONFIG get path was a no-op: the buffer
already holds the stored psk, never the sentinel. MQTT_CONFIG returned the broker password
verbatim.

Both get paths now return secretReserved when req.from != 0, and the matching set paths call
writeSecret so a read-modify-write round trip keeps the stored value.
2026-07-20 18:38:23 -05:00
Thomas GöttgensandGitHub fb75410e53 Null-check packet allocations in allocForSending and its callers (#11086)
* Null-check packet allocations in allocForSending and its callers

Sibling of 0ae44d701.

* Null-check allocDataProtobuf, allocAckNak and allocErrorResponse callers

Second tier of the same nullable contract.

* Keep telemetry sleep scheduling on allocation failure

Allocation failure now marks the telemetry invalid instead of returning
early, so power-saving SENSOR nodes still arm deep sleep.
2026-07-20 18:37:13 -05:00
Thomas GöttgensandGitHub 51019b14f4 Hold cryptLock around RNG use in admin and key verification (#11096)
setPassKey drew the session passkey outside cryptLock, unlike the signing
and key verification paths. Also replaces random() for the key verification
nonce with the hardware RNG.
2026-07-20 18:36:06 -05:00
Thomas GöttgensandGitHub e061335055 Reserve the [Exit] slot when splitting canned messages (#11095)
splitConfiguredMessages capped the split loop at
CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT and then appended [Exit]
unconditionally, so messages[] could be written one past its last index
and messagesCount could exceed the array size.
2026-07-20 17:31:21 -05:00
Thomas GöttgensandGitHub 0199a1f3ff Bounds-check detection sensor trigger type (#11091) 2026-07-20 14:49:29 +02:00
Thomas GöttgensandGitHub 290967f739 Release packets the interface declines to send (#11087) 2026-07-20 13:42:59 +02:00
Thomas GöttgensandGitHub 5ded0ec8c5 Gate identity learning on signature in NodeDB::updateUser (#11084) 2026-07-20 11:56:42 +02:00
Thomas GöttgensandGitHub 405a6bfd8a Strip inner-message padding when sizing unsigned broadcasts (#11083) 2026-07-20 11:55:55 +02:00
Thomas GöttgensandGitHub 023351a979 Remove dead code (#11082)
Removed:
- MessageStore::addFromPacket and addFromString, superseded by
  tryAddFromPacket
- GeoCoord rangeRadiansToMeters, distanceTo, bearingTo
- Router::rawSend, declared virtual with no override and no caller
- ContentHandler handleHotspot, handleFs, handleAdminSettings,
  handleAdminSettingsApply, handleDeleteFsContent and their commented
  route registrations, plus the now unreachable htmlDeleteDir and the
  handleUpdateFs declaration that had no definition
- ContentHelper replaceAll
- OnScreenKeyboardModule popup chain: showPopup, clearPopup, drawPopup,
  drawPopupOverlay and their state, unreachable since the frame based UI
  was replaced by baseUI
- DebugRenderer drawDebugInfoTrampoline, drawDebugInfoSettingsTrampoline
  and the orphaned drawFrameSettings
- NodeListRenderer calculateMaxScroll, drawColumns and a stale extern
  haveGlyphs declaration with no definition
- UIRenderer::haveGlyphs, Screen::blink,
  NotificationRenderer::showKeyboardMessagePopupWithTitle,
  VirtualKeyboard::getInputText
- InkHUD touchNavLeft, touchNavRight, Applet::getActiveNodeCount,
  ThreadedMessageApplet::saveMessagesToFlash
- TwoButton::setHandlerUp, TwoButtonExtended setHandlerUp,
  setJoystickDownHandlers, setJoystickUpHandlers
- CannedMessageModule LaunchRepeatDestination, isCharInputAllowed,
  hasMessages
- TrafficManagementModule resetStats, recordRouterHopPreserved,
  saturatingIncrement
- UnitConversions::MetersPerSecondToMilesPerHour
- EncryptedStorage getSessionRemainingSeconds
- BMI270Sensor::writeRegisters, GPS::hasFlow, FSCommon copyFile,
  SerialConsole consolePrintf, buzz playLongPressLeadUp,
  memGet displayPercentHeapFree
2026-07-20 11:55:17 +02:00
Thomas GöttgensandGitHub ba8b1b1038 Treat backslash as a path separator in XModem filename validation (#11085) 2026-07-20 10:46:33 +02:00
Thomas GöttgensandGitHub a808e992a1 Add native Windows build of meshtasticd (#11031) 2026-07-19 23:31:19 +02:00
d4aa7760cc Use hardware RNG for session passkey and PKC extra nonce (#11047)
* Use hardware RNG for session passkey and PKC extra nonce

The admin session passkey and the Curve25519 extra nonce were drawn
from Arduino random(), which is not a CSPRNG. Source them from
HardwareRNG::fill, mirroring the signing path, and fall back to the
seeded CSPRNG (CryptRNG) only when no hardware source is available.

* AdminModule: make session passkey expiry rollover-safe

session_time was compared as millis()/1000 seconds with additive
thresholds, which breaks across the millis() wrap and could keep a stale
admin session key valid. Store session_time in millis() and use
Throttle::isWithinTimespanMs for the 150s refresh and 300s validity
windows.

* AdminModule: track session passkey validity with an explicit flag

session_time == 0 was used as the uninitialized sentinel, but millis()
is legitimately 0 in the first millisecond of uptime, so a passkey
issued then would be treated as no session. Use a dedicated
session_passkey_valid flag instead.

* AdminModule: camelCase the session passkey validity flag

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-17 15:49:00 -05:00
985b983f67 TrafficManagement: gate role/NodeInfo cache writes on signer authenticity (#11048)
* TrafficManagement: gate role/NodeInfo cache writes on signer authenticity

The tier-3 role cache and the PSRAM NodeInfo response cache were updated
from any received NodeInfo with no authenticity check, so a spoofed
NodeInfo could set a node's cached role (granting dedup exceptions) or
poison the cached user served in direct responses. Skip both cache
writes when a known signer's NodeInfo arrives unsigned, matching the
identity-update gate on the direct-response path.

* TrafficManagement: hoist shared NodeInfo signer lookup

Compute the sender node lookup and unauthenticated-signer check once per
NodeInfo packet and reuse it for both the cache-refresh gate and the
direct-response identity gate, avoiding a second O(N) getMeshNode scan.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-17 16:32:01 +01:00
Thomas GöttgensandGitHub cfecef5376 Channels: fix off-by-one bound in decryptForHash (#11046)
decryptForHash accepted chIndex == getNumChannels() before reading
getHash(chIndex), which indexes one past hashes[MAX_NUM_CHANNELS].
Use >= so an out-of-range index is rejected before the array read.
2026-07-17 08:15:19 -05:00
Thomas GöttgensandGitHub 8147970957 AdminModule: only accept admin responses to requests we sent (#11024)
* AdminModule: only accept admin responses to requests we sent

An admin *_response short-circuited the auth and session-passkey checks that gate
every other admin message, so any node could deliver one. On a channel the module
listens to unauthenticated, a get_module_config_response drives the remote-hardware
pin handler with attacker-supplied values.

Track the destination of outgoing admin requests (per remote, with the pinned PKC
key when there is one) and accept a response only from a node with a matching
outstanding request, inside the same window as the session passkey. Local (from == 0)
admin is unchanged; PhoneAPI already gates it.

Also fix the response dispatch: get_module_config_response.which_payload_variant is a
ModuleConfig oneof tag, but it was compared against the AdminMessage ModuleConfigType
enum (different numbering), so the handler never ran. Compare against the oneof tag.

* AdminModule: rollover-safe request window, bind response to request type

Two review refinements to the request/response pairing:

Use Throttle::isWithinTimespanMs for the outstanding-request expiry instead of
comparing millis()/1000 sums, which mis-expired across the millis() rollover.

Bind each accepted response to a request type actually sent to that node. Each
outstanding record now carries a bitmask of the response variants its requests
authorize, so a get_owner request no longer admits a get_module_config response.
The mask accumulates per remote, so a client may still pipeline several request
types to one node and have every answer accepted.

* AdminModule: track admin requests per-request, not per-node

Reworks the outstanding-request table so each request is its own entry with its own
expiry window and pinned key, replacing the per-node bitmask that shared one timestamp
and one key across every response variant.

That sharing let a later request to the same node extend an earlier one's window and,
worse, clear its PKC pin: an unpinned request cleared keyValid, so a plaintext response
to an earlier PKC-pinned request was then accepted. Per-request entries keep each pin
intact. Identical requests are de-duplicated (a client may fetch several config subtypes,
all answered by one response variant) and eviction compares elapsed time, which is
rollover-safe.

Test: a pinned request's response still requires its key after an unpinned request to the
same node.

* AdminModule: match module-config subtype and consume answered requests

Two refinements to the request/response pairing:

Only remote_hardware get_module_config_response mutates state (the pin table), so it
must answer a request for that exact ModuleConfigType, not just any module-config
request. Each entry records the requested subtype and the gate checks it.

A matched request is now consumed on accept, so a node cannot replay a state-mutating
response within the window. Because one request yields one response, request de-dup is
dropped (a client's N indexed get_channel requests are N entries, each consumed once).

Tests: a non-remote-hardware request does not admit a remote_hardware response, and a
second copy of an answered response is rejected.
2026-07-17 07:50:41 -05:00
d5f78a37d3 XModem: reject path-traversal filenames in the transfer handler (#11037)
The SOH/STX control frame carries a client-supplied filename that was passed
straight to FSCom open/remove/exists, so a ".." component could write, read, or
delete outside the filesystem root. On embedded LittleFS this is largely inert
(no parent of the partition root); on the Portduino daemon FSCom is the host
filesystem under a mountpoint, so it is a real arbitrary-path write/read/delete.

Validate the filename before any FS access: reject empty and any ".." path
component, and NAK the transfer. Absolute and subdirectory paths are still
accepted - the file manager transfers them from the manifest and PortduinoFS
confines them to its mountpoint - so only traversal out of the root is blocked.

Reachable only from a local client connection (PhoneAPI: BLE/USB/serial/TCP),
not over the RF mesh; on the daemon the TCP API makes it network-reachable.

native-suite-count goes to 34: +1 for the new test_xmodem suite and +1 correcting
a pre-existing miscount (it read 32 for 33 suite directories).

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-17 06:31:20 -05:00
a7fde715c6 PhoneAPI: gate local admin on the connection, not the wire from (#11033)
* PhoneAPI: gate local admin on the connection, not the wire from

The lockdown admin check in handleToRadioPacket only ran when p.from == 0. from is
a client-supplied wire field, and MeshService::handleToRadio rewrites it to 0 before
AdminModule sees the packet. A client could therefore set from != 0 to skip the
!getAdminAuthorized() drop, then have the packet normalized back to a local-admin
identity and executed - unauthorized admin from an unauthorized connection.

Every packet in handleToRadioPacket already comes from the local connection, so
locality is a property of the connection, not of from. Move the decision into
classifyLocalAdminPacket(), which ignores from and keys only on the admin variant and
the connection's authorization: lockdown_auth is delivered inline, any other admin
from an unauthorized connection is dropped, authorized admin passes through.

The classifier is compiled unconditionally and unit-tested; the guarded caller (built
only in the nRF52 lockdown config) calls it. Test: an unauthorized connection's
ADMIN_APP packet with from != 0 is classified DropUnauthorized.

* PhoneAPI: wipe the encoded lockdown passphrase, shorten comments

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-07-17 05:21:32 -05:00
Thomas GöttgensandGitHub ed3afdbc61 TrafficManagement: don't learn identity from a signer's unsigned NodeInfo (#11035) 2026-07-17 09:43:22 +02:00
Thomas GöttgensandGitHub 8ebdae9921 Bound payload.bytes prints by payload.size (#11032)
decoded.payload.bytes is a 233-byte protobuf field that is not NUL-terminated.
Printing it with a plain "%s" reads until a NUL, which for a full-length payload
with no NUL runs past the field. Use "%.*s" with payload.size, matching the write
form already used a few lines up in SerialModule.

Live sites: RangeTestModule appendFile, SerialModule text output. The same fix is
applied to the commented-out debug lines in RangeTestModule and Router so the
pattern is consistent if they are re-enabled.
2026-07-16 19:45:22 -05:00
Thomas GöttgensandGitHub bdf92e1183 AudioModule: validate codec2 header and bound the RX decode reads (#11036)
* AudioModule: validate codec2 header and bound the RX decode reads

Two issues reachable from a crafted AUDIO_APP payload:

The RX path built a temp codec2 from rx_encode_frame[3] whenever the frame header
did not match ours. codec2_create returns NULL for an invalid mode byte, and the
next call dereferenced it. Only decode frames that carry our own header (magic +
mode) and drop the rest, so the untrusted mode byte never reaches codec2_create.

The decode loop advanced by the frame size while testing only i < rx_encode_frame_index,
so a payload length that was not a multiple of the frame size read past the received
data and could read past rx_encode_frame. Bound each read to i + frameSize <= the
received length clamped to the buffer, and clamp the receive memcpy to the buffer.

Behavior change: audio frames whose codec2 mode differs from this node's configured
mode are dropped instead of decoded with a temporary codec.

* AudioModule: pass byte count (not sample count) to i2s_write

* AudioModule: fix the mirror sample/byte bug on the i2s_read capture path
2026-07-16 19:18:31 -05:00
Thomas GöttgensandGitHub d3d02af817 AdminModule: don't return the device private key to remote config reads (#11030)
A SECURITY_CONFIG get_config response copied config.security verbatim, so a remote
request was answered with the device identity private_key and sent over the air.
Only the local owner needs it, for backup.

Zero private_key in the SECURITY_CONFIG response when the request is remote
(from != 0); the local BLE/USB/TCP path (from == 0) still receives it. public_key
and admin_key are public and stay as they were.
2026-07-16 16:56:47 -05:00
Thomas GöttgensandGitHub 381f9c196d NodeDB: clear only the slots removeNodeByNum() vacates (#11022) 2026-07-16 21:48:25 +02:00
Thomas GöttgensandGitHub e219e24b09 WarmNodeStore: carry the XEdDSA signer flag through the warm tier (#11020) 2026-07-16 21:46:46 +02:00
Thomas GöttgensandGitHub f52d7753ad Router: size the fit check from the decoded Data (#11018) 2026-07-16 08:51:10 -05:00
Thomas GöttgensandGitHub fb922c2413 fix(tracker-x1): silence the buzzer during init (#11007) 2026-07-14 10:44:31 +02:00
Thomas GöttgensandGitHub 7a25ffd0a2 fix: evaluate pre-hop hop_start bitfield guard post-decode instead of before decryption (#10758) 2026-07-11 12:10:25 -05:00
Thomas GöttgensandGitHub 838323cc07 Quote esp-idf include paths in esp32.ini for Windows builds (#10980)
${platformio.packages_dir} resolves to a backslash path on Windows.
PlatformIO parses build_flags with POSIX shell rules, which strip the
backslashes and turn the NimBLE include paths into broken relative
paths (d:platformiopackages/...), failing the build with
'host/ble_gap.h: No such file or directory'. Quoting the flags
preserves backslashes through parsing.
2026-07-10 10:17:47 -05:00
Thomas GöttgensandGitHub 38074f584f Fix SENSOR power saving deep sleep truncating TX and skipping sleep on failed reads (#10939)
* Fix SENSOR power saving deep sleep behavior

Deep sleep could be entered while a telemetry packet was still queued
or on air, truncating the transmission. canSleep() gained a deepSleep
parameter and now vetoes in that case; light sleep is unchanged.
Telemetry modules defer a pending deep sleep (bounded to 30s) until the
radio is idle and no longer let the sensor polling interval override
the 5s pre-sleep grace period. A failed sensor read still arms deep
sleep instead of leaving the node awake for a full telemetry interval.

Fixes #10890
Fixes #10932

* Deduplicate telemetry deep sleep deferral logic

Move the radio-busy deferral and its counter into BaseTelemetryModule
and add an isPowerSavingSensor() helper. Removes the telemetry-specific
counter from OSThread. The sleep arming block stays per module because
it needs protected OSThread members not visible to the base class.
2026-07-08 07:30:46 -05:00
Thomas GöttgensandGitHub ba473bf529 size gate: emit flash_bytes from ELF for targets without a packaged .bin (#10940)
* size gate: emit flash_bytes from ELF for targets without a packaged .bin

nRF52 builds package hex/uf2/DFU zip but no raw .bin, so collect_sizes.py
dropped budgeted envs like rak4631 entirely and the size-budget-gate failed
closed. Emit ELF text+data as flash_bytes in the manifest and use it as the
fallback flash measurement.

* Factor shared size-tool invocation into run_size_tool helper
2026-07-08 07:22:26 -05:00
Thomas Göttgens c61d32c0fa Guard AirQuality I2C re-scan behind !MESHTASTIC_EXCLUDE_I2C
ScanI2CTwoWire is compiled out on builds that define
MESHTASTIC_EXCLUDE_I2C (e.g. native-wasm/portduino), while the
AirQuality module still builds there. Skip the re-scan when I2C is
excluded; there is nothing to scan.
2026-07-03 11:13:02 +02:00
Thomas Göttgens e1982cc2b1 Merge remote-tracking branch 'origin/develop' into pr10715-fix
# Conflicts:
#	src/graphics/Screen.cpp
#	src/modules/Telemetry/Sensor/PMSA003ISensor.h
#	src/modules/Telemetry/Sensor/SCD30Sensor.h
#	src/modules/Telemetry/Sensor/SCD4XSensor.h
#	src/modules/Telemetry/Sensor/SEN5XSensor.cpp
#	src/modules/Telemetry/Sensor/SEN5XSensor.h
#	src/modules/Telemetry/Sensor/SFA30Sensor.h
2026-07-03 11:12:16 +02:00
Thomas GöttgensandGitHub 7509c1a6dd Seeed Tracker X1 Support (#10834)
* Seeed Tracker X1 Support

* silence CPPCheck

* fix macro order regression and adapt stm32hal for new radiolib

* STM32 is a radiolib upstream fix ( https://github.com/jgromes/RadioLib/issues/1825 )

* fix STM32 regression

* Seeed Tracker X1 Support

* silence CPPCheck

* fix macro order regression and adapt stm32hal for new radiolib

* STM32 is a radiolib upstream fix ( https://github.com/jgromes/RadioLib/issues/1825 )

* fix STM32 regression

* address copilot OCD

* Split behavior only when the two LEDs are on distinct pins.

* bring naming in line with the other seeed devices

* update env name to fit convention too

* guarantee evaluation order

* Guard sensor readings against null values, make sensor use less power
2026-07-02 07:39:52 -05:00
Thomas GöttgensandGitHub b28898ae4d FETCH_HEAD, checkout@V7 regression 2026-07-01 09:30:26 +02:00
Thomas GöttgensandGitHub 3edc89d087 Fix 10799 (#10819)
* Document that src/mesh/generated is auto-generated and must not be edited

* Fix esp32s2 build by enabling native USB CDC, add S2 to check matrix (#10799)
2026-06-30 06:01:48 -05:00
Thomas GöttgensandGitHub c4fdf374e1 fix: right-size warm tier for constrained platforms (#10746, #10705) (#10759)
* fix: right-size warm tier for constrained platforms and feed RP2040 watchdog during NodeDB save

* fix: size warm tier and traffic cache per-MCU RAM, lowering no-PSRAM ESP32 (classic/S2/C3) tiers

* docs: document nRF52/RP2040 #else fall-through in warm tier and TM cache cascades
2026-06-22 06:21:50 -05:00
Thomas GöttgensandJonathan Bennett 56a33a07f7 remove private flag 2026-06-08 15:54:38 -05:00
Thomas GöttgensandJonathan Bennett ce80433e43 activate HWID 2026-06-08 15:54:24 -05:00
Thomas GöttgensandGitHub 8c4900a52f Prevent ghost nodes during onboarding (#10647)
* Prevent ghost nodes during onboarding
* Coplilot is exceptionally nit-picky today
2026-06-07 22:54:25 +02:00
bfb833982e Flip C6 to supported. (#10646)
* Flip C6 to supported.

* Re-add board_level pr

and remove redundant lib_deps

---------

Co-authored-by: Austin <vidplace7@gmail.com>
2026-06-07 15:12:59 -05:00
Thomas GöttgensandGitHub f86cb7781e Remove fragile JSON libraries from the firmware while retaining Meshtasticd JSON support (#10152) 2026-06-03 16:47:30 +02:00
Thomas Göttgens e2aa44ec54 T-Echo-Card support (#10267)
# Conflicts:
#	src/graphics/draw/UIRenderer.cpp
2026-05-19 09:53:45 +02:00
Thomas GöttgensandGitHub 1747e2d8e5 T-Echo-Card support (#10267) 2026-05-19 09:31:04 +02:00
Thomas GöttgensandGitHub 0832330327 Fix antenna switch initialization logic 2026-05-19 08:00:02 +02:00
Thomas GöttgensandGitHub 98e0604edf Fix antenna switch initialization logic once more 2026-05-19 07:58:24 +02:00
Thomas Göttgens 6199faacf1 cherry pick backport fix for cardputer 2026-05-18 23:24:32 +02:00
Thomas GöttgensandGitHub 3261c04afb Fix Antenna Switch on Cardputer (#10491) 2026-05-18 11:18:40 +02:00
Thomas GöttgensJonathan BennettBen Meadorscopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>caveman99
64fd61706d ThinkNode M7 (#8077)
* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* rename variant and add guard macros

* older G3 operational. M7 next.

* Split out G3 and M7 to different variants. Completely new PCB design. The G3 stays on 'PRIVATE_HW'

* Define button behaviour and use all of the device flash

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2026-05-11 11:46:13 -05:00
Thomas GöttgensGitHubBen Meadorscopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>caveman99Jonathan Bennett
8e99ffbe7e ThinkNode M7 (#8077)
* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* rename variant and add guard macros

* older G3 operational. M7 next.

* Split out G3 and M7 to different variants. Completely new PCB design. The G3 stays on 'PRIVATE_HW'

* Define button behaviour and use all of the device flash

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2026-05-11 11:33:13 -05:00
Thomas GöttgensandGitHub 4c24218afb Revert "Update LovyanGFX to v1.2.20 (#10232)" (#10269) (#10270)
This reverts commit fb1de111d7.
2026-04-23 12:40:27 +02:00
Thomas GöttgensandGitHub 7c27f4e2df Revert "Update LovyanGFX to v1.2.20 (#10232)" (#10269)
This reverts commit fb1de111d7.
2026-04-23 12:37:05 +02:00
Thomas GöttgensandBen Meadors a67eb15ad3 fix last cppcheck issue (#10154) 2026-04-14 13:05:58 -05:00
Thomas GöttgensandGitHub d6cf67b6bc Clarify behavior when no radio instance is present
Add comment explaining silent behavior when no radio instance is available.
2026-04-14 12:19:58 +02:00
Thomas GöttgensandGitHub e42ff3590c fix last cppcheck issue (#10154) 2026-04-13 15:48:30 +02:00
969aefa551 Cardputer Kit (#9540)
* Cardputer Kit
BMI270 WIP

* BMI270 support

* verify that the number of bytes read matches the requested length

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

* trunk'd

* remove excessive logging

* Kick the screen when unsleeping

* Update the st7789 library, and enable displayon and displayoff

* Battery detection

* Default to arrow keys and enter, while in menus.

* Enable Backlight control

* Update src/detect/ScanI2CTwoWire.cpp

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

* updateState method now accepts shouldRequestFocus parameter for better maintainability

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-03-06 05:34:41 -06:00
Thomas GöttgensandGitHub 5f852a1c05 Add ADS1115 ADC to recognition as used on RAK6421 Hat (#9790) 2026-03-03 08:55:53 +01:00
Thomas GöttgensandGitHub 54781cf51a hopefully fix remaining cppcheck issues (#9745) 2026-02-25 10:27:21 +01:00
Thomas Göttgens 58496e56d2 fail cppcheck on low already. Code quality for the win. 2026-02-24 22:45:38 +01:00
Thomas GöttgensandGitHub 178c3114d9 Fake IAQ values on Non-BSEC2 platforms like Platformio and the original ESP32 (#9663)
* BSEC2 Replacement
- add approximation for IAQ to non-BSEC2 platforms.
- Re-add this sensor to ESP32 targets, and refactor env_extra includes.
- Fix C++ 11 compatibility
* Check for gas resistance 0
2026-02-17 22:16:56 +01:00
Thomas GöttgensandGitHub a4ba312579 zip a few gitrefs down (#9672) 2026-02-17 09:53:20 +01:00
Thomas GöttgensandGitHub a227fd7028 #9623 resolved a local shadow of next_key by converting it to int. (#9665) 2026-02-16 19:39:43 +01:00
6b44b5786e fix detection of SCD30 by checking if the size of the return from a 2 byte register read is correct (#9664)
* fix detection of SCD30 by checking if thee size of the return from a 2 byte register read is correct
fix signedness warning in PMSA003 sensor code.

* Add alternate path for LPS22HB

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

* check EndTransmission for errors and compare returned length to expected value

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-16 10:07:07 -06:00
Thomas GöttgensandGitHub 5feba46b53 our firmware action is too clever
Update pio_target and add pio_opts for checks.
2026-02-16 16:39:31 +01: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
Thomas GöttgensandBen Meadors 5b03b1fe52 fix some random compiler warnings (#9596) 2026-02-11 06:45:26 -06:00
Thomas GöttgensandGitHub f96a8593f2 fix some random compiler warnings (#9596) 2026-02-11 06:43:05 -06:00
233e6acc85 Preliminary Thinknode M4 Support (#8754)
* Preliminary Thinknode M4 Support

* oops

* Fix RF switch TX configuration

* trunk'd

* GPS fix for M4

* Battery handling and LED for M4

* Trunk

* Drop debug warnings

* Make Red LED notification

* Merge cleanup

* Make white LEDs flash during charge

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2026-01-14 21:36:53 -06:00
Thomas GöttgensandGitHub 79e8fc94bc 3401 fix (#8755)
* Preliminary Thinknode M4 Support

* fix 3401 detection

* don't push unrelated work
2025-11-25 16:35:17 -06:00
Thomas Göttgens 451e52b541 fix some minor compiler warnings. Note: The 'delete' is actually safe, so we suppress the warning. 2025-11-21 10:42:15 +01:00
Thomas Göttgens d743ba8e75 Add Thinknode M6 2025-11-21 10:14:06 +01:00
Thomas GöttgensandGitHub a62fed3289 Merge pull request #8610 from meshtastic/fix-ldro
Change RadioLib to commit zip til 7.4.1+ is released
2025-11-10 22:31:03 +01:00
Thomas GöttgensandGitHub 7d2744fae0 Change RadioLib to commit zip til 7.4.1+ is released
fixes regression for SX127x chips per @GUVWAF
2025-11-10 16:16:24 +01:00
71d84404c6 add WIP for Unit C6L (#7433)
* add WIP for Unit C6L
* adapt to new config structure
* Add c6l BLE and screen support (#7991)
* Minor c6l fix
* Move out of PRIVATE_HW
---------
Co-authored-by: Austin <vidplace7@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Jason P <Xaositek@users.noreply.github.com>
Co-authored-by: Markus <Links2004@users.noreply.github.com>
2025-09-17 22:40:55 +02:00
Thomas GöttgensandGitHub 9feb1d378e Support for T-Echo Lite, credits to @Szetya for doing all the heavy lifting! (#7636)
* Support for T-Echo Lite, credts to @Szetya for doing all the heavy lifting!
* move define to ini file
2025-08-17 13:37:12 +02:00
Thomas GöttgensandGitHub e69da71d4e reorder for correct recognition (#7604) 2025-08-11 11:53:01 +02:00
Thomas GöttgensandGitHub d1f3c3c982 128row display (#7511)
* Fix 128 row monochrome display
* trunk fmt
* fix assignment
2025-08-04 17:25:31 +02:00
Thomas GöttgensandGitHub 608fdc6f52 Santa may be checking his list twice, but we only need this in the platformio.ini (#7490) 2025-07-28 09:47:46 -05:00
Thomas GöttgensandGitHub b851b15a73 fix UDP builds on nRF (#7394)
* fix UDP builds on nRF
* fix rp2040 too
2025-07-20 23:13:50 +02:00
a9c9b96eb6 UDP for RAK4631 Eth Gw and the t-eth-elite. Solves #7149 (#7385)
* UDP for RAK4631 Eth Gw and the t-eth-elite. Also enable IP output on Portduino. Solves #7149

* Copilot suggestion

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

* fix portduino build

* initialize local port

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2025-07-20 06:22:00 -05:00
Thomas GöttgensandGitHub 55fc4fcd90 clean up double i2c init/scan code (#7359) 2025-07-17 00:40:29 +02:00
Thomas GöttgensandGitHub ac3e5684d6 get git url part from local repo (#7331) 2025-07-14 05:11:26 -05:00
Thomas GöttgensandGitHub 16d2650236 add pioenv to version string in debug log (#7328) 2025-07-13 19:16:14 +02:00
Thomas GöttgensandGitHub 96c18d9908 Add LINK32 (Lilygo) Board with Light+Environment sensors (#6899)
* Add LINK32 (Lilygo) Board with Light+Environment sensors
TODO: replace PRIVATE_HW with actual HWID

* Add LINK32 (Lilygo) Board with Light+Environment sensors
TODO: replace PRIVATE_HW with actual HWID

* Update to real HWID and trunk fmt
2025-05-27 18:11:32 -05:00
cc66f7c79b Crowpanel 4.3, 5.0, 7.0 support (#6611)
* SD software SPI control
* fix notification crash;
* allow wake on touch
* don't build non-MUI variants
* use pwm buzzer
* Finalize support for Crowpanel TFT 2.4, 2.8 and 3.5
* add hardware ID for TFT panels
* Add stubs for the bigger panels. WIP!
* fix braces
* elecrow 4.3, 5.0, 7.0 support
* completed implementation 4.3, 5.0, 7.0 variants
* NodeDB default config & simplified light sleep macros
* trunk fmt
* remove flags
* removed leftovers (note: rtc gpios are only needed for deep sleep; the remove section caused issues with the elecrows)
---------
Co-authored-by: mverch67 <manuel.verch@gmx.de>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
Co-authored-by: Austin <vidplace7@gmail.com>
2025-05-13 14:15:52 +02:00
e2f6600cb9 Lib Update (#6510)
* Lib Update

Draft because PIN display doesn't work yet.

* pin entry still no worky

* Fix for missing PIN code issue (#6574)

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Alexander Begoon <alex@begoonlab.tech>
2025-04-17 15:58:28 -05:00
ef14967fbf Crowpanel 2.4,2.8 and 3.5 support (#6355)
Co-authored-by: mverch67 <manuel.verch@gmx.de>
2025-04-17 16:03:37 +02:00