Skip to content

SenseCAP Indicator: RP2040 peripherals for the main firmware#6220

Open
caveman99 wants to merge 25 commits into
developfrom
indicator-comms
Open

SenseCAP Indicator: RP2040 peripherals for the main firmware#6220
caveman99 wants to merge 25 commits into
developfrom
indicator-comms

Conversation

@caveman99

@caveman99 caveman99 commented Mar 4, 2025

Copy link
Copy Markdown
Member

The Indicator's RP2040 co-processor serves as a generic peripheral bridge over a serial protobuf link (interdevice.proto). Companion PRs: meshtastic/protobufs#721 (protocol), meshtastic/device-ui#342 (map tile and SD card services), meshtastic/indicator_rp2040#3 (co-processor firmware).

  • FakeI2C implements TwoWire and tunnels write and read transactions, so the standard sensor drivers and the I2C scan work unmodified on the bridged second bus (WIRE1)
  • FakeUART forwards GPS NMEA to the regular GPS driver
  • SD card access with chunked file transfers, paged directory listings and card statistics; device-ui loads map tiles and map styles from the card behind the RP2040
  • Link at 2M baud with 4KB chunks; message structs are kept off task stacks
  • Log messages carrying their own bracket tag render it like a thread name (used by the device-ui task)

The generated interdevice bindings are included in-tree; the protobufs submodule stays on the develop pin until meshtastic/protobufs#721 merges, after which a regeneration commit follows the usual flow.

Verified on hardware: bridged sensor scan and telemetry (AHT10, SCD41), GPS fix, map tiles and SD statistics all work end to end.

Summary by CodeRabbit

  • New Features
    • Added SenseCAP Indicator support with a co-processor bridge for bridged I2C, GPS, and SD access, including directory browsing.
    • Introduced tunneled UART and I2C proxying for indicator-backed peripherals.
    • Added a remote SD/file backend to mirror SD operations over the bridge.
  • Bug Fixes
    • Improved tagged logging to avoid duplicate thread prefixes while preserving ANSI severity colors.
    • Refined I2C bus selection for RTC and sensors to follow detected bridged mappings.
  • Chores
    • Updated bundled device UI and refreshed bundled protobufs; removed indicator environmental sensor telemetry and related framing support.
    • Adjusted indicator board settings (faster UART baud, boot-time sensor power control) and expanded LVGL PSRAM heap for the indicator TFT build.

@github-actions github-actions Bot added the Stale Issues that will be closed if not triaged. label May 16, 2025
@github-actions github-actions Bot closed this May 23, 2025
@fifieldt fifieldt reopened this May 23, 2025
@fifieldt fifieldt added triaged Reviewed by the team, has enough information and ready to work on now. and removed Stale Issues that will be closed if not triaged. labels May 23, 2025
@caveman99
caveman99 requested a review from Copilot July 2, 2025 22:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR integrates a secondary SenseCap Indicator MCU by removing the local COBS implementation and introducing proxy UART/I2C bridges to tunnel sensor and NMEA data over Meshtastic interdevice messages.

  • Removed in-tree COBS serialization in favor of external or consolidated implementation
  • Added FakeUART/FakeI2C and SensecapIndicator to proxy serial and I²C traffic
  • Updated build flags, main setup, and GPS class to select the fake transports under SENSECAP_INDICATOR

Reviewed Changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
variants/seeed-sensecap-indicator/platformio.ini Switched build flags to esp32s3_base and added RingBuffer dependency
src/serialization/cobs.h & cobs.cpp Removed local COBS encode/decode files
src/modules/Telemetry/Sensor/IndicatorSensor.* Removed the IndicatorSensor class and its integration
src/modules/Telemetry/EnvironmentTelemetry.cpp Cleaned out indicatorSensor instantiation and calls
src/mesh/comms/FakeUART.h & FakeUART.cpp Introduced FakeUART to simulate serial and forward NMEA over uplink
src/mesh/comms/FakeI2C.h & FakeI2C.cpp Introduced FakeI2C to simulate I²C and forward commands/responses
src/mesh/IndicatorSerial.h & IndicatorSerial.cpp Added SensecapIndicator thread to encode/decode interdevice protobuf messages
src/main.cpp Wired up the indicator thread and replaced native Wire1 with FakeI2C under the feature flag
src/gps/GPS.h & GPS.cpp Switched GPS serial backend to FakeUART when SENSECAP_INDICATOR is defined
Comments suppressed due to low confidence (3)

src/mesh/comms/FakeUART.h:24

  • The flush(bool) signature doesn’t match the Stream::flush() override (which takes no parameters), potentially leading to unexpected behavior; consider renaming or correctly overriding void flush().
    void flush(bool wait = true);

src/mesh/comms/FakeI2C.cpp:37

  • Returning 0xFF when quantity != 1 may be misinterpreted as 255 bytes available; return 0 to match the Wire API's convention of 0 bytes read on failure.
  if (quantity != 1) return 0xFF;

Comment thread src/mesh/comms/FakeUART.cpp Outdated
Comment thread src/mesh/comms/FakeI2C.cpp Outdated
Comment thread src/main.cpp Outdated
Comment thread src/mesh/IndicatorSerial.cpp Outdated
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds a protobuf-framed SenseCAP Indicator link with tunneled I2C, UART, GPS, and filesystem operations. It initializes the bridge during boot, routes peripherals through it, removes legacy telemetry paths, and updates logging, hardware settings, and pinned revisions.

Changes

SenseCAP Indicator support

Layer / File(s) Summary
Inter-device serial transport
src/mesh/IndicatorSerial.*
Adds framed protobuf communication, handshake handling, correlation IDs, packet parsing, and synchronous I2C/file/SD request APIs.
Tunneled I2C, UART, and lock adapters
src/mesh/comms/*Proxy.*, src/mesh/comms/LinkSpiLock.h
Adds I2C and UART proxy interfaces backed by the indicator link, with per-task buffering and SPI lock coordination.
Boot, scanning, and peripheral bus wiring
src/main.cpp, src/configuration.h, src/detect/*, src/gps/*, src/input/*, src/motion/*, variants/esp32s3/seeed-sensecap-indicator/variant.h
Initializes the co-processor, enables bridged bus scanning, routes GPS and peripherals through resolved buses, and updates variant power, UART, and GPS settings.
Remote filesystem integration
src/graphics/tftSetup.cpp
Adds an IndicatorRemoteFS backend for chunked file access, directory listing, SD information, deletion, retries, and TFT lock coordination.
Legacy paths and support updates
src/modules/Telemetry/*, src/RedirectablePrint.*, platformio.ini, protobufs, variants/esp32s3/seeed-sensecap-indicator/platformio.ini
Removes indicator telemetry registration, prevents duplicate log tags, and updates pinned UI, protobuf, and LVGL memory settings.

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested reviewers: mverch67, thebentern

Sequence Diagram(s)

sequenceDiagram
  participant main
  participant SensecapIndicator
  participant I2CProxy
  participant RemoteSDService
  participant IndicatorRemoteFS
  main->>SensecapIndicator: construct and wait_ready
  I2CProxy->>SensecapIndicator: send tunneled I2C request
  SensecapIndicator-->>I2CProxy: return correlated I2C response
  RemoteSDService->>IndicatorRemoteFS: read or write remote file
  IndicatorRemoteFS->>SensecapIndicator: send file request
  SensecapIndicator-->>IndicatorRemoteFS: return file response
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding RP2040 peripheral bridging for the SenseCAP Indicator.
Description check ✅ Passed The description covers the feature scope, companion PRs, implementation notes, and hardware verification, so it is substantially complete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch indicator-comms

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@caveman99
caveman99 changed the base branch from master to develop July 9, 2026 11:07
@caveman99 caveman99 added the enhancement New feature or request label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Flash this PR in the Web Flasher

firmware commit boards expires

Warning

This is an automated, unreviewed CI test build. Back up your device configuration
before flashing, and only flash devices you are able to recover.

Supported boards built by this PR (28)
Device Board Platform
Crowpanel Adv 3.5 TFT elecrow-adv-35-tft esp32-s3
Heltec HT62 heltec-ht62-esp32c3-sx1262 esp32-c3
Heltec Mesh Node 096 heltec-mesh-node-t096 nrf52840
Heltec Mesh Node T1 heltec-mesh-node-t1 nrf52840
Heltec Mesh Node T114 heltec-mesh-node-t114 nrf52840
Heltec V3 heltec-v3 esp32-s3
Heltec V4 heltec-v4 esp32-s3
Meshnology W10 meshnology_w10 esp32-s3
Raspberry Pi Pico pico rp2040
Raspberry Pi Pico W picow rp2040
RAK WisMesh Repeater Mini V2 rak_wismesh_repeater_mini nrf52840
RAK WisMesh Tag rak_wismeshtag nrf52840
RAK WisBlock 11200 rak11200 esp32
RAK WisBlock 11310 rak11310 rp2040
RAK3312 rak3312 esp32-s3
RAK WisBlock 4631 rak4631 nrf52840
Seeed SenseCAP Mesh-Tracker-X1 seeed_mesh_tracker_X1 nrf52840
Seeed Wio Tracker L1 seeed_wio_tracker_L1 nrf52840
Seeed Xiao NRF52840 Kit seeed_xiao_nrf52840_kit nrf52840
Seeed Xiao ESP32-S3 seeed-xiao-s3 esp32-s3
Station G2 station-g2 esp32-s3
Station G3 station-g3 esp32-s3
LILYGO T-Deck t-deck-tft esp32-s3
LILYGO T-Echo t-echo nrf52840
LILYGO T-Echo Plus t-echo-plus nrf52840
LILYGO T-Impulse Plus t-impulse-plus nrf52840
LilyGo T3-C6 tlora-c6 esp32-c6
Seeed SenseCAP T1000-E tracker-t1000-e nrf52840

Build artifacts expire on 2026-08-14. Updated for 4a5111d.

@caveman99
caveman99 force-pushed the indicator-comms branch 3 times, most recently from 8d1c7ae to 3bc42a3 Compare July 12, 2026 17:35
@caveman99 caveman99 changed the title get sensor and NMEA data from indicator. SenseCAP Indicator: RP2040 peripherals for the main firmware Jul 12, 2026
@caveman99
caveman99 marked this pull request as ready for review July 12, 2026 17:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/gps/GPS.cpp (1)

1433-1454: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Preserve GPS-mode checks for the bridged backend.

This skips both GpsMode_NOT_PRESENT and disabled-mode exits, while createGps() always creates the GPS object for SenseCAP. Since this variant defaults GPS to not present, incoming RP2040 NMEA can still be processed and published despite the user disabling GPS. Keep the configuration checks and only bypass physical probing/setup.

Also applies to: 1917-1920

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/gps/GPS.cpp` around lines 1433 - 1454, Preserve the GPS mode checks in
the SenseCAP/bridged backend path: ensure GpsMode_NOT_PRESENT exits before
processing incoming NMEA, and GpsMode_ENABLED is required before publishing
updates. Restrict the conditional compilation around GPS physical probing and
setup only, updating the initialization logic near GPSInitFinished and the
corresponding code near createGps() so bridged input cannot bypass
configuration.
🧹 Nitpick comments (9)
src/RedirectablePrint.cpp (2)

81-83: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Comment exceeds the 1–2 line limit.

This explanatory comment spans three lines. As per coding guidelines, "Keep code comments minimal: one or two lines maximum, only when the reason is not obvious, and do not restate the next line."

✏️ Suggested trim
-    // A leading "[Tag] " in the message simulates the thread name tag (used
-    // by contexts without an OSThread, e.g. the device-ui task). Print it
-    // before applying the level color so it renders like a real thread name.
+    // A leading "[Tag] " simulates a thread-name tag (e.g. for device-ui);
+    // print it uncolored, before the level color codes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/RedirectablePrint.cpp` around lines 81 - 83, Shorten the explanatory
comment near the level-color printing logic to no more than two lines while
preserving only the essential reason for printing the leading “[Tag] ” before
applying the color. Remove redundant wording that restates the surrounding code.

Source: Coding guidelines


85-89: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Tag-detection window is a magic number.

The hardcoded 24 bound for the tag scan window has no named constant or brief rationale. Consider extracting it (e.g. constexpr size_t kMaxTagScanLen = 24;) for readability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/RedirectablePrint.cpp` around lines 85 - 89, Extract the hardcoded
24-byte scan bound in the tag-detection logic around printBuf into a named
constexpr constant such as kMaxTagScanLen, and use that symbol in the memchr
length expression while preserving the existing limit.
src/mesh/IndicatorSerial.cpp (2)

256-258: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Shorten this implementation comment.

It exceeds the two-line limit and largely describes the following operations.

As per coding guidelines, “Keep code comments minimal: one or two lines maximum.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/IndicatorSerial.cpp` around lines 256 - 258, Shorten the comment
above the protobuf decoding logic to one or two concise lines, retaining only
that decoding occurs and any remaining buffer bytes are preserved for the next
packet.

Source: Coding guidelines


47-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Throttle for the timeout checks.

Both loops implement elapsed-time checks with raw millis() subtraction.

As per coding guidelines, use Throttle instead of raw millis() arithmetic for “did N ms pass” checks.

Also applies to: 173-185

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/IndicatorSerial.cpp` around lines 47 - 58, Update
SensecapIndicator::wait_response and the other referenced response-wait loop to
use the existing Throttle mechanism for elapsed-time checks instead of millis()
subtraction. Configure Throttle with the requested timeout and use its
expiration/check API while preserving the current flag handling, pumping, delay,
and timeout return behavior.

Source: Coding guidelines

src/mesh/IndicatorSerial.h (1)

33-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep implementation comments to two lines or fewer.

These newly added comments exceed the repository limit; condense each without restating implementation details.

As per coding guidelines, “Keep code comments minimal: one or two lines maximum.”

Also applies to: 38-40, 54-56, 71-74

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/IndicatorSerial.h` around lines 33 - 35, Condense the newly added
comments in IndicatorSerial around the request/response flow and the
corresponding sections at the other referenced locations so each is no more than
two lines. Keep only the essential intent, removing redundant implementation
details and preserving the surrounding code unchanged.

Source: Coding guidelines

src/mesh/comms/FakeUART.cpp (1)

58-61: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

setRxBufferSize reports success without actually resizing anything.

Returning size unconditionally (regardless of the fixed BUF_SIZE = 2048 buffer) can mislead callers expecting the requested capacity was honored. Consider returning the actual BUF_SIZE instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/comms/FakeUART.cpp` around lines 58 - 61, Update
FakeUART::setRxBufferSize to return the actual fixed receive-buffer capacity,
BUF_SIZE, instead of the requested size; leave the existing buffer behavior
unchanged.
src/mesh/comms/FakeI2C.cpp (1)

44-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Silent clamp of requestFrom length instead of an invariant check.

len is silently truncated to MAX_READ (line 47-48) rather than treated as a caller bug. MAX_READ is derived from the negotiated protobuf limit (line 50-51 in the header), so any caller requesting more indicates a driver bug, not a runtime condition to gracefully clamp.

🛡️ Suggested change
 size_t FakeI2C::requestFrom(uint8_t address, size_t len, bool stopBit)
 {
     (void)stopBit;
-    if (len > MAX_READ)
-        len = MAX_READ;
+    assert(len <= MAX_READ);

As per coding guidelines, "Use assert() for invariants that should never fail."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/comms/FakeI2C.cpp` around lines 44 - 60, Replace the silent len
truncation in FakeI2C::requestFrom with an assert that len does not exceed
MAX_READ, preserving the existing transaction flow for valid requests. Include
the appropriate assert support if needed and remove the clamp assignment.

Source: Coding guidelines

src/mesh/comms/FakeI2C.h (1)

8-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Class doc comment exceeds the 1–2 line limit.

This 15-line block comment explains multiple behaviors (buffering semantics, repeated-start combining, bus-0 construction rationale) in one long explanatory block.

✏️ Suggested trim
-/**
- * TwoWire implementation that tunnels bus traffic to the RP2040 over the
- * interdevice serial link, making the sensors attached to the secondary MCU
- * usable by the regular sensor drivers of the main firmware.
- *
- * beginTransmission()/write() buffer an outgoing write. The buffered write is
- * executed as a single serial round trip on endTransmission(true). A write
- * followed by endTransmission(false) and requestFrom() is combined into one
- * write+read transaction with repeated start, matching driver access
- * patterns.
- *
- * Constructed on bus number 0: TwoWire::begin() is final and cannot be
- * intercepted, but it returns without touching hardware when the bus is
- * already initialized, which is always true for bus 0 (local touch panel).
- */
+// Tunnels TwoWire traffic over the interdevice serial link to the RP2040.
+// write()+endTransmission(false)+requestFrom() combine into one repeated-start transaction.

As per coding guidelines, "Keep code comments minimal: one or two lines maximum, only when the reason is not obvious, and do not restate the next line."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/comms/FakeI2C.h` around lines 8 - 22, Shorten the class-level
documentation for TwoWire to one or two lines, retaining only the non-obvious
purpose or rationale. Remove the detailed buffering, transaction, and bus-0
behavior explanation from the comment without changing the implementation.

Source: Coding guidelines

src/mesh/comms/FakeUART.h (1)

23-23: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

flush(bool wait = true) also hides rather than overrides Print::flush().

Same root cause as the write() mismatch: Print::flush() takes no arguments, so this signature hides it instead of overriding. Likely intentional to mirror HardwareSerial::flush(bool), but worth confirming it's never called through a Stream&/Print& reference where the argument would be silently dropped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/comms/FakeUART.h` at line 23, Update FakeUART::flush so it does not
hide Print::flush(): preserve the bool-based HardwareSerial-compatible API while
also exposing a no-argument flush path that correctly overrides Print::flush().
Ensure calls through Stream& or Print& invoke the no-argument override, and
retain the existing wait behavior for direct bool-based calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mesh/comms/FakeUART.cpp`:
- Around line 73-87: Update FakeUART::write to reserve one byte in
message.data.nmea for the null terminator by limiting the copied size to at most
sizeof(message.data.nmea) - 1. Preserve the existing truncation, logging,
send_uplink, and returned-size behavior while ensuring the buffer remains
null-terminated.

In `@src/mesh/IndicatorSerial.cpp`:
- Around line 61-64: Move the packets_received readiness checks in i2c_transact
and the other indicated request paths below their respective link_lock LockGuard
acquisitions. Ensure each check and subsequent transaction logic uses the
protected value, while preserving the existing fail-fast return behavior when no
packets have been received.
- Around line 188-205: Update SensecapIndicator::send_uplink to serialize all
access to the shared pb_tx_buf using link_lock, while preserving a private
lock-held sender for request methods that already hold the lock. Ensure
FakeUART::write and GPS uplink paths use the public locking sender, and request
methods call the private variant to avoid recursive locking.
- Around line 208-219: Update SensecapIndicator::serial_check and the
corresponding frame-length handling at the referenced path to reserve space for
the four-byte header and reject oversized payloads before filling pb_rx_buf.
Check available capacity before writing each byte, preventing the current
write-before-boundary-check overflow while preserving normal frame reads.
- Around line 61-75: Add a per-transaction correlation ID to
meshtastic_InterdeviceMessage, assign and retain the expected ID in
SensecapIndicator::i2c_transact, and include it in the request. Update
handle_packet() to compare incoming replies against the active transaction ID
and ignore mismatches before setting i2c_result_ready or copying the result.

---

Outside diff comments:
In `@src/gps/GPS.cpp`:
- Around line 1433-1454: Preserve the GPS mode checks in the SenseCAP/bridged
backend path: ensure GpsMode_NOT_PRESENT exits before processing incoming NMEA,
and GpsMode_ENABLED is required before publishing updates. Restrict the
conditional compilation around GPS physical probing and setup only, updating the
initialization logic near GPSInitFinished and the corresponding code near
createGps() so bridged input cannot bypass configuration.

---

Nitpick comments:
In `@src/mesh/comms/FakeI2C.cpp`:
- Around line 44-60: Replace the silent len truncation in FakeI2C::requestFrom
with an assert that len does not exceed MAX_READ, preserving the existing
transaction flow for valid requests. Include the appropriate assert support if
needed and remove the clamp assignment.

In `@src/mesh/comms/FakeI2C.h`:
- Around line 8-22: Shorten the class-level documentation for TwoWire to one or
two lines, retaining only the non-obvious purpose or rationale. Remove the
detailed buffering, transaction, and bus-0 behavior explanation from the comment
without changing the implementation.

In `@src/mesh/comms/FakeUART.cpp`:
- Around line 58-61: Update FakeUART::setRxBufferSize to return the actual fixed
receive-buffer capacity, BUF_SIZE, instead of the requested size; leave the
existing buffer behavior unchanged.

In `@src/mesh/comms/FakeUART.h`:
- Line 23: Update FakeUART::flush so it does not hide Print::flush(): preserve
the bool-based HardwareSerial-compatible API while also exposing a no-argument
flush path that correctly overrides Print::flush(). Ensure calls through Stream&
or Print& invoke the no-argument override, and retain the existing wait behavior
for direct bool-based calls.

In `@src/mesh/IndicatorSerial.cpp`:
- Around line 256-258: Shorten the comment above the protobuf decoding logic to
one or two concise lines, retaining only that decoding occurs and any remaining
buffer bytes are preserved for the next packet.
- Around line 47-58: Update SensecapIndicator::wait_response and the other
referenced response-wait loop to use the existing Throttle mechanism for
elapsed-time checks instead of millis() subtraction. Configure Throttle with the
requested timeout and use its expiration/check API while preserving the current
flag handling, pumping, delay, and timeout return behavior.

In `@src/mesh/IndicatorSerial.h`:
- Around line 33-35: Condense the newly added comments in IndicatorSerial around
the request/response flow and the corresponding sections at the other referenced
locations so each is no more than two lines. Keep only the essential intent,
removing redundant implementation details and preserving the surrounding code
unchanged.

In `@src/RedirectablePrint.cpp`:
- Around line 81-83: Shorten the explanatory comment near the level-color
printing logic to no more than two lines while preserving only the essential
reason for printing the leading “[Tag] ” before applying the color. Remove
redundant wording that restates the surrounding code.
- Around line 85-89: Extract the hardcoded 24-byte scan bound in the
tag-detection logic around printBuf into a named constexpr constant such as
kMaxTagScanLen, and use that symbol in the memchr length expression while
preserving the existing limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2654ff4f-f2ad-4822-9b32-96312efbe48b

📥 Commits

Reviewing files that changed from the base of the PR and between 5513c36 and 3bc42a3.

⛔ Files ignored due to path filters (2)
  • src/mesh/generated/meshtastic/interdevice.pb.cpp is excluded by !**/generated/**, !src/mesh/generated/**
  • src/mesh/generated/meshtastic/interdevice.pb.h is excluded by !**/generated/**, !src/mesh/generated/**
📒 Files selected for processing (21)
  • platformio.ini
  • protobufs
  • src/RedirectablePrint.cpp
  • src/configuration.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.cpp
  • src/gps/GPS.h
  • src/graphics/tftSetup.cpp
  • src/main.cpp
  • src/mesh/IndicatorSerial.cpp
  • src/mesh/IndicatorSerial.h
  • src/mesh/comms/FakeI2C.cpp
  • src/mesh/comms/FakeI2C.h
  • src/mesh/comms/FakeUART.cpp
  • src/mesh/comms/FakeUART.h
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/serialization/cobs.cpp
  • src/serialization/cobs.h
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
💤 Files with no reviewable changes (5)
  • src/serialization/cobs.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/serialization/cobs.h
  • src/modules/Telemetry/EnvironmentTelemetry.cpp

Comment thread src/mesh/comms/FakeUART.cpp Outdated
Comment thread src/mesh/IndicatorSerial.cpp Outdated
Comment thread src/mesh/IndicatorSerial.cpp Outdated
Comment thread src/mesh/IndicatorSerial.cpp
Comment thread src/mesh/IndicatorSerial.cpp Outdated
@caveman99
caveman99 force-pushed the indicator-comms branch 2 times, most recently from 7beaaf3 to 5fe2ed5 Compare July 12, 2026 18:12

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/gps/GPS.cpp (1)

1433-1454: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve GPS mode and serial guards for SENSECAP builds.

Compiling out this entire block causes SENSECAP_INDICATOR builds to ignore GPS_NOT_PRESENT, other non-enabled GPS modes, and _serial_gps == nullptr; runOnce() proceeds directly into active GPS processing. Keep those common guards outside the preprocessor branch, while only bypassing hardware probing/setup for the tunneled backend.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/gps/GPS.cpp` around lines 1433 - 1454, Move the GPS mode and _serial_gps
guards from the `#if` !defined(SENSECAP_INDICATOR) block into shared runOnce()
logic so SENSECAP builds still disable for GPS_NOT_PRESENT, non-enabled modes,
and a null serial interface. Keep only hardware probing/setup and GNSS detection
conditional, bypassing those operations for the tunneled backend while
preserving GPSInitFinished and publishUpdate behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/gps/GPS.cpp`:
- Around line 1917-1920: Update the GPS::createGps() guard around _rx_gpio and
_serial_gps to validate _serial_gps for SENSECAP_INDICATOR as well, preventing
construction when the serial dependency is null. Restore the SENSECAP-specific
protection or use a guaranteed runtime getter instead of relying on the cross-TU
FakeSerial initialization.

---

Outside diff comments:
In `@src/gps/GPS.cpp`:
- Around line 1433-1454: Move the GPS mode and _serial_gps guards from the `#if`
!defined(SENSECAP_INDICATOR) block into shared runOnce() logic so SENSECAP
builds still disable for GPS_NOT_PRESENT, non-enabled modes, and a null serial
interface. Keep only hardware probing/setup and GNSS detection conditional,
bypassing those operations for the tunneled backend while preserving
GPSInitFinished and publishUpdate behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a30ca51-4457-4ea7-a312-bf500853a20a

📥 Commits

Reviewing files that changed from the base of the PR and between 7beaaf3 and 5fe2ed5.

⛔ Files ignored due to path filters (2)
  • src/mesh/generated/meshtastic/interdevice.pb.cpp is excluded by !**/generated/**, !src/mesh/generated/**
  • src/mesh/generated/meshtastic/interdevice.pb.h is excluded by !**/generated/**, !src/mesh/generated/**
📒 Files selected for processing (21)
  • platformio.ini
  • protobufs
  • src/RedirectablePrint.cpp
  • src/configuration.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.cpp
  • src/gps/GPS.h
  • src/graphics/tftSetup.cpp
  • src/main.cpp
  • src/mesh/IndicatorSerial.cpp
  • src/mesh/IndicatorSerial.h
  • src/mesh/comms/FakeI2C.cpp
  • src/mesh/comms/FakeI2C.h
  • src/mesh/comms/FakeUART.cpp
  • src/mesh/comms/FakeUART.h
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/serialization/cobs.cpp
  • src/serialization/cobs.h
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
💤 Files with no reviewable changes (5)
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/serialization/cobs.cpp
  • src/serialization/cobs.h
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
🚧 Files skipped from review as they are similar to previous changes (14)
  • protobufs
  • src/configuration.h
  • src/mesh/IndicatorSerial.h
  • src/graphics/tftSetup.cpp
  • src/mesh/comms/FakeI2C.h
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
  • src/mesh/comms/FakeUART.cpp
  • src/mesh/comms/FakeUART.h
  • src/RedirectablePrint.cpp
  • src/mesh/comms/FakeI2C.cpp
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.h
  • src/main.cpp
  • src/mesh/IndicatorSerial.cpp

Comment thread src/gps/GPS.cpp Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/modules/Telemetry/EnvironmentTelemetry.cpp`:
- Around line 676-684: Replace the sprintf call in the notification construction
block with snprintf, passing sizeof(notification->message) as the buffer size
while preserving the existing format string and arguments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 22f28c40-3a0a-4870-9d06-b32aa56a27fd

📥 Commits

Reviewing files that changed from the base of the PR and between 5fe2ed5 and ae1684f.

⛔ Files ignored due to path filters (2)
  • src/mesh/generated/meshtastic/interdevice.pb.cpp is excluded by !**/generated/**, !src/mesh/generated/**
  • src/mesh/generated/meshtastic/interdevice.pb.h is excluded by !**/generated/**, !src/mesh/generated/**
📒 Files selected for processing (20)
  • platformio.ini
  • src/RedirectablePrint.cpp
  • src/configuration.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.cpp
  • src/gps/GPS.h
  • src/graphics/tftSetup.cpp
  • src/main.cpp
  • src/mesh/IndicatorSerial.cpp
  • src/mesh/IndicatorSerial.h
  • src/mesh/comms/FakeI2C.cpp
  • src/mesh/comms/FakeI2C.h
  • src/mesh/comms/FakeUART.cpp
  • src/mesh/comms/FakeUART.h
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/serialization/cobs.cpp
  • src/serialization/cobs.h
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
💤 Files with no reviewable changes (4)
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/serialization/cobs.h
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/serialization/cobs.cpp
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/configuration.h
  • platformio.ini
  • src/gps/GPS.h
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
  • src/mesh/comms/FakeUART.h
  • src/RedirectablePrint.cpp
  • src/mesh/comms/FakeI2C.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.cpp
  • src/mesh/IndicatorSerial.h
  • src/graphics/tftSetup.cpp
  • src/mesh/comms/FakeI2C.cpp
  • src/mesh/comms/FakeUART.cpp
  • src/mesh/IndicatorSerial.cpp

@mverch67

Copy link
Copy Markdown
Collaborator

I wouldn't call it FakeI2C, FakeUART, but I2CProxy / UARTProxy as these classes implement the known proxy pattern. Then its more clear alone from the name what its purpose is.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/mesh/IndicatorSerial.cpp (1)

44-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Throttle instead of raw millis() arithmetic for the probe rate limit.

probe_link() open-codes a "250 ms since last probe" gate with millis() - last_probe. Prefer the repo's Throttle helper.

♻️ Suggested change
-    if (last_probe != 0 && millis() - last_probe < 250)
-        return;
+    if (Throttle::isWithinTimespanMs(last_probe, 250))
+        return;
     ...
-    last_probe = millis();

Adjust last_probe handling to match Throttle::isWithinTimespanMs semantics.

As per coding guidelines: "Use Throttle for time-based rate limiting instead of raw millis() arithmetic; prefer Throttle::isWithinTimespanMs(lastMs, intervalMs)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/IndicatorSerial.cpp` around lines 44 - 52, Update the probe
rate-limit check in probe_link() to use Throttle::isWithinTimespanMs(last_probe,
250) instead of raw millis() subtraction, preserving the existing early return
and last_probe update behavior.

Source: Coding guidelines

src/mesh/comms/LinkSpiLock.h (1)

9-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Trim rationale comments to the project's 1-2 line limit.

These four new comment blocks explain genuinely non-obvious reasoning but each exceeds the repository's comment-length rule.

  • src/mesh/comms/LinkSpiLock.h#L9-L13: shorten the spiLockHolder extern comment to 1-2 lines.
  • src/mesh/comms/LinkSpiLock.h#L15-L22: shorten the SpiLockBreak Doxygen block to 1-2 lines (or move detail to a design doc/PR description).
  • src/mesh/comms/UARTProxy.h#L9-L17: shorten the UARTProxy class doc comment to 1-2 lines.
  • src/main.cpp#L643-L647: shorten the comment ahead of wait_ready(5000) to 1-2 lines.

As per coding guidelines, "Keep code comments minimal: one or two lines maximum, only when the reason is not obvious, and do not restate the next line."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/comms/LinkSpiLock.h` around lines 9 - 13, Shorten the rationale
comments to the project’s one- or two-line limit without changing behavior:
update the spiLockHolder comment in src/mesh/comms/LinkSpiLock.h lines 9-13, the
SpiLockBreak Doxygen comment in src/mesh/comms/LinkSpiLock.h lines 15-22, the
UARTProxy class comment in src/mesh/comms/UARTProxy.h lines 9-17, and the
comment before wait_ready(5000) in src/main.cpp lines 643-647; retain only the
essential non-obvious rationale and avoid restating the following code.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mesh/comms/UARTProxy.cpp`:
- Around line 90-93: Update UARTProxy::write to capture the boolean result from
sensecapIndicator->send_uplink(message) and return size only when transmission
succeeds; return the appropriate failure/zero count when it returns false so
callers know the bytes were not accepted.
- Around line 47-50: Update UARTProxy::flush(bool wait) to honor the wait
argument and match HardwareSerial semantics: flush(false) must discard buffered
NMEA output without clearing unread RX data, while the appropriate wait behavior
should preserve existing stream expectations. Adjust the current buf_clear()
call accordingly.

---

Nitpick comments:
In `@src/mesh/comms/LinkSpiLock.h`:
- Around line 9-13: Shorten the rationale comments to the project’s one- or
two-line limit without changing behavior: update the spiLockHolder comment in
src/mesh/comms/LinkSpiLock.h lines 9-13, the SpiLockBreak Doxygen comment in
src/mesh/comms/LinkSpiLock.h lines 15-22, the UARTProxy class comment in
src/mesh/comms/UARTProxy.h lines 9-17, and the comment before wait_ready(5000)
in src/main.cpp lines 643-647; retain only the essential non-obvious rationale
and avoid restating the following code.

In `@src/mesh/IndicatorSerial.cpp`:
- Around line 44-52: Update the probe rate-limit check in probe_link() to use
Throttle::isWithinTimespanMs(last_probe, 250) instead of raw millis()
subtraction, preserving the existing early return and last_probe update
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bf74c9a-ce51-48a7-881c-9e57ad0dbdbe

📥 Commits

Reviewing files that changed from the base of the PR and between ae1684f and d61ce58.

⛔ Files ignored due to path filters (2)
  • src/mesh/generated/meshtastic/interdevice.pb.cpp is excluded by !**/generated/**, !src/mesh/generated/**
  • src/mesh/generated/meshtastic/interdevice.pb.h is excluded by !**/generated/**, !src/mesh/generated/**
📒 Files selected for processing (20)
  • platformio.ini
  • protobufs
  • src/configuration.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.cpp
  • src/gps/GPS.h
  • src/gps/RTC.cpp
  • src/graphics/tftSetup.cpp
  • src/input/kbI2cBase.cpp
  • src/main.cpp
  • src/mesh/IndicatorSerial.cpp
  • src/mesh/IndicatorSerial.h
  • src/mesh/comms/I2CProxy.cpp
  • src/mesh/comms/I2CProxy.h
  • src/mesh/comms/LinkSpiLock.h
  • src/mesh/comms/UARTProxy.cpp
  • src/mesh/comms/UARTProxy.h
  • src/motion/BMI270Sensor.cpp
  • src/motion/BMM150Sensor.cpp
  • src/motion/ICM20948Sensor.cpp
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/configuration.h
  • src/gps/GPS.cpp
  • src/graphics/tftSetup.cpp

Comment thread src/mesh/comms/UARTProxy.cpp Outdated
Comment thread src/mesh/comms/UARTProxy.cpp
caveman99 added 16 commits July 13, 2026 12:46
The SenseCAP Indicator RP2040 co-processor serves as a generic
peripheral bridge over a serial protobuf link (interdevice.proto):

- FakeI2C implements TwoWire and tunnels write and read transactions,
  so the standard sensor drivers and the I2C scan work unmodified on
  the bridged second bus (WIRE1)
- FakeUART forwards GPS NMEA to the regular GPS driver
- SD card access with chunked file transfers, paged directory
  listings and card statistics; device-ui loads map tiles and map
  styles from the card behind the RP2040
- link at 2M baud with 4KB chunks, message structs kept off task
  stacks

Log messages carrying their own bracket tag render it like a thread
name. Replaces the earlier IndicatorSensor/COBS approach.
Correlate responses with request ids, serialize the shared TX buffer,
reject oversized frames, fix RX buffer overflow and NMEA truncation,
full-length file paths.
Static initialization order across translation units is undefined,
so createGps() assigns and null-checks the bridged serial instead.
Bound the NMEA length defensively.
The RP2040 sends nothing unsolicited without a GPS module attached, so
wait_ready now probes with the new ping message instead of listening
passively. runOnce skips its pump while a requester holds link_lock,
keeping the main loop from blocking for a full request timeout. FakeI2C
serializes transactions between the UI task and the main loop with an
owner-tracked lock held from beginTransmission to transaction end.
…ts validity

Frame resync scans to the next magic instead of flushing the RX buffer,
and the pump handles all buffered frames per pass. The RX drain reads in
bulk and the protobuf encoder gets the correct buffer bound. GPS honors
the gps_mode setting on the Indicator instead of always running. RTC,
I2C keyboard and motion sensor drivers resolve WIRE1 through
ScanI2CTwoWire::fetchI2CBus so bridged buses reach the right transport.
FakeUART implements flush/availableForWrite/const-write from the Stream
contract and fences its cross-core ring buffer. SdCardInfo.stats_valid
is passed through to device-ui, and the remote FS backend gains the
remove operation used for cleanup of failed tile saves.
Remote FS operations retry once on a transport timeout. Correlation ids
drop late responses of the first attempt; a retried append whose first
attempt landed is recognized by the offset conflict carrying the
resulting file size. Definitive failures are not retried, missing-tile
probes stay a single round trip. Regenerated bindings add the
I2CResult.Status UNSPECIFIED zero value so an empty result cannot
decode as success.
A request the co-processor cannot decode or handle is nacked, so the
requester fails fast instead of burning its timeout. All requests stage
the shared tx_message under link_lock. FakeI2C and FakeUART are renamed
to I2CProxy and UARTProxy after the pattern they implement, with their
instances following suit. Drops dead code (unused NO_NEWS_PAUSE,
unreachable not-running branches, doubled include guards) and the GPS
pin log line that is meaningless on the tunneled port.
The ping/pong handshake now carries InterdeviceVersion. A pong reporting
a version other than ours means the RP2040 runs firmware that does not
match this build, so the bridge stays shut down for the session and the
mismatch is logged with both versions. Requests fail fast instead of
being misinterpreted by the other side.
…lures

The bridged I2C bus is shared between the main loop and the UI task, and
TwoWire has no transaction bracket a lock can span: drivers drain the read
buffer with available()/read() long after requestFrom() returned. Each
calling task therefore gets its own staging and read buffers instead of a
lock that could be left held (or that could not protect the read buffer
anyway). The transaction is staged inside the link, under its lock.

No request is sent before the co-processor has completed the version
handshake, and runOnce keeps probing until it does, so a co-processor that
boots slowly or reboots on its watchdog no longer leaves the bridge dead
for the session. Requests in flight are counted, not flagged: two threads
can be in a request and the first one out must not clear the other's state.

File operations are retried on a lost frame and on a co-processor busy with
card maintenance, but not on a refusal (nack) or a definitive failure, and
they release the SPI lock while they wait so a slow link does not starve
the radio.
FileStatus moved to a fresh tag: reusing the tag of the removed success flag
made every failure status decode as success on a peer that predates it.

A card being mounted (busy) is retried rather than reported as an empty
slot, and a co-processor busy with card maintenance is waited out: mounting
takes seconds and the free space scan of a large card walks its whole FAT,
which is not a reason to report a missing tile. The bridged I2C bus releases
the SPI lock as well, so the keyboard scan on the UI task cannot starve the
radio either. Slot claims in the I2C proxy are atomic, NMEA is not sent to a
peer we refuse to talk to, and the handshake is completed by the unsolicited
ping the co-processor sends when it has booted, which also reports a
reboot.
flush() through a Stream pointer discarded the receive buffer: the flag is
txOnly, and HardwareSerial::flush() keeps what has been received. write()
reported bytes as written even when the link refused to send them. The link
probe uses Throttle for its rate limit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/RedirectablePrint.cpp (1)

81-83: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the explanatory comment within the two-line limit.

This new comment spans three lines; condense it to one or two lines while preserving only the non-obvious rationale.

As per coding guidelines, C++ comments must be at most one or two lines and must not restate the following code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/RedirectablePrint.cpp` around lines 81 - 83, Condense the explanatory
comment above the leading “[Tag] ” handling to no more than two lines, retaining
only the non-obvious rationale that it simulates a thread name tag for contexts
without an OSThread and renders it like a real thread name. Remove wording that
restates the following code.

Source: Coding guidelines

src/mesh/IndicatorSerial.cpp (2)

365-371: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

memmove always shifts a full-buffer-sized region instead of the actual remaining bytes.

The length passed is PB_BUFSIZE - MT_HEADER_SIZE - payload_len, computed from the buffer capacity rather than pb_rx_size. Every processed frame (pings, NMEA, i2c results, file chunks) shifts up to the full remaining buffer capacity instead of only the valid bytes, wasting cycles on this hot path at 2M baud.

⚡ Proposed fix
-    pb_istream_t stream = pb_istream_from_buffer(pb_rx_buf + MT_HEADER_SIZE, payload_len);
-    bool status = pb_decode(&stream, meshtastic_InterdeviceMessage_fields, &message);
-    memmove(pb_rx_buf, pb_rx_buf + MT_HEADER_SIZE + payload_len, PB_BUFSIZE - MT_HEADER_SIZE - payload_len);
-    pb_rx_size -= MT_HEADER_SIZE + payload_len;
+    pb_istream_t stream = pb_istream_from_buffer(pb_rx_buf + MT_HEADER_SIZE, payload_len);
+    bool status = pb_decode(&stream, meshtastic_InterdeviceMessage_fields, &message);
+    size_t remaining = pb_rx_size - MT_HEADER_SIZE - payload_len;
+    memmove(pb_rx_buf, pb_rx_buf + MT_HEADER_SIZE + payload_len, remaining);
+    pb_rx_size = remaining;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/IndicatorSerial.cpp` around lines 365 - 371, Update the memmove call
in the protobuf decode path to copy only the valid bytes remaining after the
processed frame, using pb_rx_size minus MT_HEADER_SIZE and payload_len as the
length. Preserve the existing source and destination offsets and subsequent
pb_rx_size adjustment.

42-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Throttle instead of raw millis() arithmetic.

probe_link()'s 250ms cooldown (Line 44) and the deadline checks in wait_response() (Line 74) and wait_ready() (Line 278) are exactly the "did N ms pass since X" pattern the guideline calls out for Throttle.

♻️ Proposed fix for probe_link
-    if (last_probe != 0 && millis() - last_probe < 250)
-        return;
+    if (last_probe != 0 && Throttle::isWithinTimespanMs(last_probe, 250))
+        return;

The same substitution applies to the timeout checks at Line 74 and Line 278.

Also applies to: 65-79, 261-283

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/IndicatorSerial.cpp` around lines 42 - 53, Replace raw
millis()-based elapsed-time checks in SensecapIndicator::probe_link,
wait_response, and wait_ready with the established Throttle utility. Preserve
the current 250 ms probe cooldown and the existing response/readiness timeout
durations, using Throttle to track and test each operation’s deadline without
changing surrounding message or state behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mesh/IndicatorSerial.cpp`:
- Line 389: Update the stale-response and nack log statements in the relevant
IndicatorSerial flow to format the 32-bit request IDs with 0x%08x instead of %u,
including both message.id and expected_id while preserving the existing log
messages.

In `@src/RedirectablePrint.cpp`:
- Around line 175-177: Update the tag-suppression condition in the relevant
RedirectablePrint formatting path to inspect the rendered message produced by
vprintf, not format[0]. Reuse the existing validated “[Tag] ” prefix detection
after formatting so dynamic prefixes suppress the thread tag and templates
beginning with “[” do not incorrectly suppress it.

---

Nitpick comments:
In `@src/mesh/IndicatorSerial.cpp`:
- Around line 365-371: Update the memmove call in the protobuf decode path to
copy only the valid bytes remaining after the processed frame, using pb_rx_size
minus MT_HEADER_SIZE and payload_len as the length. Preserve the existing source
and destination offsets and subsequent pb_rx_size adjustment.
- Around line 42-53: Replace raw millis()-based elapsed-time checks in
SensecapIndicator::probe_link, wait_response, and wait_ready with the
established Throttle utility. Preserve the current 250 ms probe cooldown and the
existing response/readiness timeout durations, using Throttle to track and test
each operation’s deadline without changing surrounding message or state
behavior.

In `@src/RedirectablePrint.cpp`:
- Around line 81-83: Condense the explanatory comment above the leading “[Tag] ”
handling to no more than two lines, retaining only the non-obvious rationale
that it simulates a thread name tag for contexts without an OSThread and renders
it like a real thread name. Remove wording that restates the following code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 39fba7cb-21d0-47b9-b143-e9be5593d04d

📥 Commits

Reviewing files that changed from the base of the PR and between d61ce58 and a13bff5.

⛔ Files ignored due to path filters (2)
  • src/mesh/generated/meshtastic/interdevice.pb.cpp is excluded by !**/generated/**, !src/mesh/generated/**
  • src/mesh/generated/meshtastic/interdevice.pb.h is excluded by !**/generated/**, !src/mesh/generated/**
📒 Files selected for processing (27)
  • platformio.ini
  • protobufs
  • src/RedirectablePrint.cpp
  • src/configuration.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/gps/GPS.cpp
  • src/gps/GPS.h
  • src/gps/RTC.cpp
  • src/graphics/tftSetup.cpp
  • src/input/kbI2cBase.cpp
  • src/main.cpp
  • src/mesh/IndicatorSerial.cpp
  • src/mesh/IndicatorSerial.h
  • src/mesh/comms/I2CProxy.cpp
  • src/mesh/comms/I2CProxy.h
  • src/mesh/comms/LinkSpiLock.h
  • src/mesh/comms/UARTProxy.cpp
  • src/mesh/comms/UARTProxy.h
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/motion/BMI270Sensor.cpp
  • src/motion/BMM150Sensor.cpp
  • src/motion/ICM20948Sensor.cpp
  • src/serialization/cobs.cpp
  • src/serialization/cobs.h
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
💤 Files with no reviewable changes (5)
  • src/modules/Telemetry/Sensor/IndicatorSensor.h
  • src/serialization/cobs.h
  • src/serialization/cobs.cpp
  • src/modules/Telemetry/Sensor/IndicatorSensor.cpp
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
🚧 Files skipped from review as they are similar to previous changes (20)
  • protobufs
  • src/mesh/comms/LinkSpiLock.h
  • platformio.ini
  • src/motion/BMM150Sensor.cpp
  • variants/esp32s3/seeed-sensecap-indicator/variant.h
  • src/mesh/comms/UARTProxy.h
  • src/configuration.h
  • src/detect/ScanI2CTwoWire.cpp
  • src/motion/BMI270Sensor.cpp
  • src/input/kbI2cBase.cpp
  • src/mesh/comms/I2CProxy.h
  • src/motion/ICM20948Sensor.cpp
  • src/mesh/IndicatorSerial.h
  • src/graphics/tftSetup.cpp
  • src/mesh/comms/UARTProxy.cpp
  • src/gps/GPS.h
  • src/main.cpp
  • src/gps/GPS.cpp
  • src/gps/RTC.cpp
  • src/mesh/comms/I2CProxy.cpp

Comment thread src/mesh/IndicatorSerial.cpp Outdated
Comment thread src/RedirectablePrint.cpp Outdated
The thread tag was suppressed based on the printf template, which disagrees
with the rendered message it is compared against: a format starting with a
conversion could produce two tags, and one without a trailing bracket-space
lost the tag entirely. vprintf now receives the thread name and picks. Also
shifts only the bytes actually buffered after a frame, throttles with
Throttle and logs request ids as hex.
The busy retry re-armed its own budget on every busy answer, so a
co-processor that stayed busy kept the caller in the loop with no way out.
Transport retries and the wait for a busy card are now separate budgets that
only count down.
A byte run lost mid-response (a UART overflow during a 4KB tile chunk, when
the display starves the RX interrupt) misaligns the assembly buffer. The
buffer was never reset, so the poison outlived the request and cascaded into
the following chunks of the same tile: one glitch dropped a whole multi-chunk
tile, while single-chunk tiles resynced in the idle gap and survived. Each
request now flushes the buffer first, bounding a glitch to the one chunk it
hit. Adds resync/decode/timeout counters, logged rarely, to see the rate.
The heap was 3MB and the image cache reserves 1.5MB of it, so a low-zoom map
tile could not find a large enough contiguous block to decode and rendered
white. 5MB of the 8MB PSRAM fixes it with room to spare.
…mits

Point the protobufs submodule at the merged SD command protos (protobufs
#986) so it matches the checked in interdevice sources, and bump the
device-ui archive to the current indicator branch tip that carries the SD
button and format UI.
Resolve the device-ui pin to the indicator branch merge commit, which carries
both develop's device-ui updates and the remote SD support, so neither side is
lost. Take develop's protobufs pointer, which already contains the merged SD
command protos.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request triaged Reviewed by the team, has enough information and ready to work on now.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants