diff --git a/main/devices/Device.hpp b/main/devices/Device.hpp index 2b44ae4d..d01bbe9e 100644 --- a/main/devices/Device.hpp +++ b/main/devices/Device.hpp @@ -239,7 +239,7 @@ class ConsoleProvider : public LogConsumer { : logRecords(logRecords) , recordedLevel(recordedLevel) { Serial.begin(115200); - Serial1.begin(115200, SERIAL_8N1, pins::RXD0, pins::TXD0); + Serial1.begin(115200, SERIAL_8N1, pins::RXD0->getGpio(), pins::TXD0->getGpio()); #if Serial != Serial0 Serial0.begin(115200); #endif diff --git a/main/devices/DeviceDefinition.hpp b/main/devices/DeviceDefinition.hpp index a12cad4a..2f7eeb7d 100644 --- a/main/devices/DeviceDefinition.hpp +++ b/main/devices/DeviceDefinition.hpp @@ -64,7 +64,7 @@ class DeviceConfiguration : public ConfigurationSection { template class DeviceDefinition { public: - DeviceDefinition(gpio_num_t statusPin, gpio_num_t bootPin) + DeviceDefinition(PinPtr statusPin, PinPtr bootPin) : statusLed("status", statusPin) , bootPin(bootPin) { } @@ -99,7 +99,7 @@ class DeviceDefinition { LedDriver statusLed; PcntManager pcnt; PwmManager pwm; - const gpio_num_t bootPin; + const PinPtr bootPin; private: ConfigurationFile configFile { FileSystem::get(), "/device-config.json" }; diff --git a/main/devices/Pin.hpp b/main/devices/Pin.hpp index d1cd435e..bab43215 100644 --- a/main/devices/Pin.hpp +++ b/main/devices/Pin.hpp @@ -1,6 +1,8 @@ #pragma once +#include #include +#include #include #include @@ -10,68 +12,100 @@ namespace farmhub::devices { +class Pin; +using PinPtr = std::shared_ptr; + class Pin { public: - static gpio_num_t registerPin(const String& name, gpio_num_t pin) { - GPIO_NUMBERS[name] = pin; - GPIO_NAMES[pin] = name; + static PinPtr registerPin(const String& name, gpio_num_t gpio) { + auto pin = std::make_shared(name, gpio); + BY_GPIO[gpio] = pin; + BY_NAME[name] = pin; return pin; } - static gpio_num_t numberOf(const String& name) { - auto it = GPIO_NUMBERS.find(name); - if (it != GPIO_NUMBERS.end()) { + static PinPtr byName(const String& name) { + auto it = BY_NAME.find(name); + if (it != BY_NAME.end()) { return it->second; } - return GPIO_NUM_MAX; + throw std::runtime_error(String("Unknown pin: " + name).c_str()); } - static String nameOf(gpio_num_t pin) { - auto it = GPIO_NAMES.find(pin); - if (it == GPIO_NAMES.end()) { + static PinPtr byGpio(gpio_num_t pin) { + auto it = BY_GPIO.find(pin); + if (it == BY_GPIO.end()) { String name = "GPIO_NUM_" + String(pin); - registerPin(name, pin); - return name; + return registerPin(name, pin); } else { return it->second; } } - static bool isRegistered(gpio_num_t pin) { - return GPIO_NAMES.find(pin) != GPIO_NAMES.end(); + Pin(const String& name, gpio_num_t gpio) + : name(name) + , gpio(gpio) { + } + + inline void pinMode(uint8_t mode) const { + ::pinMode(gpio, mode); + } + + inline void digitalWrite(uint8_t val) const { + ::digitalWrite(gpio, val); + } + + inline int digitalRead() const { + return ::digitalRead(gpio); + } + + inline uint16_t analogRead() const { + return ::analogRead(gpio); + } + + inline const String& getName() const { + return name; + } + + inline gpio_num_t getGpio() const { + return gpio; } private: - bool useName; + const String name; + const gpio_num_t gpio; - static std::map GPIO_NAMES; - static std::map GPIO_NUMBERS; + static std::map BY_GPIO; + static std::map BY_NAME; }; -std::map Pin::GPIO_NAMES; -std::map Pin::GPIO_NUMBERS; +std::map Pin::BY_GPIO; +std::map Pin::BY_NAME; } // namespace farmhub::devices namespace ArduinoJson { using farmhub::devices::Pin; +using farmhub::devices::PinPtr; template <> -struct Converter { - static void toJson(const gpio_num_t& src, JsonVariant dst) { - if (Pin::isRegistered(src)) { - dst.set(Pin::nameOf(src)); +struct Converter { + static void toJson(const PinPtr& src, JsonVariant dst) { + if (src == nullptr) { + dst.set(nullptr); + } else if (src->getName().startsWith("GPIO_NUM_")) { + dst.set(static_cast(src->getGpio())); } else { - dst.set(static_cast(src)); + dst.set(src->getName()); } } - static gpio_num_t fromJson(JsonVariantConst src) { + static PinPtr fromJson(JsonVariantConst src) { if (src.is()) { - return Pin::numberOf(src.as()); + return Pin::byName(src.as()); } else { - return static_cast(src.as()); + return Pin::byGpio(static_cast(src.as())); } } diff --git a/main/devices/UglyDucklingMk4.hpp b/main/devices/UglyDucklingMk4.hpp index 6dfa15de..d15f7ac1 100644 --- a/main/devices/UglyDucklingMk4.hpp +++ b/main/devices/UglyDucklingMk4.hpp @@ -34,25 +34,25 @@ class Mk4Config }; namespace pins { -static gpio_num_t BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); -static gpio_num_t STATUS = Pin::registerPin("STATUS", GPIO_NUM_26); - -static gpio_num_t SOIL_MOISTURE = Pin::registerPin("SOIL_MOISTURE", GPIO_NUM_6); -static gpio_num_t SOIL_TEMP = Pin::registerPin("SOIL_TEMP", GPIO_NUM_7); - -static gpio_num_t VALVE_EN = Pin::registerPin("VALVE_EN", GPIO_NUM_10); -static gpio_num_t VALVE_PH = Pin::registerPin("VALVE_PH", GPIO_NUM_11); -static gpio_num_t VALVE_FAULT = Pin::registerPin("VALVE_FAULT", GPIO_NUM_12); -static gpio_num_t VALVE_SLEEP = Pin::registerPin("VALVE_SLEEP", GPIO_NUM_13); -static gpio_num_t VALVE_MODE1 = Pin::registerPin("VALVE_MODE1", GPIO_NUM_14); -static gpio_num_t VALVE_MODE2 = Pin::registerPin("VALVE_MODE2", GPIO_NUM_15); -static gpio_num_t VALVE_CURRENT = Pin::registerPin("VALVE_CURRENT", GPIO_NUM_16); -static gpio_num_t FLOW = Pin::registerPin("FLOW", GPIO_NUM_17); - -static gpio_num_t SDA = Pin::registerPin("SDA", GPIO_NUM_8); -static gpio_num_t SCL = Pin::registerPin("SCL", GPIO_NUM_9); -static gpio_num_t RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); -static gpio_num_t TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); +static PinPtr BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); +static PinPtr STATUS = Pin::registerPin("STATUS", GPIO_NUM_26); + +static PinPtr SOIL_MOISTURE = Pin::registerPin("SOIL_MOISTURE", GPIO_NUM_6); +static PinPtr SOIL_TEMP = Pin::registerPin("SOIL_TEMP", GPIO_NUM_7); + +static PinPtr VALVE_EN = Pin::registerPin("VALVE_EN", GPIO_NUM_10); +static PinPtr VALVE_PH = Pin::registerPin("VALVE_PH", GPIO_NUM_11); +static PinPtr VALVE_FAULT = Pin::registerPin("VALVE_FAULT", GPIO_NUM_12); +static PinPtr VALVE_SLEEP = Pin::registerPin("VALVE_SLEEP", GPIO_NUM_13); +static PinPtr VALVE_MODE1 = Pin::registerPin("VALVE_MODE1", GPIO_NUM_14); +static PinPtr VALVE_MODE2 = Pin::registerPin("VALVE_MODE2", GPIO_NUM_15); +static PinPtr VALVE_CURRENT = Pin::registerPin("VALVE_CURRENT", GPIO_NUM_16); +static PinPtr FLOW = Pin::registerPin("FLOW", GPIO_NUM_17); + +static PinPtr SDA = Pin::registerPin("SDA", GPIO_NUM_8); +static PinPtr SCL = Pin::registerPin("SCL", GPIO_NUM_9); +static PinPtr RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); +static PinPtr TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); } // namespace pins class UglyDucklingMk4 : public DeviceDefinition { diff --git a/main/devices/UglyDucklingMk5.hpp b/main/devices/UglyDucklingMk5.hpp index 24b16292..d9ac60ac 100644 --- a/main/devices/UglyDucklingMk5.hpp +++ b/main/devices/UglyDucklingMk5.hpp @@ -33,46 +33,46 @@ class Mk5Config }; namespace pins { -static gpio_num_t BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); -static gpio_num_t BATTERY = Pin::registerPin("BATTERY", GPIO_NUM_1); -static gpio_num_t STATUS = Pin::registerPin("STATUS", GPIO_NUM_2); -static gpio_num_t AIPROPI = Pin::registerPin("AIPROPI", GPIO_NUM_4); - -static gpio_num_t IOA1 = Pin::registerPin("A1", GPIO_NUM_5); -static gpio_num_t IOA2 = Pin::registerPin("A2", GPIO_NUM_6); -static gpio_num_t BIPROPI = Pin::registerPin("BIPROPI", GPIO_NUM_7); -static gpio_num_t IOB1 = Pin::registerPin("B1", GPIO_NUM_15); -static gpio_num_t AIN1 = Pin::registerPin("AIN1", GPIO_NUM_16); -static gpio_num_t AIN2 = Pin::registerPin("AIN2", GPIO_NUM_17); -static gpio_num_t BIN1 = Pin::registerPin("BIN1", GPIO_NUM_18); -static gpio_num_t BIN2 = Pin::registerPin("BIN2", GPIO_NUM_8); - -static gpio_num_t DMINUS = Pin::registerPin("D-", GPIO_NUM_19); -static gpio_num_t DPLUS = Pin::registerPin("D+", GPIO_NUM_20); - -static gpio_num_t IOB2 = Pin::registerPin("B2", GPIO_NUM_9); - -static gpio_num_t NSLEEP = Pin::registerPin("NSLEEP", GPIO_NUM_10); -static gpio_num_t NFault = Pin::registerPin("NFault", GPIO_NUM_11); -static gpio_num_t IOC4 = Pin::registerPin("C4", GPIO_NUM_12); -static gpio_num_t IOC3 = Pin::registerPin("C3", GPIO_NUM_13); -static gpio_num_t IOC2 = Pin::registerPin("C2", GPIO_NUM_14); -static gpio_num_t IOC1 = Pin::registerPin("C1", GPIO_NUM_21); -static gpio_num_t IOD4 = Pin::registerPin("D4", GPIO_NUM_47); -static gpio_num_t IOD3 = Pin::registerPin("D3", GPIO_NUM_48); - -static gpio_num_t SDA = Pin::registerPin("SDA", GPIO_NUM_35); -static gpio_num_t SCL = Pin::registerPin("SCL", GPIO_NUM_36); - -static gpio_num_t IOD1 = Pin::registerPin("D1", GPIO_NUM_37); -static gpio_num_t IOD2 = Pin::registerPin("D2", GPIO_NUM_38); - -static gpio_num_t TCK = Pin::registerPin("TCK", GPIO_NUM_39); -static gpio_num_t TDO = Pin::registerPin("TDO", GPIO_NUM_40); -static gpio_num_t TDI = Pin::registerPin("TDI", GPIO_NUM_41); -static gpio_num_t TMS = Pin::registerPin("TMS", GPIO_NUM_42); -static gpio_num_t RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); -static gpio_num_t TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); +static PinPtr BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); +static PinPtr BATTERY = Pin::registerPin("BATTERY", GPIO_NUM_1); +static PinPtr STATUS = Pin::registerPin("STATUS", GPIO_NUM_2); +static PinPtr AIPROPI = Pin::registerPin("AIPROPI", GPIO_NUM_4); + +static PinPtr IOA1 = Pin::registerPin("A1", GPIO_NUM_5); +static PinPtr IOA2 = Pin::registerPin("A2", GPIO_NUM_6); +static PinPtr BIPROPI = Pin::registerPin("BIPROPI", GPIO_NUM_7); +static PinPtr IOB1 = Pin::registerPin("B1", GPIO_NUM_15); +static PinPtr AIN1 = Pin::registerPin("AIN1", GPIO_NUM_16); +static PinPtr AIN2 = Pin::registerPin("AIN2", GPIO_NUM_17); +static PinPtr BIN1 = Pin::registerPin("BIN1", GPIO_NUM_18); +static PinPtr BIN2 = Pin::registerPin("BIN2", GPIO_NUM_8); + +static PinPtr DMINUS = Pin::registerPin("D-", GPIO_NUM_19); +static PinPtr DPLUS = Pin::registerPin("D+", GPIO_NUM_20); + +static PinPtr IOB2 = Pin::registerPin("B2", GPIO_NUM_9); + +static PinPtr NSLEEP = Pin::registerPin("NSLEEP", GPIO_NUM_10); +static PinPtr NFault = Pin::registerPin("NFault", GPIO_NUM_11); +static PinPtr IOC4 = Pin::registerPin("C4", GPIO_NUM_12); +static PinPtr IOC3 = Pin::registerPin("C3", GPIO_NUM_13); +static PinPtr IOC2 = Pin::registerPin("C2", GPIO_NUM_14); +static PinPtr IOC1 = Pin::registerPin("C1", GPIO_NUM_21); +static PinPtr IOD4 = Pin::registerPin("D4", GPIO_NUM_47); +static PinPtr IOD3 = Pin::registerPin("D3", GPIO_NUM_48); + +static PinPtr SDA = Pin::registerPin("SDA", GPIO_NUM_35); +static PinPtr SCL = Pin::registerPin("SCL", GPIO_NUM_36); + +static PinPtr IOD1 = Pin::registerPin("D1", GPIO_NUM_37); +static PinPtr IOD2 = Pin::registerPin("D2", GPIO_NUM_38); + +static PinPtr TCK = Pin::registerPin("TCK", GPIO_NUM_39); +static PinPtr TDO = Pin::registerPin("TDO", GPIO_NUM_40); +static PinPtr TDI = Pin::registerPin("TDI", GPIO_NUM_41); +static PinPtr TMS = Pin::registerPin("TMS", GPIO_NUM_42); +static PinPtr RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); +static PinPtr TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); } // namespace pins class UglyDucklingMk5 : public DeviceDefinition { diff --git a/main/devices/UglyDucklingMk6.hpp b/main/devices/UglyDucklingMk6.hpp index 559272fd..8a4d9550 100644 --- a/main/devices/UglyDucklingMk6.hpp +++ b/main/devices/UglyDucklingMk6.hpp @@ -27,47 +27,47 @@ using namespace farmhub::peripherals::valve; namespace farmhub::devices { namespace pins { -static gpio_num_t BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); -static gpio_num_t BATTERY = Pin::registerPin("BATTERY", GPIO_NUM_1); -static gpio_num_t STATUS = Pin::registerPin("STATUS", GPIO_NUM_2); -static gpio_num_t STATUS2 = Pin::registerPin("STATUS2", GPIO_NUM_4); - -static gpio_num_t IOB1 = Pin::registerPin("B1", GPIO_NUM_5); -static gpio_num_t IOA1 = Pin::registerPin("A1", GPIO_NUM_6); -static gpio_num_t DIPROPI = Pin::registerPin("DIPROPI", GPIO_NUM_7); -static gpio_num_t IOA2 = Pin::registerPin("A2", GPIO_NUM_15); -static gpio_num_t AIN1 = Pin::registerPin("AIN1", GPIO_NUM_16); -static gpio_num_t AIN2 = Pin::registerPin("AIN2", GPIO_NUM_17); -static gpio_num_t BIN2 = Pin::registerPin("BIN2", GPIO_NUM_18); -static gpio_num_t BIN1 = Pin::registerPin("BIN1", GPIO_NUM_8); - -static gpio_num_t DMINUS = Pin::registerPin("D-", GPIO_NUM_19); -static gpio_num_t DPLUS = Pin::registerPin("D+", GPIO_NUM_20); - -static gpio_num_t LEDA_RED = Pin::registerPin("LEDA_RED", GPIO_NUM_46); -static gpio_num_t LEDA_GREEN = Pin::registerPin("LEDA_GREEN", GPIO_NUM_9); - -static gpio_num_t NFault = Pin::registerPin("NFault", GPIO_NUM_11); -static gpio_num_t BTN1 = Pin::registerPin("BTN1", GPIO_NUM_12); -static gpio_num_t BTN2 = Pin::registerPin("BTN2", GPIO_NUM_13); -static gpio_num_t IOC4 = Pin::registerPin("C4", GPIO_NUM_14); -static gpio_num_t IOC3 = Pin::registerPin("C3", GPIO_NUM_21); -static gpio_num_t IOC2 = Pin::registerPin("C2", GPIO_NUM_47); -static gpio_num_t IOC1 = Pin::registerPin("C1", GPIO_NUM_48); -static gpio_num_t IOB2 = Pin::registerPin("B2", GPIO_NUM_45); - -static gpio_num_t SDA = Pin::registerPin("SDA", GPIO_NUM_35); -static gpio_num_t SCL = Pin::registerPin("SCL", GPIO_NUM_36); - -static gpio_num_t LEDB_GREEN = Pin::registerPin("LEDB_GREEN", GPIO_NUM_37); -static gpio_num_t LEDB_RED = Pin::registerPin("LEDB_RED", GPIO_NUM_38); - -static gpio_num_t TCK = Pin::registerPin("TCK", GPIO_NUM_39); -static gpio_num_t TDO = Pin::registerPin("TDO", GPIO_NUM_40); -static gpio_num_t TDI = Pin::registerPin("TDI", GPIO_NUM_41); -static gpio_num_t TMS = Pin::registerPin("TMS", GPIO_NUM_42); -static gpio_num_t RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); -static gpio_num_t TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); +static PinPtr BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); +static PinPtr BATTERY = Pin::registerPin("BATTERY", GPIO_NUM_1); +static PinPtr STATUS = Pin::registerPin("STATUS", GPIO_NUM_2); +static PinPtr STATUS2 = Pin::registerPin("STATUS2", GPIO_NUM_4); + +static PinPtr IOB1 = Pin::registerPin("B1", GPIO_NUM_5); +static PinPtr IOA1 = Pin::registerPin("A1", GPIO_NUM_6); +static PinPtr DIPROPI = Pin::registerPin("DIPROPI", GPIO_NUM_7); +static PinPtr IOA2 = Pin::registerPin("A2", GPIO_NUM_15); +static PinPtr AIN1 = Pin::registerPin("AIN1", GPIO_NUM_16); +static PinPtr AIN2 = Pin::registerPin("AIN2", GPIO_NUM_17); +static PinPtr BIN2 = Pin::registerPin("BIN2", GPIO_NUM_18); +static PinPtr BIN1 = Pin::registerPin("BIN1", GPIO_NUM_8); + +static PinPtr DMINUS = Pin::registerPin("D-", GPIO_NUM_19); +static PinPtr DPLUS = Pin::registerPin("D+", GPIO_NUM_20); + +static PinPtr LEDA_RED = Pin::registerPin("LEDA_RED", GPIO_NUM_46); +static PinPtr LEDA_GREEN = Pin::registerPin("LEDA_GREEN", GPIO_NUM_9); + +static PinPtr NFault = Pin::registerPin("NFault", GPIO_NUM_11); +static PinPtr BTN1 = Pin::registerPin("BTN1", GPIO_NUM_12); +static PinPtr BTN2 = Pin::registerPin("BTN2", GPIO_NUM_13); +static PinPtr IOC4 = Pin::registerPin("C4", GPIO_NUM_14); +static PinPtr IOC3 = Pin::registerPin("C3", GPIO_NUM_21); +static PinPtr IOC2 = Pin::registerPin("C2", GPIO_NUM_47); +static PinPtr IOC1 = Pin::registerPin("C1", GPIO_NUM_48); +static PinPtr IOB2 = Pin::registerPin("B2", GPIO_NUM_45); + +static PinPtr SDA = Pin::registerPin("SDA", GPIO_NUM_35); +static PinPtr SCL = Pin::registerPin("SCL", GPIO_NUM_36); + +static PinPtr LEDB_GREEN = Pin::registerPin("LEDB_GREEN", GPIO_NUM_37); +static PinPtr LEDB_RED = Pin::registerPin("LEDB_RED", GPIO_NUM_38); + +static PinPtr TCK = Pin::registerPin("TCK", GPIO_NUM_39); +static PinPtr TDO = Pin::registerPin("TDO", GPIO_NUM_40); +static PinPtr TDI = Pin::registerPin("TDI", GPIO_NUM_41); +static PinPtr TMS = Pin::registerPin("TMS", GPIO_NUM_42); +static PinPtr RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); +static PinPtr TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); } // namespace pins class Mk6Config @@ -81,7 +81,7 @@ class Mk6Config * @brief The built-in motor driver's nSLEEP pin can be manually set by a jumper, * but can be connected to a GPIO pin, too. Defaults to C2. */ - Property motorNSleepPin { this, "motorNSleepPin", pins::IOC2 }; + Property motorNSleepPin { this, "motorNSleepPin", pins::IOC2 }; }; class UglyDucklingMk6 : public DeviceDefinition { diff --git a/main/devices/UglyDucklingMk7.hpp b/main/devices/UglyDucklingMk7.hpp index e418b775..229e4501 100644 --- a/main/devices/UglyDucklingMk7.hpp +++ b/main/devices/UglyDucklingMk7.hpp @@ -25,53 +25,53 @@ using namespace farmhub::peripherals::valve; namespace farmhub::devices { namespace pins { -static gpio_num_t BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); +static PinPtr BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); -static gpio_num_t IOA2 = Pin::registerPin("A2", GPIO_NUM_1); -static gpio_num_t IOA1 = Pin::registerPin("A1", GPIO_NUM_2); -static gpio_num_t IOA3 = Pin::registerPin("A3", GPIO_NUM_3); -static gpio_num_t IOB3 = Pin::registerPin("B3", GPIO_NUM_4); -static gpio_num_t IOB1 = Pin::registerPin("B1", GPIO_NUM_5); -static gpio_num_t IOB2 = Pin::registerPin("B2", GPIO_NUM_6); +static PinPtr IOA2 = Pin::registerPin("A2", GPIO_NUM_1); +static PinPtr IOA1 = Pin::registerPin("A1", GPIO_NUM_2); +static PinPtr IOA3 = Pin::registerPin("A3", GPIO_NUM_3); +static PinPtr IOB3 = Pin::registerPin("B3", GPIO_NUM_4); +static PinPtr IOB1 = Pin::registerPin("B1", GPIO_NUM_5); +static PinPtr IOB2 = Pin::registerPin("B2", GPIO_NUM_6); // GPIO_NUM_7 is NC -static gpio_num_t BAT_GPIO = Pin::registerPin("BAT_GPIO", GPIO_NUM_8); +static PinPtr BAT_GPIO = Pin::registerPin("BAT_GPIO", GPIO_NUM_8); -static gpio_num_t FSPIHD = Pin::registerPin("FSPIHD", GPIO_NUM_9); -static gpio_num_t FSPICS0 = Pin::registerPin("FSPICS0", GPIO_NUM_10); -static gpio_num_t FSPID = Pin::registerPin("FSPID", GPIO_NUM_11); -static gpio_num_t FSPICLK = Pin::registerPin("FSPICLK", GPIO_NUM_12); -static gpio_num_t FSPIQ = Pin::registerPin("FSPIQ", GPIO_NUM_13); -static gpio_num_t FSPIWP = Pin::registerPin("FSPIWP", GPIO_NUM_14); +static PinPtr FSPIHD = Pin::registerPin("FSPIHD", GPIO_NUM_9); +static PinPtr FSPICS0 = Pin::registerPin("FSPICS0", GPIO_NUM_10); +static PinPtr FSPID = Pin::registerPin("FSPID", GPIO_NUM_11); +static PinPtr FSPICLK = Pin::registerPin("FSPICLK", GPIO_NUM_12); +static PinPtr FSPIQ = Pin::registerPin("FSPIQ", GPIO_NUM_13); +static PinPtr FSPIWP = Pin::registerPin("FSPIWP", GPIO_NUM_14); -static gpio_num_t STATUS = Pin::registerPin("STATUS", GPIO_NUM_15); -static gpio_num_t LOADEN = Pin::registerPin("LOADEN", GPIO_NUM_16); +static PinPtr STATUS = Pin::registerPin("STATUS", GPIO_NUM_15); +static PinPtr LOADEN = Pin::registerPin("LOADEN", GPIO_NUM_16); -static gpio_num_t SCL = Pin::registerPin("SCL", GPIO_NUM_17); -static gpio_num_t SDA = Pin::registerPin("SDA", GPIO_NUM_18); +static PinPtr SCL = Pin::registerPin("SCL", GPIO_NUM_17); +static PinPtr SDA = Pin::registerPin("SDA", GPIO_NUM_18); -static gpio_num_t DMINUS = Pin::registerPin("D-", GPIO_NUM_19); -static gpio_num_t DPLUS = Pin::registerPin("D+", GPIO_NUM_20); +static PinPtr DMINUS = Pin::registerPin("D-", GPIO_NUM_19); +static PinPtr DPLUS = Pin::registerPin("D+", GPIO_NUM_20); -static gpio_num_t IOX1 = Pin::registerPin("X1", GPIO_NUM_21); +static PinPtr IOX1 = Pin::registerPin("X1", GPIO_NUM_21); // GPIO_NUM_22 to GPIO_NUM_36 are NC -static gpio_num_t DBIN1 = Pin::registerPin("DBIN1", GPIO_NUM_37); -static gpio_num_t DBIN2 = Pin::registerPin("DBIN2", GPIO_NUM_38); -static gpio_num_t DAIN2 = Pin::registerPin("DAIN2", GPIO_NUM_39); -static gpio_num_t DAIN1 = Pin::registerPin("DAIN1", GPIO_NUM_40); -static gpio_num_t DNFault = Pin::registerPin("DNFault", GPIO_NUM_41); +static PinPtr DBIN1 = Pin::registerPin("DBIN1", GPIO_NUM_37); +static PinPtr DBIN2 = Pin::registerPin("DBIN2", GPIO_NUM_38); +static PinPtr DAIN2 = Pin::registerPin("DAIN2", GPIO_NUM_39); +static PinPtr DAIN1 = Pin::registerPin("DAIN1", GPIO_NUM_40); +static PinPtr DNFault = Pin::registerPin("DNFault", GPIO_NUM_41); // GPIO_NUM_42 is NC -static gpio_num_t TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); -static gpio_num_t RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); -static gpio_num_t IOX2 = Pin::registerPin("X2", GPIO_NUM_45); -static gpio_num_t STATUS2 = Pin::registerPin("STATUS2", GPIO_NUM_46); -static gpio_num_t IOB4 = Pin::registerPin("B4", GPIO_NUM_47); -static gpio_num_t IOA4 = Pin::registerPin("A4", GPIO_NUM_48); +static PinPtr TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43); +static PinPtr RXD0 = Pin::registerPin("RXD0", GPIO_NUM_44); +static PinPtr IOX2 = Pin::registerPin("X2", GPIO_NUM_45); +static PinPtr STATUS2 = Pin::registerPin("STATUS2", GPIO_NUM_46); +static PinPtr IOB4 = Pin::registerPin("B4", GPIO_NUM_47); +static PinPtr IOA4 = Pin::registerPin("A4", GPIO_NUM_48); } // namespace pins class Mk7Config diff --git a/main/kernel/I2CManager.hpp b/main/kernel/I2CManager.hpp index 6234820d..0824863c 100644 --- a/main/kernel/I2CManager.hpp +++ b/main/kernel/I2CManager.hpp @@ -7,21 +7,24 @@ #include #include +#include #include namespace farmhub::kernel { -using GpioPair = std::pair; +using farmhub::devices::PinPtr; + +using GpioPair = std::pair; using TwoWireMap = std::map; struct I2CConfig { public: uint8_t address; - gpio_num_t sda; - gpio_num_t scl; + PinPtr sda; + PinPtr scl; String toString() const { - return String("I2C address: 0x") + String(address, HEX) + ", SDA: " + String(sda) + ", SCL: " + String(scl); + return String("I2C address: 0x") + String(address, HEX) + ", SDA: " + sda->getName() + ", SCL: " + scl->getName(); } }; @@ -31,21 +34,23 @@ class I2CManager { return getWireFor(config.sda, config.scl); } - TwoWire& getWireFor(gpio_num_t sda, gpio_num_t scl) { + TwoWire& getWireFor(PinPtr sda, PinPtr scl) { GpioPair key = std::make_pair(sda, scl); auto it = wireMap.find(key); if (it != wireMap.end()) { - Log.trace("Reusing already registered I2C bus for SDA: %d, SCL: %d", sda, scl); + Log.trace("Reusing already registered I2C bus for SDA: %s, SCL: %s", + sda->getName().c_str(), scl->getName().c_str()); return *(it->second); } else { - Log.trace("Creating new I2C bus for SDA: %d, SCL: %d", sda, scl); + Log.trace("Creating new I2C bus for SDA: %s, SCL: %s", + sda->getName().c_str(), scl->getName().c_str()); if (nextBus >= 2) { throw std::runtime_error("Maximum number of I2C buses reached"); } TwoWire* wire = new TwoWire(nextBus++); - if (!wire->begin(sda, scl)) { + if (!wire->begin(sda->getGpio(), scl->getGpio())) { throw std::runtime_error( - String("Failed to initialize I2C bus for SDA: " + String(sda) + ", SCL: " + String(scl)).c_str()); + String("Failed to initialize I2C bus for SDA: " + sda->getName() + ", SCL: " + scl->getName()).c_str()); } wireMap[key] = wire; return *wire; diff --git a/main/kernel/PcntManager.hpp b/main/kernel/PcntManager.hpp index 89b65710..770b7d57 100644 --- a/main/kernel/PcntManager.hpp +++ b/main/kernel/PcntManager.hpp @@ -15,13 +15,13 @@ namespace farmhub::kernel { // TODO Limit number of channels available struct PcntUnit { - PcntUnit(pcnt_unit_handle_t unit, gpio_num_t pin) + PcntUnit(pcnt_unit_handle_t unit, PinPtr pin) : unit(unit) , pin(pin) { } PcntUnit() - : PcntUnit(nullptr, GPIO_NUM_MAX) { + : PcntUnit(nullptr, nullptr) { } PcntUnit(const PcntUnit& other) @@ -48,18 +48,18 @@ struct PcntUnit { return count; } - gpio_num_t getPin() const { + PinPtr getPin() const { return pin; } private: pcnt_unit_handle_t unit; - gpio_num_t pin; + PinPtr pin; }; class PcntManager { public: - PcntUnit registerUnit(gpio_num_t pin) { + PcntUnit registerUnit(PinPtr pin) { pcnt_unit_config_t unitConfig = { .low_limit = std::numeric_limits::min(), .high_limit = std::numeric_limits::max(), @@ -75,7 +75,7 @@ class PcntManager { ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(unit, &filterConfig)); pcnt_chan_config_t channelConfig = { - .edge_gpio_num = pin, + .edge_gpio_num = pin->getGpio(), .level_gpio_num = -1, .flags = {}, }; @@ -87,8 +87,8 @@ class PcntManager { ESP_ERROR_CHECK(pcnt_unit_clear_count(unit)); ESP_ERROR_CHECK(pcnt_unit_start(unit)); - Log.debug("Registered PCNT unit on pin %d", - pin); + Log.debug("Registered PCNT unit on pin %s", + pin->getName().c_str()); return PcntUnit(unit, pin); } }; diff --git a/main/kernel/PwmManager.hpp b/main/kernel/PwmManager.hpp index 9ab6c70d..91278a3a 100644 --- a/main/kernel/PwmManager.hpp +++ b/main/kernel/PwmManager.hpp @@ -11,7 +11,7 @@ namespace farmhub::kernel { // TODO Limit number of channels available struct PwmPin { - PwmPin(gpio_num_t pin, uint32_t freq, uint8_t resolutionBits) + PwmPin(PinPtr pin, uint32_t freq, uint8_t resolutionBits) : pin(pin) , freq(freq) , resolutionBits(resolutionBits) { @@ -26,20 +26,20 @@ struct PwmPin { } void write(uint32_t value) const { - ledcWrite(pin, value); + ledcWrite(pin->getGpio(), value); } - const gpio_num_t pin; + const PinPtr pin; const uint32_t freq; const uint8_t resolutionBits; }; class PwmManager { public: - PwmPin registerPin(gpio_num_t pin, uint32_t freq, uint8_t resolutionBits = 8) { - ledcAttach(pin, freq, resolutionBits); - Log.debug("Registered PWM channel on pin %d with freq %ld and resolution %d", - pin, freq, resolutionBits); + PwmPin registerPin(PinPtr pin, uint32_t freq, uint8_t resolutionBits = 8) { + ledcAttach(pin->getGpio(), freq, resolutionBits); + Log.debug("Registered PWM channel on pin %s with freq %ld and resolution %d", + pin->getName().c_str(), freq, resolutionBits); return PwmPin(pin, freq, resolutionBits); } }; diff --git a/main/kernel/drivers/BatteryDriver.hpp b/main/kernel/drivers/BatteryDriver.hpp index 78fec16a..c4a0e64b 100644 --- a/main/kernel/drivers/BatteryDriver.hpp +++ b/main/kernel/drivers/BatteryDriver.hpp @@ -2,9 +2,12 @@ #include +#include #include #include +using farmhub::devices::PinPtr; + namespace farmhub::kernel::drivers { class BatteryDriver : public TelemetryProvider { @@ -20,22 +23,22 @@ class BatteryDriver : public TelemetryProvider { class AnalogBatteryDriver : public BatteryDriver { public: - AnalogBatteryDriver(gpio_num_t pin, float voltageDividerRatio) + AnalogBatteryDriver(PinPtr pin, float voltageDividerRatio) : pin(pin) , voltageDividerRatio(voltageDividerRatio) { - Log.info("Initializing analog battery driver on pin %d", - pin); + Log.info("Initializing analog battery driver on pin %s", + pin->getName().c_str()); - pinMode(pin, INPUT); + pin->pinMode(INPUT); } float getVoltage() { - auto batteryLevel = analogRead(pin); + auto batteryLevel = pin->analogRead(); return batteryLevel * 3.3 / 4096 * voltageDividerRatio; } private: - const gpio_num_t pin; + const PinPtr pin; const float voltageDividerRatio; }; diff --git a/main/kernel/drivers/Bq27220Driver.hpp b/main/kernel/drivers/Bq27220Driver.hpp index 34843f81..6538d6b6 100644 --- a/main/kernel/drivers/Bq27220Driver.hpp +++ b/main/kernel/drivers/Bq27220Driver.hpp @@ -12,11 +12,11 @@ namespace farmhub::kernel::drivers { class Bq27220Driver : public BatteryDriver { public: - Bq27220Driver(I2CManager& i2c, gpio_num_t sda, gpio_num_t scl, const uint8_t address = 0x55) + Bq27220Driver(I2CManager& i2c, PinPtr sda, PinPtr scl, const uint8_t address = 0x55) : wire(i2c.getWireFor(sda, scl)) , address(address) { - Log.info("Initializing BQ27220 driver on SDA %d, SCL %d", - sda, scl); + Log.info("Initializing BQ27220 driver on SDA %s, SCL %s", + sda->getName().c_str(), scl->getName().c_str()); wire.beginTransmission(address); if (wire.endTransmission() != 0) { diff --git a/main/kernel/drivers/Drv8801Driver.hpp b/main/kernel/drivers/Drv8801Driver.hpp index f78d015b..843aeadd 100644 --- a/main/kernel/drivers/Drv8801Driver.hpp +++ b/main/kernel/drivers/Drv8801Driver.hpp @@ -28,32 +28,38 @@ class Drv8801Driver // Note: on Ugly Duckling MK5, the DRV8874's PMODE is wired to 3.3V, so it's locked in PWM mode Drv8801Driver( PwmManager& pwm, - gpio_num_t enablePin, - gpio_num_t phasePin, - gpio_num_t mode1Pin, - gpio_num_t mode2Pin, - gpio_num_t currentPin, - gpio_num_t faultPin, - gpio_num_t sleepPin) + PinPtr enablePin, + PinPtr phasePin, + PinPtr mode1Pin, + PinPtr mode2Pin, + PinPtr currentPin, + PinPtr faultPin, + PinPtr sleepPin) : enablePin(enablePin) - , phaseChannel(pwm.registerPin(phasePin, PWM_FREQ, PWM_RESOLUTION)) + , phaseChannel(pwm.registerPin(phasePin->gpio, PWM_FREQ, PWM_RESOLUTION)) , currentPin(currentPin) , faultPin(faultPin) , sleepPin(sleepPin) { - Log.info("Initializing DRV8801 on pins enable = %d, phase = %d, fault = %d, sleep = %d, mode1 = %d, mode2 = %d, current = %d", - enablePin, phasePin, faultPin, sleepPin, mode1Pin, mode2Pin, currentPin); - - pinMode(enablePin, OUTPUT); - pinMode(mode1Pin, OUTPUT); - pinMode(mode2Pin, OUTPUT); - pinMode(sleepPin, OUTPUT); - pinMode(faultPin, INPUT); - pinMode(currentPin, INPUT); + Log.info("Initializing DRV8801 on pins enable = %s, phase = %s, fault = %s, sleep = %s, mode1 = %s, mode2 = %s, current = %s", + enablePin->getName(), + phasePin->getName(), + faultPin->getName(), + sleepPin->getName(), + mode1Pin->getName(), + mode2Pin->getName(), + currentPin->getName()); + + enablePin->pinMode(OUTPUT); + mode1Pin->pinMode(OUTPUT); + mode2Pin->pinMode(OUTPUT); + sleepPin->pinMode(OUTPUT); + faultPin->pinMode(INPUT); + currentPin->pinMode(INPUT); // TODO Allow using the DRV8801 in other modes - digitalWrite(mode1Pin, HIGH); - digitalWrite(mode2Pin, HIGH); + mode1Pin->digitalWrite(HIGH); + mode2Pin->digitalWrite(HIGH); sleep(); } @@ -62,11 +68,11 @@ class Drv8801Driver if (duty == 0) { Log.debug("Stopping"); sleep(); - digitalWrite(enablePin, LOW); + enablePin->digitalWrite(LOW); return; } wakeUp(); - digitalWrite(enablePin, HIGH); + enablePin->digitalWrite(HIGH); int direction = (phase == MotorPhase::FORWARD ? 1 : -1); int dutyValue = phaseChannel.maxValue() / 2 + direction * (int) (phaseChannel.maxValue() / 2 * duty); @@ -78,12 +84,12 @@ class Drv8801Driver } void sleep() { - digitalWrite(sleepPin, LOW); + sleepPin->digitalWrite(LOW); sleeping = true; } void wakeUp() { - digitalWrite(sleepPin, HIGH); + sleepPin->digitalWrite(HIGH); sleeping = false; } @@ -92,11 +98,11 @@ class Drv8801Driver } private: - const gpio_num_t enablePin; + const PinPtr enablePin; const PwmPin phaseChannel; - const gpio_num_t currentPin; - const gpio_num_t faultPin; - const gpio_num_t sleepPin; + const PinPtr currentPin; + const PinPtr faultPin; + const PinPtr sleepPin; std::atomic sleeping { false }; }; diff --git a/main/kernel/drivers/Drv8833Driver.hpp b/main/kernel/drivers/Drv8833Driver.hpp index 0e0798b7..29de3420 100644 --- a/main/kernel/drivers/Drv8833Driver.hpp +++ b/main/kernel/drivers/Drv8833Driver.hpp @@ -23,22 +23,29 @@ class Drv8833Driver { // Note: on Ugly Duckling MK5, the DRV8874's PMODE is wired to 3.3V, so it's locked in PWM mode Drv8833Driver( PwmManager& pwm, - gpio_num_t ain1Pin, - gpio_num_t ain2Pin, - gpio_num_t bin1Pin, - gpio_num_t bin2Pin, - gpio_num_t faultPin, - gpio_num_t sleepPin) - : motorA(this, pwm, ain1Pin, ain2Pin, sleepPin != GPIO_NUM_NC) - , motorB(this, pwm, bin1Pin, bin2Pin, sleepPin != GPIO_NUM_NC) + PinPtr ain1Pin, + PinPtr ain2Pin, + PinPtr bin1Pin, + PinPtr bin2Pin, + PinPtr faultPin, + PinPtr sleepPin) + : motorA(this, pwm, ain1Pin, ain2Pin, sleepPin != nullptr) + , motorB(this, pwm, bin1Pin, bin2Pin, sleepPin != nullptr) , faultPin(faultPin) , sleepPin(sleepPin) { - Log.info("Initializing DRV8833 on pins ain1 = %d, ain2 = %d, bin1 = %d, bin2 = %d, fault = %d, sleep = %d", - ain1Pin, ain2Pin, bin1Pin, bin2Pin, faultPin, sleepPin); + Log.info("Initializing DRV8833 on pins ain1 = %s, ain2 = %s, bin1 = %s, bin2 = %s, fault = %s, sleep = %s", + ain1Pin->getName().c_str(), + ain2Pin->getName().c_str(), + bin1Pin->getName().c_str(), + bin2Pin->getName().c_str(), + faultPin->getName().c_str(), + sleepPin->getName().c_str()); - pinMode(sleepPin, OUTPUT); - pinMode(faultPin, INPUT); + if (sleepPin != nullptr) { + sleepPin->pinMode(OUTPUT); + } + faultPin->pinMode(INPUT); updateSleepState(); } @@ -61,22 +68,21 @@ class Drv8833Driver { Drv8833MotorDriver( Drv8833Driver* driver, PwmManager& pwm, - gpio_num_t in1Pin, - gpio_num_t in2Pin, + PinPtr in1Pin, + PinPtr in2Pin, bool canSleep) : driver(driver) , in1Channel(pwm.registerPin(in1Pin, PWM_FREQ, PWM_RESOLUTION)) , in2Channel(pwm.registerPin(in2Pin, PWM_FREQ, PWM_RESOLUTION)) - , canSleep(canSleep) , sleeping(canSleep) { } void drive(MotorPhase phase, double duty = 1) override { int dutyValue = static_cast((in1Channel.maxValue() + in1Channel.maxValue() * duty) / 2); - Log.debug("Driving motor %s on pins %d/%d at %d%% (duty = %d)", + Log.debug("Driving motor %s on pins %s/%s at %d%% (duty = %d)", phase == MotorPhase::FORWARD ? "forward" : "reverse", - in1Channel.pin, - in2Channel.pin, + in1Channel.pin->getName().c_str(), + in2Channel.pin->getName().c_str(), (int) (duty * 100), dutyValue); @@ -116,7 +122,6 @@ class Drv8833Driver { Drv8833Driver* const driver; const PwmPin in1Channel; const PwmPin in2Channel; - const bool canSleep; bool sleeping; }; @@ -126,15 +131,15 @@ class Drv8833Driver { } void setSleepState(bool sleep) { - if (sleepPin != GPIO_NUM_NC) { - digitalWrite(sleepPin, sleep ? LOW : HIGH); + if (sleepPin != nullptr) { + sleepPin->digitalWrite(sleep ? LOW : HIGH); } } Drv8833MotorDriver motorA; Drv8833MotorDriver motorB; - const gpio_num_t faultPin; - const gpio_num_t sleepPin; + const PinPtr faultPin; + const PinPtr sleepPin; std::atomic sleeping { false }; }; diff --git a/main/kernel/drivers/Drv8874Driver.hpp b/main/kernel/drivers/Drv8874Driver.hpp index 79433660..b458f0c2 100644 --- a/main/kernel/drivers/Drv8874Driver.hpp +++ b/main/kernel/drivers/Drv8874Driver.hpp @@ -28,13 +28,13 @@ class Drv8874Driver // Note: on Ugly Duckling MK5, the DRV8874's PMODE is wired to 3.3V, so it's locked in PWM mode Drv8874Driver( PwmManager& pwm, - gpio_num_t in1Pin, - gpio_num_t in2Pin, - gpio_num_t currentPin, - gpio_num_t faultPin, - gpio_num_t sleepPin) - : in1Channel(pwm.registerPin(in1Pin, PWM_FREQ, PWM_RESOLUTION)) - , in2Channel(pwm.registerPin(in2Pin, PWM_FREQ, PWM_RESOLUTION)) + PinPtr in1Pin, + PinPtr in2Pin, + PinPtr currentPin, + PinPtr faultPin, + PinPtr sleepPin) + : in1Channel(pwm.registerPin(in1Pin->getGpio(), PWM_FREQ, PWM_RESOLUTION)) + , in2Channel(pwm.registerPin(in2Pin->getGpio(), PWM_FREQ, PWM_RESOLUTION)) , currentPin(currentPin) , faultPin(faultPin) , sleepPin(sleepPin) { @@ -42,9 +42,9 @@ class Drv8874Driver Log.info("Initializing DRV8874 on pins in1 = %d, in2 = %d, fault = %d, sleep = %d, current = %d", in1Pin, in2Pin, faultPin, sleepPin, currentPin); - pinMode(sleepPin, OUTPUT); - pinMode(faultPin, INPUT); - pinMode(currentPin, INPUT); + sleepPin->pinMode(OUTPUT); + faultPin->pinMode(INPUT); + currentPin->pinMode(INPUT); sleep(); } @@ -75,12 +75,12 @@ class Drv8874Driver } void sleep() { - digitalWrite(sleepPin, LOW); + sleepPin->digitalWrite(LOW); sleeping = true; } void wakeUp() { - digitalWrite(sleepPin, HIGH); + sleepPin->digitalWrite(HIGH); sleeping = false; } @@ -91,9 +91,9 @@ class Drv8874Driver private: const PwmPin in1Channel; const PwmPin in2Channel; - const gpio_num_t currentPin; - const gpio_num_t faultPin; - const gpio_num_t sleepPin; + const PinPtr currentPin; + const PinPtr faultPin; + const PinPtr sleepPin; std::atomic sleeping { false }; }; diff --git a/main/kernel/drivers/LedDriver.hpp b/main/kernel/drivers/LedDriver.hpp index efcece5e..c04257ca 100644 --- a/main/kernel/drivers/LedDriver.hpp +++ b/main/kernel/drivers/LedDriver.hpp @@ -4,26 +4,29 @@ #include #include +#include #include #include #include using namespace std::chrono; +using farmhub::devices::PinPtr; + namespace farmhub::kernel::drivers { class LedDriver { public: typedef std::list BlinkPattern; - LedDriver(const String& name, gpio_num_t pin) + LedDriver(const String& name, PinPtr pin) : pin(pin) , patternQueue(name, 1) , pattern({ -milliseconds::max() }) { - Log.info("Initializing LED driver on pin %d", - pin); + Log.info("Initializing LED driver on pin %s", + pin->getName().c_str()); - pinMode(pin, OUTPUT); + pin->pinMode(OUTPUT); Task::loop(name, 2048, [this](Task& task) { if (currentPattern.empty()) { currentPattern = pattern; @@ -77,10 +80,10 @@ class LedDriver { void setLedState(bool state) { this->ledState = state; - digitalWrite(pin, state); + pin->digitalWrite(state); } - const gpio_num_t pin; + const PinPtr pin; Queue patternQueue; BlinkPattern pattern; std::atomic ledState; diff --git a/main/kernel/drivers/SwitchManager.hpp b/main/kernel/drivers/SwitchManager.hpp index 1880d795..632d77d7 100644 --- a/main/kernel/drivers/SwitchManager.hpp +++ b/main/kernel/drivers/SwitchManager.hpp @@ -8,12 +8,15 @@ #include +#include #include #include #include using namespace std::chrono; +using farmhub::devices::PinPtr; + namespace farmhub::kernel::drivers { enum class SwitchMode { @@ -24,7 +27,7 @@ enum class SwitchMode { class Switch { public: virtual const String& getName() const = 0; - virtual gpio_num_t getPin() const = 0; + virtual PinPtr getPin() const = 0; virtual bool isEngaged() const = 0; }; @@ -52,22 +55,22 @@ class SwitchManager { typedef std::function SwitchEngagementHandler; typedef std::function SwitchReleaseHandler; - const Switch& onEngaged(const String& name, gpio_num_t pin, SwitchMode mode, SwitchEngagementHandler engagementHandler) { + const Switch& onEngaged(const String& name, PinPtr pin, SwitchMode mode, SwitchEngagementHandler engagementHandler) { return registerHandler( name, pin, mode, engagementHandler, [](const Switch&, milliseconds) {}); } - const Switch& onReleased(const String& name, gpio_num_t pin, SwitchMode mode, SwitchReleaseHandler releaseHandler) { + const Switch& onReleased(const String& name, PinPtr pin, SwitchMode mode, SwitchReleaseHandler releaseHandler) { return registerHandler( name, pin, mode, [](const Switch&) {}, releaseHandler); } - const Switch& registerHandler(const String& name, gpio_num_t pin, SwitchMode mode, SwitchEngagementHandler engagementHandler, SwitchReleaseHandler releaseHandler) { - Log.info("Registering switch %s on pin %d, mode %s", - name.c_str(), pin, mode == SwitchMode::PullUp ? "pull-up" : "pull-down"); + const Switch& registerHandler(const String& name, PinPtr pin, SwitchMode mode, SwitchEngagementHandler engagementHandler, SwitchReleaseHandler releaseHandler) { + Log.info("Registering switch %s on pin %s, mode %s", + name.c_str(), pin->getName().c_str(), mode == SwitchMode::PullUp ? "pull-up" : "pull-down"); // Configure PIN_INPUT as input - pinMode(pin, mode == SwitchMode::PullUp ? INPUT_PULLUP : INPUT_PULLDOWN); + pin->pinMode(mode == SwitchMode::PullUp ? INPUT_PULLUP : INPUT_PULLDOWN); // gpio_set_direction(pin, GPIO_MODE_INPUT); // gpio_set_pull_mode(pin, mode == SwitchMode::PullUp ? GPIO_PULLUP_ONLY : GPIO_PULLDOWN_ONLY); @@ -81,8 +84,8 @@ class SwitchManager { // Install GPIO ISR gpio_install_isr_service(0); - gpio_isr_handler_add(pin, handleSwitchInterrupt, switchState); - gpio_set_intr_type(pin, GPIO_INTR_ANYEDGE); + gpio_isr_handler_add(pin->getGpio(), handleSwitchInterrupt, switchState); + gpio_set_intr_type(pin->getGpio(), GPIO_INTR_ANYEDGE); return *switchState; } @@ -94,17 +97,17 @@ class SwitchManager { return name; } - gpio_num_t getPin() const override { + PinPtr getPin() const override { return pin; } bool isEngaged() const override { - return digitalRead(pin) == (mode == SwitchMode::PullUp ? LOW : HIGH); + return pin->digitalRead() == (mode == SwitchMode::PullUp ? LOW : HIGH); } private: String name; - gpio_num_t pin; + PinPtr pin; SwitchMode mode; SwitchEngagementHandler engagementHandler; @@ -133,7 +136,7 @@ class SwitchManager { // ISR handler for GPIO interrupt static void IRAM_ATTR handleSwitchInterrupt(void* arg) { SwitchManager::SwitchState* state = static_cast(arg); - bool engaged = digitalRead(state->pin) == (state->mode == SwitchMode::PullUp ? LOW : HIGH); + bool engaged = state->pin->digitalRead() == (state->mode == SwitchMode::PullUp ? LOW : HIGH); state->manager->queueSwitchStateChange(state, engaged); } diff --git a/main/peripherals/I2CConfig.hpp b/main/peripherals/I2CConfig.hpp index 519a0c8b..104db446 100644 --- a/main/peripherals/I2CConfig.hpp +++ b/main/peripherals/I2CConfig.hpp @@ -19,18 +19,18 @@ class I2CDeviceConfig // but JSON doesn't support 0x notation, so we // take it as a string instead Property address { this, "address" }; - Property sda { this, "sda", GPIO_NUM_NC }; - Property scl { this, "scl", GPIO_NUM_NC }; + Property sda { this, "sda" }; + Property scl { this, "scl" }; - I2CConfig parse(uint8_t defaultAddress = 0xFF, gpio_num_t defaultSda = GPIO_NUM_NC, gpio_num_t defaultScl = GPIO_NUM_NC) const { + I2CConfig parse(uint8_t defaultAddress = 0xFF, PinPtr defaultSda = nullptr, PinPtr defaultScl = nullptr) const { return { address.get().isEmpty() ? defaultAddress : (uint8_t) strtol(address.get().c_str(), nullptr, 0), - sda.get() == GPIO_NUM_NC + sda.get() == nullptr ? defaultSda : sda.get(), - scl.get() == GPIO_NUM_NC + scl.get() == nullptr ? defaultScl : scl.get() }; diff --git a/main/peripherals/SinglePinDeviceConfig.hpp b/main/peripherals/SinglePinDeviceConfig.hpp index f9b50bc7..bc9336c8 100644 --- a/main/peripherals/SinglePinDeviceConfig.hpp +++ b/main/peripherals/SinglePinDeviceConfig.hpp @@ -14,7 +14,7 @@ namespace farmhub::peripherals { class SinglePinDeviceConfig : public ConfigurationSection { public: - Property pin { this, "pin", GPIO_NUM_NC }; + Property pin { this, "pin" }; }; } // namespace farmhub::peripherals::environment diff --git a/main/peripherals/chicken_door/ChickenDoor.hpp b/main/peripherals/chicken_door/ChickenDoor.hpp index 7b06a32c..1f319874 100644 --- a/main/peripherals/chicken_door/ChickenDoor.hpp +++ b/main/peripherals/chicken_door/ChickenDoor.hpp @@ -70,8 +70,8 @@ class ChickenDoorDeviceConfig : public ConfigurationSection { public: Property motor { this, "motor" }; - Property openPin { this, "openPin", GPIO_NUM_NC }; - Property closedPin { this, "closedPin", GPIO_NUM_NC }; + Property openPin { this, "openPin" }; + Property closedPin { this, "closedPin" }; Property movementTimeout { this, "movementTimeout", seconds(60) }; NamedConfigurationEntry lightSensor { this, "lightSensor" }; @@ -95,8 +95,8 @@ class ChickenDoorComponent SwitchManager& switches, PwmMotorDriver& motor, TLightSensorComponent& lightSensor, - gpio_num_t openPin, - gpio_num_t closedPin, + PinPtr openPin, + PinPtr closedPin, ticks movementTimeout, std::function publishTelemetry) : Component(name, mqttRoot) @@ -122,8 +122,8 @@ class ChickenDoorComponent // TODO Make this configurable { - Log.info("Initializing chicken door %s, open switch %d, close switch %d", - name.c_str(), openSwitch.getPin(), closedSwitch.getPin()); + Log.info("Initializing chicken door %s, open switch %s, close switch %s", + name.c_str(), openSwitch.getPin()->getName().c_str(), closedSwitch.getPin()->getName().c_str()); motor.stop(); diff --git a/main/peripherals/environment/Ds18B20SoilSensor.hpp b/main/peripherals/environment/Ds18B20SoilSensor.hpp index 4210cde2..01875c3f 100644 --- a/main/peripherals/environment/Ds18B20SoilSensor.hpp +++ b/main/peripherals/environment/Ds18B20SoilSensor.hpp @@ -32,13 +32,13 @@ class Ds18B20SoilSensorComponent Ds18B20SoilSensorComponent( const String& name, shared_ptr mqttRoot, - gpio_num_t pin) + PinPtr pin) : Component(name, mqttRoot) { - Log.info("Initializing DS18B20 soil temperature sensor on pin %d", - pin); + Log.info("Initializing DS18B20 soil temperature sensor on pin %s", + pin->getName().c_str()); - oneWire.begin(pin); + oneWire.begin(pin->getGpio()); // locate devices on the bus Log.trace("Locating devices..."); @@ -90,7 +90,7 @@ class Ds18B20SoilSensorComponent class Ds18B20SoilSensor : public Peripheral { public: - Ds18B20SoilSensor(const String& name, shared_ptr mqttRoot, gpio_num_t pin) + Ds18B20SoilSensor(const String& name, shared_ptr mqttRoot, PinPtr pin) : Peripheral(name, mqttRoot) , sensor(name, mqttRoot, pin) { } diff --git a/main/peripherals/environment/Environment.hpp b/main/peripherals/environment/Environment.hpp index 92c0a36a..0ff596d0 100644 --- a/main/peripherals/environment/Environment.hpp +++ b/main/peripherals/environment/Environment.hpp @@ -51,7 +51,7 @@ class I2CEnvironmentFactory } unique_ptr> createPeripheral(const String& name, const I2CDeviceConfig& deviceConfig, shared_ptr mqttRoot, PeripheralServices& services) override { - auto i2cConfig = deviceConfig.parse(defaultAddress, GPIO_NUM_NC, GPIO_NUM_NC); + auto i2cConfig = deviceConfig.parse(defaultAddress); Log.info("Creating %s sensor %s with %s", sensorType.c_str(), name.c_str(), i2cConfig.toString().c_str()); return make_unique>(name, sensorType, mqttRoot, services.i2c, i2cConfig); diff --git a/main/peripherals/environment/SoilMoistureSensor.hpp b/main/peripherals/environment/SoilMoistureSensor.hpp index af313742..830ecc69 100644 --- a/main/peripherals/environment/SoilMoistureSensor.hpp +++ b/main/peripherals/environment/SoilMoistureSensor.hpp @@ -19,7 +19,7 @@ namespace farmhub::peripherals::environment { class SoilMoistureSensorDeviceConfig : public ConfigurationSection { public: - Property pin { this, "pin", GPIO_NUM_NC }; + Property pin { this, "pin" }; // These values need calibrating for each sensor Property air { this, "air", 3000 }; Property water { this, "water", 1000 }; @@ -38,14 +38,14 @@ class SoilMoistureSensorComponent , waterValue(config.water.get()) , pin(config.pin.get()) { - Log.info("Initializing soil moisture sensor on pin %d; air value: %d; water value: %d", - pin, airValue, waterValue); + Log.info("Initializing soil moisture sensor on pin %s; air value: %d; water value: %d", + pin->getName().c_str(), airValue, waterValue); - pinMode(pin, INPUT); + pin->pinMode(INPUT); } void populateTelemetry(JsonObject& json) override { - uint16_t soilMoistureValue = analogRead(pin); + uint16_t soilMoistureValue = pin->analogRead(); Log.trace("Soil moisture value: %d", soilMoistureValue); @@ -60,7 +60,7 @@ class SoilMoistureSensorComponent private: const int airValue; const int waterValue; - gpio_num_t pin; + PinPtr pin; }; class SoilMoistureSensor diff --git a/main/peripherals/fence/ElectricFenceMonitor.hpp b/main/peripherals/fence/ElectricFenceMonitor.hpp index 8cf932b3..4fbfcc0e 100644 --- a/main/peripherals/fence/ElectricFenceMonitor.hpp +++ b/main/peripherals/fence/ElectricFenceMonitor.hpp @@ -20,7 +20,7 @@ using namespace farmhub::peripherals; namespace farmhub::peripherals::fence { struct FencePinConfig { - gpio_num_t pin; + PinPtr pin; uint16_t voltage; }; @@ -56,7 +56,7 @@ class ElectricFenceMonitorComponent for (auto& pinConfig : config.pins.get()) { if (pinsDescription.length() > 0) pinsDescription += ", "; - pinsDescription += String(pinConfig.pin) + "=" + String(pinConfig.voltage) + "V"; + pinsDescription += pinConfig.pin->getName() + "=" + String(pinConfig.voltage) + "V"; } Log.info("Initializing electric fence with pins %s", pinsDescription.c_str()); @@ -74,8 +74,8 @@ class ElectricFenceMonitorComponent if (count > 0) { lastVoltage = max(pin.voltage, lastVoltage); - Log.trace("Counted %d pulses on pin %d (voltage: %dV)", - count, pin.pcntUnit.getPin(), pin.voltage); + Log.trace("Counted %d pulses on pin %s (voltage: %dV)", + count, pin.pcntUnit.getPin()->getName().c_str(), pin.voltage); } } { diff --git a/main/peripherals/flow_control/FlowControl.hpp b/main/peripherals/flow_control/FlowControl.hpp index 303b24f2..49ff5dee 100644 --- a/main/peripherals/flow_control/FlowControl.hpp +++ b/main/peripherals/flow_control/FlowControl.hpp @@ -36,7 +36,7 @@ class FlowControl : public Peripheral { SleepManager& sleepManager, PwmMotorDriver& controller, ValveControlStrategy& strategy, - gpio_num_t pin, + PinPtr pin, double qFactor, milliseconds measurementFrequency) : Peripheral(name, mqttRoot) diff --git a/main/peripherals/flow_meter/FlowMeter.hpp b/main/peripherals/flow_meter/FlowMeter.hpp index f2202df1..a93d3844 100644 --- a/main/peripherals/flow_meter/FlowMeter.hpp +++ b/main/peripherals/flow_meter/FlowMeter.hpp @@ -19,7 +19,7 @@ namespace farmhub::peripherals::flow_meter { class FlowMeter : public Peripheral { public: - FlowMeter(const String& name, shared_ptr mqttRoot, PcntManager& pcnt, gpio_num_t pin, double qFactor, milliseconds measurementFrequency) + FlowMeter(const String& name, shared_ptr mqttRoot, PcntManager& pcnt, PinPtr pin, double qFactor, milliseconds measurementFrequency) : Peripheral(name, mqttRoot) , flowMeter(name, mqttRoot, pcnt, pin, qFactor, measurementFrequency) { } diff --git a/main/peripherals/flow_meter/FlowMeterComponent.hpp b/main/peripherals/flow_meter/FlowMeterComponent.hpp index ce1f4a9d..cf7a3813 100644 --- a/main/peripherals/flow_meter/FlowMeterComponent.hpp +++ b/main/peripherals/flow_meter/FlowMeterComponent.hpp @@ -27,13 +27,14 @@ class FlowMeterComponent const String& name, shared_ptr mqttRoot, PcntManager& pcnt, - gpio_num_t pin, + PinPtr pin, double qFactor, milliseconds measurementFrequency) : Component(name, mqttRoot) , qFactor(qFactor) { - Log.info("Initializing flow meter on pin %d with Q = %.2f", pin, qFactor); + Log.info("Initializing flow meter on pin %s with Q = %.2f", + pin->getName().c_str(), qFactor); pcntUnit = pcnt.registerUnit(pin); diff --git a/main/peripherals/flow_meter/FlowMeterConfig.hpp b/main/peripherals/flow_meter/FlowMeterConfig.hpp index 75f66169..2c96f180 100644 --- a/main/peripherals/flow_meter/FlowMeterConfig.hpp +++ b/main/peripherals/flow_meter/FlowMeterConfig.hpp @@ -13,7 +13,7 @@ namespace farmhub::peripherals::flow_meter { class FlowMeterDeviceConfig : public ConfigurationSection { public: - Property pin { this, "pin", GPIO_NUM_NC }; + Property pin { this, "pin" }; Property qFactor { this, "qFactor", 5.0 }; Property measurementFrequency { this, "measurementFrequency", 1s }; };