Skip to content

feat(lora+gps): Add components for gps, sx126x lora radio. Add preliminary meshtastic component (ai-generated), and update bsps to start testing - #678

Open
finger563 wants to merge 5 commits into
mainfrom
feat/gps-lora-meshtastic
Open

feat(lora+gps): Add components for gps, sx126x lora radio. Add preliminary meshtastic component (ai-generated), and update bsps to start testing#678
finger563 wants to merge 5 commits into
mainfrom
feat/gps-lora-meshtastic

Conversation

@finger563

@finger563 finger563 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Description

Adds LoRa + GPS support to espp, along with a radio-agnostic Meshtastic
node, and wires all three into the T-Deck and M5Stack Cardputer BSPs.

New components

  • sx126xespp::Sx126x driver for Semtech SX1261 / SX1262 / LLCC68
    LoRa radios. Built on espp::BasePeripheral<uint8_t, false>; the caller
    supplies a write_then_read that holds chip-select across the write and
    read phases (one full-duplex SPI transfer), since SX126x commands return
    their status/data in the same CS assertion. LoRa modulation with explicit
    header, configurable frequency / SF / BW / CR / preamble / CRC / sync word,
    TCXO and DC-DC/LDO options, and DIO1 IRQ servicing.
  • gpsespp::Gps (UART NMEA reader task) plus a platform-independent
    espp::NmeaParser (RMC/GGA) and an espp::GpsFix value type with a
    user-supplied on-fix callback.
  • meshtasticespp::MeshtasticNode, radio-agnostic (you provide a
    transmit function and feed it received frames). Implements over-the-air
    interop on the public default channel: 16-byte little-endian packet header,
    AES-CTR payload encryption with the default PSK, djb2 frequency-slot + XOR
    channel hashing, a small hand-written protobuf codec for Text / NodeInfo /
    Position, packet de-duplication, and optional managed-flood rebroadcast.
    The README carries a clean-room / licensing note (Meshtastic firmware and
    protobufs are GPL-3; this is an independent MIT implementation of the
    wire format).

BSP integration — both boards gain initialize_lora(radio_config) /
lora() and initialize_gps(...) / gps():

  • T-Deck: SX1262 (HPD16A module, 1.8 V TCXO on DIO3, DIO2 RF switch) on
    the shared LCD/SD SPI bus. GPS (T-Deck Plus, u-blox MIA-M10Q) over UART.
  • M5Stack Cardputer-Adv + LoRa/GPS Cap: SX1262 (Stamp LoRa-1262 Mini
    module, 3.0 V TCXO on DIO3, LDO regulator) on the shared microSD SPI bus,
    with the Cap's PI4IOE5V6408 IO expander driving the RF switch / GPS LNA;
    ATGM336H GPS over UART.

Examples

  • Standalone sx126x, gps, and meshtastic examples (the meshtastic
    example has a Kconfig board + region selector and runs a full node).
  • The T-Deck GUI example gains a LoRa tab (status, text entry + Send,
    scrolling RX/TX log with RSSI/SNR).
  • The Cardputer GUI example is reorganized into a 6-tab layout
    (Text / LoRa / IMU / GPS / Sys / Help) with keyboard navigation, and now
    brings up GPS when the Cap is present.

Docs / CI — per-component READMEs, a new doc/en/wireless/ docs section
(index + sx126x + gps + meshtastic, each with an example page), Doxyfile
inputs, and build.yml / upload_components.yml matrix entries for the three
new examples.

Motivation and Context

espp had no LoRa or GPS support and no path to interoperate with the
Meshtastic ecosystem. This adds reusable, radio-/board-agnostic building
blocks (a general SX126x driver, an NMEA GPS reader, and a Meshtastic wire
codec) and demonstrates them end-to-end on two popular ESP32-S3 dev boards,
so espp users can build LoRa messaging / mesh / tracker applications.

How has this been tested?

so espp users can build LoRa messaging / mesh / tracker applications.

How has this been tested?

  • Hardware: T-Deck ↔ M5Stack Cardputer-Adv (+ LoRa/GPS Cap) messaging over
    a raw private LoRa link (US LongFast modulation, private sync word 0x12),
    confirmed bidirectional on real devices using the GUI examples' LoRa tabs.
    GPS fixes displayed on both boards. TCXO voltage / regulator settings for
    each module were validated against the vendors' RadioLib configs after an
    initial dead-oscillator symptom on the Cardputer module.
  • Builds: all new/changed examples build clean for esp32s3 with
    ESP-IDF v5.5.2 — sx126x, gps, and meshtastic examples (the latter for
    both the T-Deck and Cardputer-Adv Kconfig targets), plus the updated T-Deck
    and Cardputer GUI examples.
  • Static analysis: cppcheck (--enable=all, the repo's CI config) clean
    on the changed files.
  • Not yet tested: the Meshtastic component has not been validated
    over-the-air against a stock Meshtastic device/phone — all hardware testing
    so far used the raw-LoRa path, which shares the SX126x driver but not the
    Meshtastic framing/crypto. This is the main follow-up before relying on
    mesh interop.

Screenshots (if appropriate, e.g. schematic, board, console logs, lab pictures):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update
  • Hardware (schematic, board, system design) change
  • Software change

Checklist:

  • My change requires a change to the documentation.
  • I have added / updated the documentation related to this change via either README or WIKI

Software

  • I have added tests to cover my changes.
  • I have updated the .github/workflows/build.yml file to add my new test to the automated cloud build github action.
  • All new and existing tests passed.
  • My code follows the code style of this project.

…eliminary meshtastic component (ai-generated), and update bsps to start testing
Copilot AI review requested due to automatic review settings July 27, 2026 01:19
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

✅Static analysis result - no issues found! ✅

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

Adds a new “wireless” documentation section and introduces new gps, sx126x (LoRa radio), and preliminary meshtastic components, then wires LoRa/GPS support into the LilyGo T-Deck and M5Stack Cardputer-Adv BSPs and examples so they can be built/tested in CI.

Changes:

  • Add new components: gps (UART NMEA GNSS), sx126x (SX1261/2/LLCC68 LoRa driver), meshtastic (radio-agnostic Meshtastic-compatible node + example).
  • Update BSPs/examples (t-deck, m5stack-cardputer) to initialize and demonstrate LoRa + GPS (plus shared-bus handling on the Cardputer Cap).
  • Update docs (new doc/en/wireless/*) and CI/component publishing lists to include the new components and examples.

Reviewed changes

Copilot reviewed 68 out of 68 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
doc/en/wireless/index.rst Introduces the “Wireless & Radio APIs” doc section and links new wireless component pages.
doc/en/wireless/sx126x.rst Adds SX126x component documentation entry and API include hooks.
doc/en/wireless/gps.rst Adds GPS component documentation entry and API include hooks.
doc/en/wireless/meshtastic.rst Adds Meshtastic component documentation entry and API include hooks.
doc/en/index.rst Adds the wireless docs section to the top-level docs index.
doc/Doxyfile Adds new components’ headers/examples to Doxygen inputs/example paths.
components/sx126x/CMakeLists.txt Registers the sx126x component build.
components/sx126x/include/sx126x.hpp Defines the public SX126x driver API/types/config.
components/sx126x/src/sx126x.cpp Implements the SX126x driver (SPI command layer + LoRa modem support).
components/sx126x/README.md Adds SX126x component overview and feature list.
components/sx126x/idf_component.yml Adds SX126x component manager metadata (deps/tags/docs link).
components/sx126x/example/CMakeLists.txt Adds SX126x example project configuration.
components/sx126x/example/sdkconfig.defaults Adds SX126x example default sdkconfig.
components/sx126x/example/README.md Adds SX126x example usage documentation.
components/sx126x/example/main/CMakeLists.txt Registers the SX126x example “main” component.
components/sx126x/example/main/Kconfig.projbuild Adds SX126x example menuconfig options (hardware/pins/frequency/etc.).
components/sx126x/example/main/sx126x_example.cpp Adds SX126x example app (bring-up + RX + periodic TX ping).
components/gps/CMakeLists.txt Registers the gps component build.
components/gps/include/gps.hpp Defines the UART-attached GPS driver public API.
components/gps/include/nmea_parser.hpp Defines the platform-independent NMEA parser API.
components/gps/include/gps_fix.hpp Defines the parsed fix struct and timestamp conversion helper.
components/gps/src/gps.cpp Implements the UART driver + background read/parsing task.
components/gps/src/nmea_parser.cpp Implements NMEA parsing/checksum and fix extraction.
components/gps/README.md Adds GPS component overview and capabilities.
components/gps/idf_component.yml Adds GPS component manager metadata (deps/tags/docs link).
components/gps/example/CMakeLists.txt Adds GPS example project configuration.
components/gps/example/sdkconfig.defaults Adds GPS example default sdkconfig.
components/gps/example/README.md Adds GPS example usage documentation.
components/gps/example/main/CMakeLists.txt Registers the GPS example “main” component.
components/gps/example/main/Kconfig.projbuild Adds GPS example menuconfig options (hardware/pins/baud).
components/gps/example/main/gps_example.cpp Adds GPS example app (print fixes).
components/meshtastic/CMakeLists.txt Registers the meshtastic component build.
components/meshtastic/include/meshtastic.hpp Defines MeshtasticNode public API/config/callbacks.
components/meshtastic/include/meshtastic_types.hpp Adds protocol constants and message structs.
components/meshtastic/include/meshtastic_protocol.hpp Declares channel hashing/modem config/header pack/unpack helpers.
components/meshtastic/include/meshtastic_crypto.hpp Declares PSK expansion and AES-CTR payload crypt helpers.
components/meshtastic/include/meshtastic_protobuf.hpp Declares minimal protobuf encode/decode helpers for used messages.
components/meshtastic/src/meshtastic.cpp Implements node behavior (send/receive/dedup/rebroadcast).
components/meshtastic/src/meshtastic_protocol.cpp Implements region/preset-based modem config + header pack/unpack + hashes.
components/meshtastic/src/meshtastic_crypto.cpp Implements PSK expansion and AES-CTR crypt via mbedtls.
components/meshtastic/src/meshtastic_protobuf.cpp Implements minimal protobuf wire-format encode/decode for required messages.
components/meshtastic/README.md Adds Meshtastic component overview/scope/licensing notes.
components/meshtastic/idf_component.yml Adds Meshtastic component manager metadata (deps/tags/docs link).
components/meshtastic/example/CMakeLists.txt Adds Meshtastic example project configuration.
components/meshtastic/example/sdkconfig.defaults Adds Meshtastic example default sdkconfig.
components/meshtastic/example/README.md Adds Meshtastic example usage documentation.
components/meshtastic/example/main/CMakeLists.txt Registers the Meshtastic example “main” component.
components/meshtastic/example/main/Kconfig.projbuild Adds Meshtastic example menuconfig options (hardware/region/intervals/etc.).
components/meshtastic/example/main/meshtastic_example.cpp Adds Meshtastic node example using BSP-provided SX1262 radio.
components/t-deck/CMakeLists.txt Adds gps/sx126x to T-Deck component requirements.
components/t-deck/idf_component.yml Adds gps/sx126x dependencies to the T-Deck component manifest.
components/t-deck/include/t-deck.hpp Adds LoRa + GPS APIs/pins/state to the T-Deck BSP.
components/t-deck/src/lora.cpp Implements T-Deck LoRa + GPS initialization.
components/t-deck/example/README.md Updates T-Deck example docs to include LoRa demo behavior.
components/t-deck/example/main/t_deck_example.cpp Adds LoRa tab/demo wiring and non-blocking TX dispatch via main loop.
components/t-deck/example/main/gui.hpp Extends T-Deck example GUI API to support a LoRa tab and logging.
components/t-deck/example/main/gui.cpp Implements the new LoRa tab UI and thread-safe message/status updates.
components/m5stack-cardputer/CMakeLists.txt Adds gps/sx126x to Cardputer component requirements.
components/m5stack-cardputer/idf_component.yml Adds gps/sx126x dependencies to the Cardputer component manifest.
components/m5stack-cardputer/include/m5stack-cardputer.hpp Adds LoRa+GPS Cap APIs/pins/state and new helper methods.
components/m5stack-cardputer/src/lora_gps_cap.cpp Implements LoRa+GPS Cap SPI-bus bring-up and LoRa/GPS initialization.
components/m5stack-cardputer/src/sdcard.cpp Adjusts SD init to reuse the shared expansion SPI bus when LoRa is present.
components/m5stack-cardputer/example/README.md Updates Cardputer example docs for new tabbed UI + LoRa/GPS features.
components/m5stack-cardputer/example/main/m5stack_cardputer_example.cpp Wires LoRa+GPS demos into the example and updates tab/shortcut behavior.
components/m5stack-cardputer/example/main/gui.hpp Refactors Cardputer GUI into tabbed layout with LoRa/GPS/Sys tabs.
components/m5stack-cardputer/example/main/gui.cpp Implements tabbed UI, LoRa log/status rendering, and new per-tab helpers.
.github/workflows/build.yml Adds gps/meshtastic/sx126x examples to CI build matrix.
.github/workflows/upload_components.yml Adds gps/meshtastic/sx126x to component upload list.

Comment thread components/sx126x/example/main/sx126x_example.cpp
Comment thread components/meshtastic/example/main/meshtastic_example.cpp
Comment thread components/meshtastic/src/meshtastic.cpp
Comment thread components/meshtastic/src/meshtastic.cpp
Comment thread components/t-deck/include/t-deck.hpp Outdated
Comment thread components/m5stack-cardputer/src/lora_gps_cap.cpp Outdated
Comment thread doc/en/wireless/sx126x.rst
Comment thread doc/en/wireless/gps.rst
Comment thread doc/en/wireless/meshtastic.rst
Copilot AI review requested due to automatic review settings July 27, 2026 03:45

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

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

Comment thread components/t-deck/src/lora.cpp
Comment thread components/m5stack-cardputer/src/lora_gps_cap.cpp
Comment thread components/sx126x/example/main/sx126x_example.cpp
Comment thread components/meshtastic/src/meshtastic.cpp
Copilot AI review requested due to automatic review settings July 28, 2026 03:43

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

Copilot reviewed 71 out of 71 changed files in this pull request and generated 1 comment.

Comment thread components/sx126x/src/sx126x.cpp
Copilot AI review requested due to automatic review settings July 28, 2026 03:51
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

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

Copilot reviewed 71 out of 71 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

components/t-deck/example/main/t_deck_example.cpp:1

  • std::transform is used but <algorithm> is not included in this file, which can cause compilation failures depending on toolchain/headers. Add #include <algorithm> alongside the other standard includes.
    components/t-deck/example/main/t_deck_example.cpp:1
  • std::transform is used but <algorithm> is not included in this file, which can cause compilation failures depending on toolchain/headers. Add #include <algorithm> alongside the other standard includes.
    components/meshtastic/src/meshtastic_protobuf.cpp:1
  • pos + length > size can overflow when length is a large varint (and then incorrectly pass the bounds check), and (size_t)length truncation can produce a span smaller than intended. Use an overflow-safe bounds check (e.g., length > (size - pos) after validating length <= SIZE_MAX) before creating the span and advancing pos.

Comment on lines +133 to +147
void Gps::handle_line(std::string_view line) {
logger_.debug("NMEA: {}", line);
if (!NmeaParser::checksum_valid(line)) {
return;
}
if (config_.on_sentence) {
config_.on_sentence(line);
}
bool is_rmc = line.size() > 6 && line.substr(3, 3) == "RMC";
GpsFix fix_copy;
{
std::lock_guard<std::mutex> lock(fix_mutex_);
parser_.parse(line);
fix_copy = parser_.fix();
}
Copilot AI review requested due to automatic review settings July 28, 2026 04:09

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

Copilot reviewed 71 out of 71 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

components/t-deck/example/main/t_deck_example.cpp:1

  • std::transform is used later in this file (in printable()), but <algorithm> is not included in the shown includes. This is a compile error on standard toolchains; add #include <algorithm>.
    components/sx126x/src/sx126x.cpp:1
  • receiving_ is set to false in start_transmit(), so this TX_DONE path will never restart RX even if the radio was in continuous receive before TX (for non-blocking start_transmit() usage). If the intended behavior is “return to RX if we were receiving before TX”, store that prior state (e.g., return_to_rx_after_tx_) in start_transmit() and consult it here; otherwise, update/remove the misleading comment.
    components/meshtastic/src/meshtastic_protobuf.cpp:1
  • The decode paths parse fields without validating that wire matches the expected protobuf wire type for that field (e.g., portnum should be VARINT, payload should be LENGTH). Because this processes untrusted over-the-air frames, add wire-type checks per field and skip(wire) (or return nullopt) on mismatch to avoid mis-decoding random/corrupted bytes into plausible-looking messages.
    components/meshtastic/src/meshtastic.cpp:1
  • On invalid PSK length, expand_psk() returns an empty key and the node continues operating unencrypted (only logging an error). That’s a dangerous failure mode because it can silently downgrade confidentiality if logs are missed. Consider making this a hard failure (e.g., set an internal psk_valid_ flag and have send_*()/handle_frame() refuse to operate when invalid), or provide an explicit allow_unencrypted_fallback config to require a conscious opt-in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants