feat(bot): Actions commands, multi-trigger, and user GPIO pins

- Auto-Reply Bot gains Actions (!buzz/!gps/!advert) behind a new per-target
  toggle nested under Commands (bot_actions_dm/ch/room); off by default.
- Bot Trigger fields accept comma-separated multiple phrases, matching any
  one fires the reply.
- New user-assignable GPIO feature (Wio Tracker L1): !gpio1..!gpio4 bot
  commands plus a Tools > GPIO screen. Each pin cycles Off/Input/Output;
  GPIO1/GPIO2 (P0.02/P0.29, the nRF52840's AIN0/AIN5) also offer a read-only
  Analog mode via direct SAADC access. GPIO3/GPIO4 (P0.09/P0.10) are the
  chip's NFC1/NFC2 pins, repurposed as plain GPIO via a one-time UICR
  NFCPINS bit-clear in initVariant() (adapted from Adafruit's own
  nfc_to_gpio example) -- confirmed working on real hardware.
- Fix: DM/room reply-prefix ("@[nick] ") stripping happened at the wrong
  layer, hiding the "To:" header on DM replies and leaking the raw prefix
  into room messages' list view; a related mismatch had the history
  scrollbar's sizing pass wrap room messages with the sender name still
  attached, disagreeing with the actual rendered text.

Build-verified: WioTrackerL1_companion_solo_dual and
WioTrackerL1Eink_companion_solo_dual both compile and link clean
(sizeof(NodePrefs) confirmed 2720 via real build, not guessed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-07-21 20:30:03 +02:00
parent 7113d34ea1
commit 5bfebc6559
15 changed files with 729 additions and 55 deletions

View File

@@ -63,7 +63,31 @@ const uint32_t g_ADigitalPinMap[] = {
0xFF, // 37 MISO
};
// GPIO3/GPIO4 (P0.09/P0.10) are the nRF52840's NFC1/NFC2 pins. Factory UICR
// reserves them for NFC antenna operation -- nrf_gpio_cfg_output/cfg_input
// alone won't work on them until UICR.NFCPINS.PROTECT flips from NFC to
// GPIO, which only takes effect after a reset. This clears a single bit
// (1=NFC -> 0=GPIO), which flash permits without an erase cycle, so no other
// UICR field (BOOTLOADERADDR, APPROTECT, ...) is touched. One-way: going back
// to NFC needs a full chip erase via debugger. No-ops on every boot after the
// first (reads as GPIO already). Adapted from Adafruit's own
// Bluefruit52Lib/examples/Hardware/nfc_to_gpio example.
static void ensureNfcPinsAsGpio() {
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) ==
(UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)) {
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
NVIC_SystemReset(); // UICR is only latched at boot
}
}
void initVariant() {
ensureNfcPinsAsGpio(); // must run first: may reset the board
pinMode(PIN_QSPI_CS, OUTPUT);
digitalWrite(PIN_QSPI_CS, HIGH);

View File

@@ -91,6 +91,17 @@
#define PIN_GPS_STANDBY (0)
#define PIN_GPS_EN (PIN_GPS_STANDBY)
// User-assignable GPIO: 4 pins with no board function, exposed for bot
// commands (!gpio1..!gpio4) and the Tools > GPIO screen. Raw nRF52 pin
// addressing via NRF_GPIO_PIN_MAP (NOT Arduino pin numbers -- these aren't in
// g_ADigitalPinMap[], so pinMode()/digitalWrite() would silently hit whatever
// Arduino pin index happens to equal the raw value instead). See
// initVariant()'s ensureNfcPinsAsGpio() for the GPIO3/GPIO4 NFC-pin caveat.
#define PIN_GPIO1 NRF_GPIO_PIN_MAP(0, 2)
#define PIN_GPIO2 NRF_GPIO_PIN_MAP(0, 29)
#define PIN_GPIO3 NRF_GPIO_PIN_MAP(0, 9) // NFC1
#define PIN_GPIO4 NRF_GPIO_PIN_MAP(0, 10) // NFC2
// QSPI Pins
#define PIN_QSPI_SCK (19)
#define PIN_QSPI_CS (20)