diff --git a/Gpio.cpp b/Gpio.cpp index db790f4..cdb12af 100644 --- a/Gpio.cpp +++ b/Gpio.cpp @@ -3,23 +3,47 @@ #include "Arduino.h" #include "Pins.h" #include "Logger.h" +#include "PreferencesKeys.h" Gpio* Gpio::_inst = nullptr; NukiWrapper* Gpio::_nuki = nullptr; unsigned long Gpio::_lockedTs = 0; const uint Gpio::_debounceTime = 1000; +Gpio::Gpio(Preferences* preferences, NukiWrapper* nuki) +: _preferences(preferences) +{ + loadPinConfiguration(); + + _inst = this; + _inst->init(nuki); +} + void Gpio::init(NukiWrapper* nuki) { _nuki = nuki; - pinMode(TRIGGER_LOCK_PIN, INPUT_PULLUP); - pinMode(TRIGGER_UNLOCK_PIN, INPUT_PULLUP); - pinMode(TRIGGER_UNLATCH_PIN, INPUT_PULLUP); - - attachInterrupt(TRIGGER_LOCK_PIN, isrLock, FALLING); - attachInterrupt(TRIGGER_UNLOCK_PIN, isrUnlock, FALLING); - attachInterrupt(TRIGGER_UNLATCH_PIN, isrUnlatch, FALLING); + for(const auto& entry : _inst->_pinConfiguration) + { + switch(entry.role) + { + case PinRole::InputLock: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrLock, FALLING); + break; + case PinRole::InputUnlock: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrUnlock, FALLING); + break; + case PinRole::InputUnlatch: + pinMode(entry.pin, INPUT_PULLUP); + attachInterrupt(entry.pin, isrUnlatch, FALLING); + break; + default: + pinMode(entry.pin, OUTPUT); + break; + } + } } void Gpio::isrLock() @@ -42,3 +66,46 @@ void Gpio::isrUnlatch() _nuki->unlatch(); _lockedTs = millis() + _debounceTime; } + +const std::vector& Gpio::availablePins() const +{ + return _availablePins; +} + +void Gpio::loadPinConfiguration() +{ + uint8_t serialized[_availablePins.size() * 2]; + + size_t size = _preferences->getBytes(preference_gpio_configuration, serialized, _availablePins.size() * 2); + if(size == 0) + { + return; + } + + size_t numEntries = size / 2; + + _pinConfiguration.clear(); + _pinConfiguration.reserve(numEntries); + for(int i=0; i < numEntries; i++) + { + PinEntry entry; + entry.pin = i * 2; + entry.role = (PinRole)(i * 2 +1); + _pinConfiguration.push_back(entry); + } +} + +void Gpio::savePinConfiguration(const std::vector &pinConfiguration) +{ + uint8_t serialized[pinConfiguration.size() * 2]; + + int len = pinConfiguration.size(); + for(int i=0; i < len; i++) + { + const auto& entry = pinConfiguration[i]; + serialized[i * 2] = entry.pin; + serialized[i * 2 + 1] = (int8_t)entry.role; + } + + _preferences->putBytes(preference_gpio_configuration, serialized, sizeof(serialized)); +} diff --git a/Gpio.h b/Gpio.h index 6d4383e..2ae5eef 100644 --- a/Gpio.h +++ b/Gpio.h @@ -3,13 +3,37 @@ #include "NukiWrapper.h" +enum class PinRole +{ + Undefined, + InputLock, + InputUnlock, + InputUnlatch, + OutputHighLocked, + OutputHighUnlocked, +}; + +struct PinEntry +{ + uint8_t pin = 0; + PinRole role = PinRole::Undefined; +}; + class Gpio { public: - Gpio() = delete; + Gpio(Preferences* preferences, NukiWrapper* nuki); static void init(NukiWrapper* nuki); + void loadPinConfiguration(); + void savePinConfiguration(const std::vector& pinConfiguration); + + const std::vector& availablePins() const; + private: + const std::vector _availablePins = { 2, 4, 5, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 32, 33 }; + + std::vector _pinConfiguration; static const uint _debounceTime; static void IRAM_ATTR isrLock(); @@ -19,4 +43,6 @@ private: static Gpio* _inst; static NukiWrapper* _nuki; static unsigned long _lockedTs; + + Preferences* _preferences = nullptr; }; diff --git a/PreferencesKeys.h b/PreferencesKeys.h index 4aed7cb..be0caee 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -44,6 +44,7 @@ #define preference_cred_password "crdpass" #define preference_publish_authdata "pubauth" #define preference_gpio_locking_enabled "gpiolck" +#define preference_gpio_configuration "gpiocfg" #define preference_publish_debug_info "pubdbg" #define preference_presence_detection_timeout "prdtimeout" #define preference_has_mac_saved "hasmac" diff --git a/main.cpp b/main.cpp index 7fe8644..e697b6f 100644 --- a/main.cpp +++ b/main.cpp @@ -25,6 +25,7 @@ NukiOpenerWrapper* nukiOpener = nullptr; PresenceDetection* presenceDetection = nullptr; Preferences* preferences = nullptr; EthServer* ethServer = nullptr; +Gpio* gpio = nullptr; bool lockEnabled = false; bool openerEnabled = false; @@ -213,10 +214,12 @@ void setup() nuki = new NukiWrapper("NukiHub", deviceId, bleScanner, networkLock, preferences); nuki->initialize(firstStart); - if(preferences->getBool(preference_gpio_locking_enabled)) - { - Gpio::init(nuki); - } + gpio = new Gpio(preferences, nuki); + +// if(preferences->getBool(preference_gpio_locking_enabled)) +// { +// Gpio::init(nuki); +// } } Log->println(openerEnabled ? F("NUKI Opener enabled") : F("NUKI Opener disabled"));