Skip to content

fix: Treat CRC and header errors as RF noise, not radio faults (#91) - #93

Merged
cwill747 merged 2 commits into
mainfrom
fix-91
Sep 10, 2026
Merged

cwill747 merged 2 commits into
mainfrom
fix-91

Conversation

@cwill747

@cwill747 cwill747 commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Fixes #91.

Diagnosis

The CRC and header errors are real RF events, not a bug. In the log attached to the issue, the failing packets arrive at RSSI −113 dBm, SNR −7 dB, and the SX1262 reports DeviceErrors=0x0000. The corrupt frame at 16:02:25.326 is the same RESPONSE relayed one more hop, received with a corrupt routing prefix. Decoding the clean copy per Packet.read_from() gives path_len=0x8a (3-byte hashes, 10 hops, 30 path bytes), so its payload starts at offset 32 with length 20 — matching the payload length the dispatcher logged. One further 3-byte hop predicts a 55-byte frame whose payload starts at offset 35, and that is exactly the length the SX1262 reported and exactly where the payload bytes sit. The 20-byte payload is byte-identical to the clean copy. But the frame arrived with header=0x0c and path_len=0x11, which would place the payload at offset 23 with length 32 — inconsistent with its own contents. Four bytes are corrupt (the header, path_len, and two path bytes); the payload came through clean. IRQ=0x0042 is RX_DONE | CRC_ERR with no HEADER_ERR bit, so the LoRa physical header decoded and the payload CRC then failed. The radio is healthy.

The defect is ours: RadioErrorHandler treated every WARNING from a radio-layer logger as a fault. pyMC_core logs reception noise at WARNING, so normal traffic flipped the header badge to "Radio Error" and flooded the console.

Changes

meshcore/logging_setup.py

  • classify_rf_noise() separates reception noise (CRC error, header error or corrupted header, empty packet) from real radio errors.
  • RadioErrorHandler counts the noise instead of reporting it. Only real errors reach the badge and the toasts.
  • RfNoiseCounter keeps per-category totals and writes one summary line per minute, so the rate stays visible without spam.
  • RfNoiseFilter on the stderr handler drops the noise from the console. The rotating file handler still records every line for bug reports, and at DEBUG console level the filter steps aside.

ui_gtk/views/settings.py

  • New read-only RX Noise row in the Logging panel. It refreshes every 2 s while the panel is mapped.

Tests

10 new tests in tests/unit/test_logging_setup.py. Full suite: 129 passed, 1 skipped. ruff check, ruff format --check, and mypy are clean on the touched files.

Review notes

  • I could not render the settings panel. The development environment has no X or Wayland display, and the flake provides no Xvfb. The RX Noise row needs a run on the Pi or in mock mode before merge.
  • RX timeout detected stays classified as a real error. It does not appear in the report, so silencing it would be a guess.
  • NoiseFloor=-113.8dBm at 62.5 kHz bandwidth is roughly 8-10 dB above a quiet band. That is typical for SPI and display noise inside a uConsole, and it explains why weak packets fail CRC. It is an antenna and shielding matter, not software.

🤖 Generated with Claude Code

RadioErrorHandler reported every WARNING from a radio-layer logger as a
fault. LoRa reception noise arrives at WARNING, so a weak or distant
transmitter flipped the header badge to "Radio Error" and flooded the
console.

The failing packets in the report arrive at RSSI -113 dBm and SNR -7 dB
with DeviceErrors=0x0000, so the radio itself is healthy.

- Classify CRC errors, header errors, and empty packets as reception
  noise. Only real errors reach the badge and the toasts.
- Count the noise per category and write one summary line per minute.
- Drop the noise from the console handler. The log file keeps every
  record for bug reports, and DEBUG level shows the noise again.
- Report the counts in a read-only "RX Noise" row in Settings > Logging.

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 74da943eaf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/meshcore_console/meshcore/logging_setup.py Outdated
Codex review on #93: a noise burst shorter than the summary window and
then silence never reached the log, because only the next event ran the
elapsed-time check. Window boundaries also depended on packet arrival
instead of the configured interval.

The first event now opens a window and arms a timer. The timer closes the
window and writes the summary on schedule, whether or not more noise
arrives. RadioErrorHandler.close() flushes the open window, so a log
bundle carries the final tally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cwill747
cwill747 merged commit dcda733 into main Sep 10, 2026
9 checks passed
@cwill747
cwill747 deleted the fix-91 branch September 10, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CRC Errors all over the place

1 participant