Skip to content

Runtime-configurable GPS pins and baud (companion) 🤖🤖 - #3683

Open
ajgray2017 wants to merge 3 commits into
meshcore-dev:devfrom
ajgray2017:feature/gps-runtime-pins
Open

ajgray2017 wants to merge 3 commits into
meshcore-dev:devfrom
ajgray2017:feature/gps-runtime-pins

Conversation

@ajgray2017

@ajgray2017 ajgray2017 commented Oct 26, 2026 •

Copy link
Copy Markdown

Problem

External GPS modules are often wired to whatever header pins are free (for example on a Heltec V3), and Meshtastic lets users set those pins at runtime. MeshCore fixes PIN_GPS_RX/TX/EN and the baud rate per variant, so such a GPS is never detected and the only fix is a custom build.

Change

  • New sensor settings through the existing CMD_GET/SET_CUSTOM_VAR, so there is no protocol change: gps_rx, gps_tx, gps_en and gps_baud. The names follow the existing PIN_GPS_* macros.
  • The settings always show the effective value, so the app shows the real pin. On a stock Heltec V3 they read gps_rx:47, gps_tx:48, gps_en:26, gps_baud:9600. Setting the board's own value, or -1 (0 for gps_baud), makes the setting follow the board default again.
  • Saved in NodePrefs (gps.pin_rx, gps.pin_tx, gps.pin_en, gps.baud) and applied before sensors.begin(), so changes take effect on the next reboot. Existing prefs load as "board default".
  • Listed even when no GPS was detected. Otherwise a wrong pin could not be fixed from the app.
  • Opt-in: listed only after the firmware calls EnvironmentSensorManager::configureGPS(). Only the companion calls it, because only the companion saves the values. Repeater, room server and sensor firmware are unchanged. Wiring up CommonCLI prefs could be a follow-up.
  • Validation:
    • Input must be a whole number. Pins must be -1 to 127, and the baud rate must be a standard rate.
    • Rejects pins the variant already uses: LoRa, I2C, button, Vext, LED, buzzer and companion serial.
    • On ESP32, also rejects invalid GPIOs, flash/PSRAM pins and the USB serial pins.
    • Rejects one pin for two GPS lines.
    • Values loaded from prefs go through the same checks and fall back to the board default if invalid.
  • LocationProvider::setEnablePin() (a no-op by default) lets MicroNMEALocationProvider take over the enable pin at runtime. It releases the variant's default pin.
  • Not applied to RAK WisBlock GPS boards, which probe their sockets instead.
  • FAQ entry 5.17.

Testing

Two Heltec V3 companions (USB build), each with a u-blox module with TX on GPIO34, RX on GPIO33, VCC from GPIO42. Everything below passed on the first board. The second passed the same set except the gps_rx=49 and empty-value cases, which weren't run there:

  • Stock pins: the GPS is not detected. The vars read gps_rx:47, gps_tx:48, gps_en:26, gps_baud:9600, and gps is absent.
  • Rejected with ERR_CODE_ILLEGAL_ARG:
    • Reserved pins: gps_rx=8 (LoRa NSS), gps_en=29 (flash), gps_en=43 (UART0).
    • Shared pin: gps_rx=34 while gps_tx=34.
    • Bad values: gps_baud=12345, gps_rx=300, gps_rx=127, gps_rx=49, gps_rx=abc, gps_rx=34x, an empty value, gps_baud=abc.
  • Real wiring: set 34/33/42/9600 and rebooted. The GPS was detected (gps listed), the values persisted, and a saved gps=1 was restored.
  • Back to defaults: reset everything (mixing board values and -1/0) and rebooted. The GPS was no longer detected.
  • Unit tests: pio test -e native -e native_kiss_modem passes (54/54).

Compile-checked (all build, no new warnings; wio_wm1110_repeater shows the same 5 ENV_INCLUDE_GPS redefined warnings as dev):
Heltec_v3_companion_radio_usb, Heltec_v3_companion_radio_ble, Heltec_v3_repeater, Heltec_v3_room_server,
Heltec_t114_companion_radio_ble, Heltec_Wireless_Tracker_companion_radio_ble, Tbeam_SX1276_companion_radio_ble,
Tbeam_SX1276_repeater, LilyGo_TDeck_companion_radio_ble, RAK_4631_companion_radio_ble, RAK_4631_companion_radio_ethernet,
RAK_4631_repeater, RAK_4631_repeater_ethernet, RAK_4631_room_server, RAK_4631_room_server_ethernet,
PicoW_repeater, wio-e5-mini_repeater, LilyGo_Tlora_C6_repeater_, wio_wm1110_repeater.

Known limitations

  • Validation only knows pins the variant declares. For example, the Heltec V3 LoRa reset (GPIO12) is declared as RADIOLIB_NC, so it is accepted.
  • The shared-pin check compares the overrides with each other, not with the board defaults. This lets the RX and TX lines be swapped one setting at a time.

Note

#3684 (GPS power cycling) is independent and also branches from dev. Both touch the GPS settings list, GPSPrefs and the FAQ numbering. I test-merged the two: the conflicts are "keep both sides", plus one shared #if block in the header and the FAQ renumbered to 5.18. The result runs on a Heltec V3 with all six GPS settings working.

🤖 Generated with Claude Code

ajgray2017 and others added 3 commits October 26, 2026 10:58
External GPS modules are often wired to arbitrary header pins, but
PIN_GPS_RX/TX/EN and the baud rate were fixed per variant, so such a GPS
was never detected without a custom build.

- New sensor settings gps_rx, gps_tx, gps_en, gps_baud via the existing
  custom vars. They show the effective value; setting a board default
  (or -1 / 0) follows the board again.
- Companion persists them in NodePrefs (gps.pin_rx/pin_tx/pin_en/baud)
  and applies them before sensors.begin(); changes apply after reboot.
- Listed even when no GPS was detected so bad pins can be fixed.
- Pins used by the variant (LoRa, I2C, button, Vext, LED, ...) and ESP32
  flash/PSRAM/USB-serial pins are rejected.
- LocationProvider::setEnablePin() lets MicroNMEALocationProvider switch
  the enable pin at runtime.
- Not applied to RAK WisBlock GPS boards. FAQ 5.17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gps_rx/gps_tx/gps_en were parsed with atoi() and validated as int, then
stored in int8_t. A value above 127 could pass validation and wrap on
store: on a Heltec V3, gps_rx=300 was accepted and saved as 44 (UART0 RX,
which the check itself rejects), and gps_en=290 was saved as 34 while
gps_tx was 34, bypassing the duplicate-pin check. On ESP32,
GPIO_IS_VALID_GPIO() shifts 1ULL by the pin with no bounds check, so pins
of 64 and up were undefined behaviour.

- Parse pins and baud as whole decimal numbers: "abc" or "34x" is now an
  error instead of 0. Pins must be -1..127 before any other check.
- On ESP32, reject pins >= SOC_GPIO_PIN_COUNT before GPIO_IS_VALID_*.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
getSettingName()/getSettingValue() returned the pin settings by range
but, unlike the "gps" entry, did not advance the running index. Any
setting added after them would be looked up at the wrong index and
return NULL while getNumSettings() still counted it; CMD_GET_CUSTOM_VARS
strcpy()s that name. Advance the index so later settings (such as
gps_duty in a separate PR) can be appended in either order.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@fdlamotte

Copy link
Copy Markdown
Collaborator

You should probabli use the cli instead of custom vars, now we have companion cli I'm not sure we'll continue with them as it is not as straightforward to use as we thought

It would be good if it was also usable in repeaters, with as little change as possible (something like how radio prefs work) radio prefs work on both repeater and companion with the same cli interface (although the parameters are not stored in the same way)

An please, you can use AI to help you ... but when you have a direction I think you should try to do your code yourself and not let claude do the commit for you ... it gives a bad impression along with all the bloat text it writes each time (and we as maintainers have to read with the risk of falling asleep). I'm sure you can do better than an AI. (I see no problem in copying generated code, and I sometimes do it myself, but by doing the integration yourself you really embrace what you write and don't let the AI write in your place)

@fdlamotte

Copy link
Copy Markdown
Collaborator

and also, about the PR itself, I'm not really sure ...

As you mention meshtastic, we are not meshtastic ... and don't share the basic philosophy of one unique big firmware (which is a valid stance but not ours)

So it totally make sense that, for a custom board, someone has to configure and compile its own firmware so that the firmware does not get bloated by unnecessary things ...

@fdlamotte

Copy link
Copy Markdown
Collaborator

I'm still not sure about this one ...

If someone makes a custom configuration with it's own gps pinout configuration, he would probably know enough to make the variant that goes with it ...

Won't close this PR (because other maintainers can have their own thought about it), but for now I won't be the one to merge it either ...

This branch has not been deployed

No deployments
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.

2 participants