diff --git a/src/modules/RemoteHardwareModule.cpp b/src/modules/RemoteHardwareModule.cpp index f6b8b2e90..43612e450 100644 --- a/src/modules/RemoteHardwareModule.cpp +++ b/src/modules/RemoteHardwareModule.cpp @@ -15,26 +15,44 @@ // a max of one change per 30 seconds #define WATCH_INTERVAL_MSEC (30 * 1000) +// Tests for access to read from or write to a specified GPIO pin +static bool pinAccessAllowed(uint64_t mask, uint8_t pin) +{ + // If undefined pin access is allowed, don't check the pin and just return true + if (moduleConfig.remote_hardware.allow_undefined_pin_access) { + return true; + } + + // Test to see if the pin is in the list of allowed pins and return true if found + if (mask & (1ULL << pin)) { + return true; + } + + return false; +} + /// Set pin modes for every set bit in a mask -static void pinModes(uint64_t mask, uint8_t mode) +static void pinModes(uint64_t mask, uint8_t mode, uint64_t maskAvailable) { for (uint64_t i = 0; i < NUM_GPIOS; i++) { if (mask & (1ULL << i)) { - pinMode(i, mode); + if (pinAccessAllowed(maskAvailable, i)) { + pinMode(i, mode); + } } } } /// Read all the pins mentioned in a mask -static uint64_t digitalReads(uint64_t mask) +static uint64_t digitalReads(uint64_t mask, uint64_t maskAvailable) { uint64_t res = 0; - pinModes(mask, INPUT_PULLUP); + pinModes(mask, INPUT_PULLUP, maskAvailable); for (uint64_t i = 0; i < NUM_GPIOS; i++) { uint64_t m = 1ULL << i; - if (mask & m) { + if (mask & m && pinAccessAllowed(maskAvailable, i)) { if (digitalRead(i)) { res |= m; } @@ -50,6 +68,11 @@ RemoteHardwareModule::RemoteHardwareModule() { // restrict to the gpio channel for rx boundChannel = Channels::gpioChannel; + + // Pull available pin allowlist from config and build a bitmask out of it for fast comparisons later + for (uint8_t i = 0; i < 4; i++) { + availablePins += 1ULL << moduleConfig.remote_hardware.available_pins[i].gpio_pin; + } } bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, meshtastic_HardwareMessage *pptr) @@ -63,10 +86,10 @@ bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &r // Print notification to LCD screen screen->print("Write GPIOs\n"); - pinModes(p.gpio_mask, OUTPUT); + pinModes(p.gpio_mask, OUTPUT, availablePins); for (uint8_t i = 0; i < NUM_GPIOS; i++) { uint64_t mask = 1ULL << i; - if (p.gpio_mask & mask) { + if (p.gpio_mask & mask && pinAccessAllowed(availablePins, i)) { digitalWrite(i, (p.gpio_value & mask) ? 1 : 0); } } @@ -79,7 +102,7 @@ bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &r if (screen) screen->print("Read GPIOs\n"); - uint64_t res = digitalReads(p.gpio_mask); + uint64_t res = digitalReads(p.gpio_mask, availablePins); // Send the reply meshtastic_HardwareMessage r = meshtastic_HardwareMessage_init_default; @@ -121,7 +144,7 @@ int32_t RemoteHardwareModule::runOnce() if (moduleConfig.remote_hardware.enabled && watchGpios) { if (!Throttle::isWithinTimespanMs(lastWatchMsec, WATCH_INTERVAL_MSEC)) { - uint64_t curVal = digitalReads(watchGpios); + uint64_t curVal = digitalReads(watchGpios, availablePins); lastWatchMsec = millis(); if (curVal != previousWatch) { diff --git a/src/modules/RemoteHardwareModule.h b/src/modules/RemoteHardwareModule.h index dd39f5b69..4dc31d405 100644 --- a/src/modules/RemoteHardwareModule.h +++ b/src/modules/RemoteHardwareModule.h @@ -17,6 +17,9 @@ class RemoteHardwareModule : public ProtobufModule, /// The timestamp of our last watch event (we throttle watches to 1 change every 30 seconds) uint32_t lastWatchMsec = 0; + /// A bitmask of GPIOs that are exposed to the mesh if undefined access is not enabled + uint64_t availablePins = 0; + public: /** Constructor * name is for debugging output