From 69a55d685747e4f1523c3ba8c916f2873a7cf7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sat, 26 Oct 2024 22:06:51 +0200 Subject: [PATCH 01/16] Pass Pin around instead of gpio_num_t --- main/devices/Device.hpp | 2 +- main/devices/DeviceDefinition.hpp | 4 +- main/devices/Pin.hpp | 88 +++++++++++++------ main/devices/UglyDucklingMk4.hpp | 38 ++++---- main/devices/UglyDucklingMk5.hpp | 80 ++++++++--------- main/devices/UglyDucklingMk6.hpp | 88 +++++++++---------- main/devices/UglyDucklingMk7.hpp | 64 +++++++------- main/kernel/I2CManager.hpp | 23 +++-- main/kernel/PcntManager.hpp | 16 ++-- main/kernel/PwmManager.hpp | 14 +-- main/kernel/drivers/BatteryDriver.hpp | 15 ++-- main/kernel/drivers/Bq27220Driver.hpp | 6 +- main/kernel/drivers/Drv8801Driver.hpp | 58 ++++++------ main/kernel/drivers/Drv8833Driver.hpp | 51 ++++++----- main/kernel/drivers/Drv8874Driver.hpp | 34 +++---- main/kernel/drivers/LedDriver.hpp | 15 ++-- main/kernel/drivers/SwitchManager.hpp | 29 +++--- main/peripherals/I2CConfig.hpp | 10 +-- main/peripherals/SinglePinDeviceConfig.hpp | 2 +- main/peripherals/chicken_door/ChickenDoor.hpp | 12 +-- .../environment/Ds18B20SoilSensor.hpp | 10 +-- main/peripherals/environment/Environment.hpp | 2 +- .../environment/SoilMoistureSensor.hpp | 12 +-- .../fence/ElectricFenceMonitor.hpp | 8 +- main/peripherals/flow_control/FlowControl.hpp | 2 +- main/peripherals/flow_meter/FlowMeter.hpp | 2 +- .../flow_meter/FlowMeterComponent.hpp | 5 +- .../flow_meter/FlowMeterConfig.hpp | 2 +- 28 files changed, 378 insertions(+), 314 deletions(-) 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..af596df0 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 { @@ -92,8 +92,8 @@ class UglyDucklingMk6 : public DeviceDefinition { pins::BOOT) { // Switch off strapping pin // TODO: Add a LED driver instead - pinMode(pins::LEDA_RED, OUTPUT); - digitalWrite(pins::LEDA_RED, HIGH); + pins::LEDA_RED->pinMode(OUTPUT); + pins::LEDA_RED->digitalWrite(HIGH); } virtual std::shared_ptr createBatteryDriver(I2CManager& i2c) override { 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..67c6761b 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)) , 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().c_str(), + phasePin->getName().c_str(), + faultPin->getName().c_str(), + sleepPin->getName().c_str(), + mode1Pin->getName().c_str(), + mode2Pin->getName().c_str(), + currentPin->getName().c_str()); + + 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..7dd2750f 100644 --- a/main/kernel/drivers/Drv8874Driver.hpp +++ b/main/kernel/drivers/Drv8874Driver.hpp @@ -28,23 +28,27 @@ 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) + PinPtr in1Pin, + PinPtr in2Pin, + PinPtr currentPin, + PinPtr faultPin, + PinPtr sleepPin) : in1Channel(pwm.registerPin(in1Pin, PWM_FREQ, PWM_RESOLUTION)) , in2Channel(pwm.registerPin(in2Pin, PWM_FREQ, PWM_RESOLUTION)) , currentPin(currentPin) , faultPin(faultPin) , sleepPin(sleepPin) { - Log.info("Initializing DRV8874 on pins in1 = %d, in2 = %d, fault = %d, sleep = %d, current = %d", - in1Pin, in2Pin, faultPin, sleepPin, currentPin); + Log.info("Initializing DRV8874 on pins in1 = %s, in2 = %s, fault = %s, sleep = %s, current = %s", + in1Pin->getName().c_str(), + in2Pin->getName().c_str(), + faultPin->getName().c_str(), + sleepPin->getName().c_str(), + currentPin->getName().c_str()); - pinMode(sleepPin, OUTPUT); - pinMode(faultPin, INPUT); - pinMode(currentPin, INPUT); + sleepPin->pinMode(OUTPUT); + faultPin->pinMode(INPUT); + currentPin->pinMode(INPUT); sleep(); } @@ -75,12 +79,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 +95,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 }; }; From 8cb76acb592ac413da85831532df56b8f79087c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sat, 26 Oct 2024 22:52:37 +0200 Subject: [PATCH 02/16] Require an InternalPin for stuff where an actual GPIO is needed --- main/devices/DeviceDefinition.hpp | 4 +- main/devices/Pin.hpp | 120 +++++++++++++----- main/devices/UglyDucklingMk4.hpp | 38 +++--- main/devices/UglyDucklingMk5.hpp | 80 ++++++------ main/devices/UglyDucklingMk6.hpp | 82 ++++++------ main/devices/UglyDucklingMk7.hpp | 64 +++++----- main/kernel/I2CManager.hpp | 6 +- main/kernel/PcntManager.hpp | 6 +- main/kernel/PwmManager.hpp | 6 +- main/kernel/drivers/Bq27220Driver.hpp | 2 +- main/kernel/drivers/Drv8801Driver.hpp | 2 +- main/kernel/drivers/Drv8833Driver.hpp | 12 +- main/kernel/drivers/Drv8874Driver.hpp | 4 +- main/kernel/drivers/SwitchManager.hpp | 12 +- main/peripherals/I2CConfig.hpp | 6 +- main/peripherals/SinglePinDeviceConfig.hpp | 2 +- main/peripherals/chicken_door/ChickenDoor.hpp | 8 +- .../environment/Ds18B20SoilSensor.hpp | 4 +- .../fence/ElectricFenceMonitor.hpp | 2 +- main/peripherals/flow_control/FlowControl.hpp | 2 +- main/peripherals/flow_meter/FlowMeter.hpp | 2 +- .../flow_meter/FlowMeterComponent.hpp | 2 +- .../flow_meter/FlowMeterConfig.hpp | 2 +- 23 files changed, 265 insertions(+), 203 deletions(-) diff --git a/main/devices/DeviceDefinition.hpp b/main/devices/DeviceDefinition.hpp index 2f7eeb7d..e68f9c21 100644 --- a/main/devices/DeviceDefinition.hpp +++ b/main/devices/DeviceDefinition.hpp @@ -64,7 +64,7 @@ class DeviceConfiguration : public ConfigurationSection { template class DeviceDefinition { public: - DeviceDefinition(PinPtr statusPin, PinPtr bootPin) + DeviceDefinition(PinPtr statusPin, InternalPinPtr bootPin) : statusLed("status", statusPin) , bootPin(bootPin) { } @@ -99,7 +99,7 @@ class DeviceDefinition { LedDriver statusLed; PcntManager pcnt; PwmManager pwm; - const PinPtr bootPin; + const InternalPinPtr bootPin; private: ConfigurationFile configFile { FileSystem::get(), "/device-config.json" }; diff --git a/main/devices/Pin.hpp b/main/devices/Pin.hpp index bab43215..4e0dd2a6 100644 --- a/main/devices/Pin.hpp +++ b/main/devices/Pin.hpp @@ -15,15 +15,11 @@ namespace farmhub::devices { class Pin; using PinPtr = std::shared_ptr; +class InternalPin; +using InternalPinPtr = std::shared_ptr; + class Pin { public: - 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 PinPtr byName(const String& name) { auto it = BY_NAME.find(name); if (it != BY_NAME.end()) { @@ -32,9 +28,56 @@ class Pin { throw std::runtime_error(String("Unknown pin: " + name).c_str()); } - static PinPtr byGpio(gpio_num_t pin) { - auto it = BY_GPIO.find(pin); - if (it == BY_GPIO.end()) { + virtual void pinMode(uint8_t mode) const = 0; + + virtual void digitalWrite(uint8_t val) const = 0; + + virtual int digitalRead() const = 0; + + virtual uint16_t analogRead() const = 0; + + inline const String& getName() const { + return name; + } + +protected: + Pin(const String& name) + : name(name) { + } + + static void registerPin(const String& name, PinPtr pin) { + BY_NAME[name] = pin; + } + +protected: + const String name; + + static std::map BY_NAME; +}; + +std::map Pin::BY_NAME; + +class InternalPin : public Pin { +public: + static InternalPinPtr registerPin(const String& name, gpio_num_t gpio) { + auto pin = std::make_shared(name, gpio); + INTERNAL_BY_GPIO[gpio] = pin; + INTERNAL_BY_NAME[name] = pin; + Pin::registerPin(name, pin); + return pin; + } + + static InternalPinPtr byName(const String& name) { + auto it = INTERNAL_BY_NAME.find(name); + if (it != INTERNAL_BY_NAME.end()) { + return it->second; + } + throw std::runtime_error(String("Unknown internal pin: " + name).c_str()); + } + + static InternalPinPtr byGpio(gpio_num_t pin) { + auto it = INTERNAL_BY_GPIO.find(pin); + if (it == INTERNAL_BY_GPIO.end()) { String name = "GPIO_NUM_" + String(pin); return registerPin(name, pin); } else { @@ -42,45 +85,39 @@ class Pin { } } - Pin(const String& name, gpio_num_t gpio) - : name(name) + InternalPin(const String& name, gpio_num_t gpio) + : Pin(name) , gpio(gpio) { } - inline void pinMode(uint8_t mode) const { + inline void pinMode(uint8_t mode) const override { ::pinMode(gpio, mode); } - inline void digitalWrite(uint8_t val) const { + inline void digitalWrite(uint8_t val) const override { ::digitalWrite(gpio, val); } - inline int digitalRead() const { + inline int digitalRead() const override { return ::digitalRead(gpio); } - inline uint16_t analogRead() const { + inline uint16_t analogRead() const override { return ::analogRead(gpio); } - inline const String& getName() const { - return name; - } - inline gpio_num_t getGpio() const { return gpio; } private: - const String name; const gpio_num_t gpio; - - static std::map BY_GPIO; - static std::map BY_NAME; + static std::map INTERNAL_BY_NAME; + static std::map INTERNAL_BY_GPIO; }; -std::map Pin::BY_GPIO; -std::map Pin::BY_NAME; +std::map InternalPin::INTERNAL_BY_NAME; +std::map InternalPin::INTERNAL_BY_GPIO; } // namespace farmhub::devices @@ -88,14 +125,14 @@ namespace ArduinoJson { using farmhub::devices::Pin; using farmhub::devices::PinPtr; +using farmhub::devices::InternalPin; +using farmhub::devices::InternalPinPtr; template <> 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(src->getName()); } @@ -105,7 +142,32 @@ struct Converter { if (src.is()) { return Pin::byName(src.as()); } else { - return Pin::byGpio(static_cast(src.as())); + throw std::runtime_error(String("Invalid pin name: " + src.as()).c_str()); + } + } + + static bool checkJson(JsonVariantConst src) { + return src.is(); + } +}; + +template <> +struct Converter { + static void toJson(const InternalPinPtr& 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(src->getName()); + } + } + + static InternalPinPtr fromJson(JsonVariantConst src) { + if (src.is()) { + return InternalPin::byName(src.as()); + } else { + return InternalPin::byGpio(static_cast(src.as())); } } diff --git a/main/devices/UglyDucklingMk4.hpp b/main/devices/UglyDucklingMk4.hpp index d15f7ac1..a76849bb 100644 --- a/main/devices/UglyDucklingMk4.hpp +++ b/main/devices/UglyDucklingMk4.hpp @@ -34,25 +34,25 @@ class Mk4Config }; namespace pins { -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); +static InternalPinPtr BOOT = InternalPin::registerPin("BOOT", GPIO_NUM_0); +static InternalPinPtr STATUS = InternalPin::registerPin("STATUS", GPIO_NUM_26); + +static InternalPinPtr SOIL_MOISTURE = InternalPin::registerPin("SOIL_MOISTURE", GPIO_NUM_6); +static InternalPinPtr SOIL_TEMP = InternalPin::registerPin("SOIL_TEMP", GPIO_NUM_7); + +static InternalPinPtr VALVE_EN = InternalPin::registerPin("VALVE_EN", GPIO_NUM_10); +static InternalPinPtr VALVE_PH = InternalPin::registerPin("VALVE_PH", GPIO_NUM_11); +static InternalPinPtr VALVE_FAULT = InternalPin::registerPin("VALVE_FAULT", GPIO_NUM_12); +static InternalPinPtr VALVE_SLEEP = InternalPin::registerPin("VALVE_SLEEP", GPIO_NUM_13); +static InternalPinPtr VALVE_MODE1 = InternalPin::registerPin("VALVE_MODE1", GPIO_NUM_14); +static InternalPinPtr VALVE_MODE2 = InternalPin::registerPin("VALVE_MODE2", GPIO_NUM_15); +static InternalPinPtr VALVE_CURRENT = InternalPin::registerPin("VALVE_CURRENT", GPIO_NUM_16); +static InternalPinPtr FLOW = InternalPin::registerPin("FLOW", GPIO_NUM_17); + +static InternalPinPtr SDA = InternalPin::registerPin("SDA", GPIO_NUM_8); +static InternalPinPtr SCL = InternalPin::registerPin("SCL", GPIO_NUM_9); +static InternalPinPtr RXD0 = InternalPin::registerPin("RXD0", GPIO_NUM_44); +static InternalPinPtr TXD0 = InternalPin::registerPin("TXD0", GPIO_NUM_43); } // namespace pins class UglyDucklingMk4 : public DeviceDefinition { diff --git a/main/devices/UglyDucklingMk5.hpp b/main/devices/UglyDucklingMk5.hpp index d9ac60ac..7d1250a0 100644 --- a/main/devices/UglyDucklingMk5.hpp +++ b/main/devices/UglyDucklingMk5.hpp @@ -33,46 +33,46 @@ class Mk5Config }; namespace pins { -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); +static InternalPinPtr BOOT = InternalPin::registerPin("BOOT", GPIO_NUM_0); +static InternalPinPtr BATTERY = InternalPin::registerPin("BATTERY", GPIO_NUM_1); +static InternalPinPtr STATUS = InternalPin::registerPin("STATUS", GPIO_NUM_2); +static InternalPinPtr AIPROPI = InternalPin::registerPin("AIPROPI", GPIO_NUM_4); + +static InternalPinPtr IOA1 = InternalPin::registerPin("A1", GPIO_NUM_5); +static InternalPinPtr IOA2 = InternalPin::registerPin("A2", GPIO_NUM_6); +static InternalPinPtr BIPROPI = InternalPin::registerPin("BIPROPI", GPIO_NUM_7); +static InternalPinPtr IOB1 = InternalPin::registerPin("B1", GPIO_NUM_15); +static InternalPinPtr AIN1 = InternalPin::registerPin("AIN1", GPIO_NUM_16); +static InternalPinPtr AIN2 = InternalPin::registerPin("AIN2", GPIO_NUM_17); +static InternalPinPtr BIN1 = InternalPin::registerPin("BIN1", GPIO_NUM_18); +static InternalPinPtr BIN2 = InternalPin::registerPin("BIN2", GPIO_NUM_8); + +static InternalPinPtr DMINUS = InternalPin::registerPin("D-", GPIO_NUM_19); +static InternalPinPtr DPLUS = InternalPin::registerPin("D+", GPIO_NUM_20); + +static InternalPinPtr IOB2 = InternalPin::registerPin("B2", GPIO_NUM_9); + +static InternalPinPtr NSLEEP = InternalPin::registerPin("NSLEEP", GPIO_NUM_10); +static InternalPinPtr NFault = InternalPin::registerPin("NFault", GPIO_NUM_11); +static InternalPinPtr IOC4 = InternalPin::registerPin("C4", GPIO_NUM_12); +static InternalPinPtr IOC3 = InternalPin::registerPin("C3", GPIO_NUM_13); +static InternalPinPtr IOC2 = InternalPin::registerPin("C2", GPIO_NUM_14); +static InternalPinPtr IOC1 = InternalPin::registerPin("C1", GPIO_NUM_21); +static InternalPinPtr IOD4 = InternalPin::registerPin("D4", GPIO_NUM_47); +static InternalPinPtr IOD3 = InternalPin::registerPin("D3", GPIO_NUM_48); + +static InternalPinPtr SDA = InternalPin::registerPin("SDA", GPIO_NUM_35); +static InternalPinPtr SCL = InternalPin::registerPin("SCL", GPIO_NUM_36); + +static InternalPinPtr IOD1 = InternalPin::registerPin("D1", GPIO_NUM_37); +static InternalPinPtr IOD2 = InternalPin::registerPin("D2", GPIO_NUM_38); + +static InternalPinPtr TCK = InternalPin::registerPin("TCK", GPIO_NUM_39); +static InternalPinPtr TDO = InternalPin::registerPin("TDO", GPIO_NUM_40); +static InternalPinPtr TDI = InternalPin::registerPin("TDI", GPIO_NUM_41); +static InternalPinPtr TMS = InternalPin::registerPin("TMS", GPIO_NUM_42); +static InternalPinPtr RXD0 = InternalPin::registerPin("RXD0", GPIO_NUM_44); +static InternalPinPtr TXD0 = InternalPin::registerPin("TXD0", GPIO_NUM_43); } // namespace pins class UglyDucklingMk5 : public DeviceDefinition { diff --git a/main/devices/UglyDucklingMk6.hpp b/main/devices/UglyDucklingMk6.hpp index af596df0..4c7eb106 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 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); +static InternalPinPtr BOOT = InternalPin::registerPin("BOOT", GPIO_NUM_0); +static InternalPinPtr BATTERY = InternalPin::registerPin("BATTERY", GPIO_NUM_1); +static InternalPinPtr STATUS = InternalPin::registerPin("STATUS", GPIO_NUM_2); +static InternalPinPtr STATUS2 = InternalPin::registerPin("STATUS2", GPIO_NUM_4); + +static InternalPinPtr IOB1 = InternalPin::registerPin("B1", GPIO_NUM_5); +static InternalPinPtr IOA1 = InternalPin::registerPin("A1", GPIO_NUM_6); +static InternalPinPtr DIPROPI = InternalPin::registerPin("DIPROPI", GPIO_NUM_7); +static InternalPinPtr IOA2 = InternalPin::registerPin("A2", GPIO_NUM_15); +static InternalPinPtr AIN1 = InternalPin::registerPin("AIN1", GPIO_NUM_16); +static InternalPinPtr AIN2 = InternalPin::registerPin("AIN2", GPIO_NUM_17); +static InternalPinPtr BIN2 = InternalPin::registerPin("BIN2", GPIO_NUM_18); +static InternalPinPtr BIN1 = InternalPin::registerPin("BIN1", GPIO_NUM_8); + +static InternalPinPtr DMINUS = InternalPin::registerPin("D-", GPIO_NUM_19); +static InternalPinPtr DPLUS = InternalPin::registerPin("D+", GPIO_NUM_20); + +static InternalPinPtr LEDA_RED = InternalPin::registerPin("LEDA_RED", GPIO_NUM_46); +static InternalPinPtr LEDA_GREEN = InternalPin::registerPin("LEDA_GREEN", GPIO_NUM_9); + +static InternalPinPtr NFault = InternalPin::registerPin("NFault", GPIO_NUM_11); +static InternalPinPtr BTN1 = InternalPin::registerPin("BTN1", GPIO_NUM_12); +static InternalPinPtr BTN2 = InternalPin::registerPin("BTN2", GPIO_NUM_13); +static InternalPinPtr IOC4 = InternalPin::registerPin("C4", GPIO_NUM_14); +static InternalPinPtr IOC3 = InternalPin::registerPin("C3", GPIO_NUM_21); +static InternalPinPtr IOC2 = InternalPin::registerPin("C2", GPIO_NUM_47); +static InternalPinPtr IOC1 = InternalPin::registerPin("C1", GPIO_NUM_48); +static InternalPinPtr IOB2 = InternalPin::registerPin("B2", GPIO_NUM_45); + +static InternalPinPtr SDA = InternalPin::registerPin("SDA", GPIO_NUM_35); +static InternalPinPtr SCL = InternalPin::registerPin("SCL", GPIO_NUM_36); + +static InternalPinPtr LEDB_GREEN = InternalPin::registerPin("LEDB_GREEN", GPIO_NUM_37); +static InternalPinPtr LEDB_RED = InternalPin::registerPin("LEDB_RED", GPIO_NUM_38); + +static InternalPinPtr TCK = InternalPin::registerPin("TCK", GPIO_NUM_39); +static InternalPinPtr TDO = InternalPin::registerPin("TDO", GPIO_NUM_40); +static InternalPinPtr TDI = InternalPin::registerPin("TDI", GPIO_NUM_41); +static InternalPinPtr TMS = InternalPin::registerPin("TMS", GPIO_NUM_42); +static InternalPinPtr RXD0 = InternalPin::registerPin("RXD0", GPIO_NUM_44); +static InternalPinPtr TXD0 = InternalPin::registerPin("TXD0", GPIO_NUM_43); } // namespace pins class Mk6Config diff --git a/main/devices/UglyDucklingMk7.hpp b/main/devices/UglyDucklingMk7.hpp index 229e4501..45a4b4cc 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 PinPtr BOOT = Pin::registerPin("BOOT", GPIO_NUM_0); +static InternalPinPtr BOOT = InternalPin::registerPin("BOOT", GPIO_NUM_0); -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); +static InternalPinPtr IOA2 = InternalPin::registerPin("A2", GPIO_NUM_1); +static InternalPinPtr IOA1 = InternalPin::registerPin("A1", GPIO_NUM_2); +static InternalPinPtr IOA3 = InternalPin::registerPin("A3", GPIO_NUM_3); +static InternalPinPtr IOB3 = InternalPin::registerPin("B3", GPIO_NUM_4); +static InternalPinPtr IOB1 = InternalPin::registerPin("B1", GPIO_NUM_5); +static InternalPinPtr IOB2 = InternalPin::registerPin("B2", GPIO_NUM_6); // GPIO_NUM_7 is NC -static PinPtr BAT_GPIO = Pin::registerPin("BAT_GPIO", GPIO_NUM_8); +static InternalPinPtr BAT_GPIO = InternalPin::registerPin("BAT_GPIO", GPIO_NUM_8); -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 InternalPinPtr FSPIHD = InternalPin::registerPin("FSPIHD", GPIO_NUM_9); +static InternalPinPtr FSPICS0 = InternalPin::registerPin("FSPICS0", GPIO_NUM_10); +static InternalPinPtr FSPID = InternalPin::registerPin("FSPID", GPIO_NUM_11); +static InternalPinPtr FSPICLK = InternalPin::registerPin("FSPICLK", GPIO_NUM_12); +static InternalPinPtr FSPIQ = InternalPin::registerPin("FSPIQ", GPIO_NUM_13); +static InternalPinPtr FSPIWP = InternalPin::registerPin("FSPIWP", GPIO_NUM_14); -static PinPtr STATUS = Pin::registerPin("STATUS", GPIO_NUM_15); -static PinPtr LOADEN = Pin::registerPin("LOADEN", GPIO_NUM_16); +static InternalPinPtr STATUS = InternalPin::registerPin("STATUS", GPIO_NUM_15); +static InternalPinPtr LOADEN = InternalPin::registerPin("LOADEN", GPIO_NUM_16); -static PinPtr SCL = Pin::registerPin("SCL", GPIO_NUM_17); -static PinPtr SDA = Pin::registerPin("SDA", GPIO_NUM_18); +static InternalPinPtr SCL = InternalPin::registerPin("SCL", GPIO_NUM_17); +static InternalPinPtr SDA = InternalPin::registerPin("SDA", GPIO_NUM_18); -static PinPtr DMINUS = Pin::registerPin("D-", GPIO_NUM_19); -static PinPtr DPLUS = Pin::registerPin("D+", GPIO_NUM_20); +static InternalPinPtr DMINUS = InternalPin::registerPin("D-", GPIO_NUM_19); +static InternalPinPtr DPLUS = InternalPin::registerPin("D+", GPIO_NUM_20); -static PinPtr IOX1 = Pin::registerPin("X1", GPIO_NUM_21); +static InternalPinPtr IOX1 = InternalPin::registerPin("X1", GPIO_NUM_21); // GPIO_NUM_22 to GPIO_NUM_36 are NC -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); +static InternalPinPtr DBIN1 = InternalPin::registerPin("DBIN1", GPIO_NUM_37); +static InternalPinPtr DBIN2 = InternalPin::registerPin("DBIN2", GPIO_NUM_38); +static InternalPinPtr DAIN2 = InternalPin::registerPin("DAIN2", GPIO_NUM_39); +static InternalPinPtr DAIN1 = InternalPin::registerPin("DAIN1", GPIO_NUM_40); +static InternalPinPtr DNFault = InternalPin::registerPin("DNFault", GPIO_NUM_41); // GPIO_NUM_42 is NC -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); +static InternalPinPtr TXD0 = InternalPin::registerPin("TXD0", GPIO_NUM_43); +static InternalPinPtr RXD0 = InternalPin::registerPin("RXD0", GPIO_NUM_44); +static InternalPinPtr IOX2 = InternalPin::registerPin("X2", GPIO_NUM_45); +static InternalPinPtr STATUS2 = InternalPin::registerPin("STATUS2", GPIO_NUM_46); +static InternalPinPtr IOB4 = InternalPin::registerPin("B4", GPIO_NUM_47); +static InternalPinPtr IOA4 = InternalPin::registerPin("A4", GPIO_NUM_48); } // namespace pins class Mk7Config diff --git a/main/kernel/I2CManager.hpp b/main/kernel/I2CManager.hpp index 0824863c..03c2fd0e 100644 --- a/main/kernel/I2CManager.hpp +++ b/main/kernel/I2CManager.hpp @@ -20,8 +20,8 @@ using TwoWireMap = std::map; struct I2CConfig { public: uint8_t address; - PinPtr sda; - PinPtr scl; + InternalPinPtr sda; + InternalPinPtr scl; String toString() const { return String("I2C address: 0x") + String(address, HEX) + ", SDA: " + sda->getName() + ", SCL: " + scl->getName(); @@ -34,7 +34,7 @@ class I2CManager { return getWireFor(config.sda, config.scl); } - TwoWire& getWireFor(PinPtr sda, PinPtr scl) { + TwoWire& getWireFor(InternalPinPtr sda, InternalPinPtr scl) { GpioPair key = std::make_pair(sda, scl); auto it = wireMap.find(key); if (it != wireMap.end()) { diff --git a/main/kernel/PcntManager.hpp b/main/kernel/PcntManager.hpp index 770b7d57..7157164d 100644 --- a/main/kernel/PcntManager.hpp +++ b/main/kernel/PcntManager.hpp @@ -15,7 +15,7 @@ namespace farmhub::kernel { // TODO Limit number of channels available struct PcntUnit { - PcntUnit(pcnt_unit_handle_t unit, PinPtr pin) + PcntUnit(pcnt_unit_handle_t unit, InternalPinPtr pin) : unit(unit) , pin(pin) { } @@ -54,12 +54,12 @@ struct PcntUnit { private: pcnt_unit_handle_t unit; - PinPtr pin; + InternalPinPtr pin; }; class PcntManager { public: - PcntUnit registerUnit(PinPtr pin) { + PcntUnit registerUnit(InternalPinPtr pin) { pcnt_unit_config_t unitConfig = { .low_limit = std::numeric_limits::min(), .high_limit = std::numeric_limits::max(), diff --git a/main/kernel/PwmManager.hpp b/main/kernel/PwmManager.hpp index 91278a3a..b70c94e5 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(PinPtr pin, uint32_t freq, uint8_t resolutionBits) + PwmPin(InternalPinPtr pin, uint32_t freq, uint8_t resolutionBits) : pin(pin) , freq(freq) , resolutionBits(resolutionBits) { @@ -29,14 +29,14 @@ struct PwmPin { ledcWrite(pin->getGpio(), value); } - const PinPtr pin; + const InternalPinPtr pin; const uint32_t freq; const uint8_t resolutionBits; }; class PwmManager { public: - PwmPin registerPin(PinPtr pin, uint32_t freq, uint8_t resolutionBits = 8) { + PwmPin registerPin(InternalPinPtr 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); diff --git a/main/kernel/drivers/Bq27220Driver.hpp b/main/kernel/drivers/Bq27220Driver.hpp index 6538d6b6..287ea580 100644 --- a/main/kernel/drivers/Bq27220Driver.hpp +++ b/main/kernel/drivers/Bq27220Driver.hpp @@ -12,7 +12,7 @@ namespace farmhub::kernel::drivers { class Bq27220Driver : public BatteryDriver { public: - Bq27220Driver(I2CManager& i2c, PinPtr sda, PinPtr scl, const uint8_t address = 0x55) + Bq27220Driver(I2CManager& i2c, InternalPinPtr sda, InternalPinPtr scl, const uint8_t address = 0x55) : wire(i2c.getWireFor(sda, scl)) , address(address) { Log.info("Initializing BQ27220 driver on SDA %s, SCL %s", diff --git a/main/kernel/drivers/Drv8801Driver.hpp b/main/kernel/drivers/Drv8801Driver.hpp index 67c6761b..8f0c0404 100644 --- a/main/kernel/drivers/Drv8801Driver.hpp +++ b/main/kernel/drivers/Drv8801Driver.hpp @@ -29,7 +29,7 @@ class Drv8801Driver Drv8801Driver( PwmManager& pwm, PinPtr enablePin, - PinPtr phasePin, + InternalPinPtr phasePin, PinPtr mode1Pin, PinPtr mode2Pin, PinPtr currentPin, diff --git a/main/kernel/drivers/Drv8833Driver.hpp b/main/kernel/drivers/Drv8833Driver.hpp index 29de3420..03469285 100644 --- a/main/kernel/drivers/Drv8833Driver.hpp +++ b/main/kernel/drivers/Drv8833Driver.hpp @@ -23,10 +23,10 @@ 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, - PinPtr ain1Pin, - PinPtr ain2Pin, - PinPtr bin1Pin, - PinPtr bin2Pin, + InternalPinPtr ain1Pin, + InternalPinPtr ain2Pin, + InternalPinPtr bin1Pin, + InternalPinPtr bin2Pin, PinPtr faultPin, PinPtr sleepPin) : motorA(this, pwm, ain1Pin, ain2Pin, sleepPin != nullptr) @@ -68,8 +68,8 @@ class Drv8833Driver { Drv8833MotorDriver( Drv8833Driver* driver, PwmManager& pwm, - PinPtr in1Pin, - PinPtr in2Pin, + InternalPinPtr in1Pin, + InternalPinPtr in2Pin, bool canSleep) : driver(driver) , in1Channel(pwm.registerPin(in1Pin, PWM_FREQ, PWM_RESOLUTION)) diff --git a/main/kernel/drivers/Drv8874Driver.hpp b/main/kernel/drivers/Drv8874Driver.hpp index 7dd2750f..ec3e17dc 100644 --- a/main/kernel/drivers/Drv8874Driver.hpp +++ b/main/kernel/drivers/Drv8874Driver.hpp @@ -28,8 +28,8 @@ 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, - PinPtr in1Pin, - PinPtr in2Pin, + InternalPinPtr in1Pin, + InternalPinPtr in2Pin, PinPtr currentPin, PinPtr faultPin, PinPtr sleepPin) diff --git a/main/kernel/drivers/SwitchManager.hpp b/main/kernel/drivers/SwitchManager.hpp index 632d77d7..98376631 100644 --- a/main/kernel/drivers/SwitchManager.hpp +++ b/main/kernel/drivers/SwitchManager.hpp @@ -27,7 +27,7 @@ enum class SwitchMode { class Switch { public: virtual const String& getName() const = 0; - virtual PinPtr getPin() const = 0; + virtual InternalPinPtr getPin() const = 0; virtual bool isEngaged() const = 0; }; @@ -55,17 +55,17 @@ class SwitchManager { typedef std::function SwitchEngagementHandler; typedef std::function SwitchReleaseHandler; - const Switch& onEngaged(const String& name, PinPtr pin, SwitchMode mode, SwitchEngagementHandler engagementHandler) { + const Switch& onEngaged(const String& name, InternalPinPtr pin, SwitchMode mode, SwitchEngagementHandler engagementHandler) { return registerHandler( name, pin, mode, engagementHandler, [](const Switch&, milliseconds) {}); } - const Switch& onReleased(const String& name, PinPtr pin, SwitchMode mode, SwitchReleaseHandler releaseHandler) { + const Switch& onReleased(const String& name, InternalPinPtr pin, SwitchMode mode, SwitchReleaseHandler releaseHandler) { return registerHandler( name, pin, mode, [](const Switch&) {}, releaseHandler); } - const Switch& registerHandler(const String& name, PinPtr pin, SwitchMode mode, SwitchEngagementHandler engagementHandler, SwitchReleaseHandler releaseHandler) { + const Switch& registerHandler(const String& name, InternalPinPtr 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"); @@ -97,7 +97,7 @@ class SwitchManager { return name; } - PinPtr getPin() const override { + InternalPinPtr getPin() const override { return pin; } @@ -107,7 +107,7 @@ class SwitchManager { private: String name; - PinPtr pin; + InternalPinPtr pin; SwitchMode mode; SwitchEngagementHandler engagementHandler; diff --git a/main/peripherals/I2CConfig.hpp b/main/peripherals/I2CConfig.hpp index 104db446..90fc3b0f 100644 --- a/main/peripherals/I2CConfig.hpp +++ b/main/peripherals/I2CConfig.hpp @@ -19,10 +19,10 @@ 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" }; - Property scl { this, "scl" }; + Property sda { this, "sda" }; + Property scl { this, "scl" }; - I2CConfig parse(uint8_t defaultAddress = 0xFF, PinPtr defaultSda = nullptr, PinPtr defaultScl = nullptr) const { + I2CConfig parse(uint8_t defaultAddress = 0xFF, InternalPinPtr defaultSda = nullptr, InternalPinPtr defaultScl = nullptr) const { return { address.get().isEmpty() ? defaultAddress diff --git a/main/peripherals/SinglePinDeviceConfig.hpp b/main/peripherals/SinglePinDeviceConfig.hpp index bc9336c8..b84d83f0 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" }; + 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 1f319874..7bec698a 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" }; - Property closedPin { this, "closedPin" }; + 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, - PinPtr openPin, - PinPtr closedPin, + InternalPinPtr openPin, + InternalPinPtr closedPin, ticks movementTimeout, std::function publishTelemetry) : Component(name, mqttRoot) diff --git a/main/peripherals/environment/Ds18B20SoilSensor.hpp b/main/peripherals/environment/Ds18B20SoilSensor.hpp index 01875c3f..35fa9bcb 100644 --- a/main/peripherals/environment/Ds18B20SoilSensor.hpp +++ b/main/peripherals/environment/Ds18B20SoilSensor.hpp @@ -32,7 +32,7 @@ class Ds18B20SoilSensorComponent Ds18B20SoilSensorComponent( const String& name, shared_ptr mqttRoot, - PinPtr pin) + InternalPinPtr pin) : Component(name, mqttRoot) { Log.info("Initializing DS18B20 soil temperature sensor on pin %s", @@ -90,7 +90,7 @@ class Ds18B20SoilSensorComponent class Ds18B20SoilSensor : public Peripheral { public: - Ds18B20SoilSensor(const String& name, shared_ptr mqttRoot, PinPtr pin) + Ds18B20SoilSensor(const String& name, shared_ptr mqttRoot, InternalPinPtr pin) : Peripheral(name, mqttRoot) , sensor(name, mqttRoot, pin) { } diff --git a/main/peripherals/fence/ElectricFenceMonitor.hpp b/main/peripherals/fence/ElectricFenceMonitor.hpp index 4fbfcc0e..ce408454 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 { - PinPtr pin; + InternalPinPtr pin; uint16_t voltage; }; diff --git a/main/peripherals/flow_control/FlowControl.hpp b/main/peripherals/flow_control/FlowControl.hpp index 49ff5dee..76fadd58 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, - PinPtr pin, + InternalPinPtr 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 a93d3844..bc56125f 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, PinPtr pin, double qFactor, milliseconds measurementFrequency) + FlowMeter(const String& name, shared_ptr mqttRoot, PcntManager& pcnt, InternalPinPtr 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 cf7a3813..96b8ec16 100644 --- a/main/peripherals/flow_meter/FlowMeterComponent.hpp +++ b/main/peripherals/flow_meter/FlowMeterComponent.hpp @@ -27,7 +27,7 @@ class FlowMeterComponent const String& name, shared_ptr mqttRoot, PcntManager& pcnt, - PinPtr pin, + InternalPinPtr pin, double qFactor, milliseconds measurementFrequency) : Component(name, mqttRoot) diff --git a/main/peripherals/flow_meter/FlowMeterConfig.hpp b/main/peripherals/flow_meter/FlowMeterConfig.hpp index 2c96f180..b2752e23 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" }; + Property pin { this, "pin" }; Property qFactor { this, "qFactor", 5.0 }; Property measurementFrequency { this, "measurementFrequency", 1s }; }; From 659e013f118d9a7abd6a90ba4c1203f36eb615dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 00:15:50 +0200 Subject: [PATCH 03/16] Only internal GPIOs can do analog input --- main/devices/Pin.hpp | 4 +--- main/kernel/drivers/BatteryDriver.hpp | 4 ++-- main/peripherals/environment/SoilMoistureSensor.hpp | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/main/devices/Pin.hpp b/main/devices/Pin.hpp index 4e0dd2a6..151e2314 100644 --- a/main/devices/Pin.hpp +++ b/main/devices/Pin.hpp @@ -34,8 +34,6 @@ class Pin { virtual int digitalRead() const = 0; - virtual uint16_t analogRead() const = 0; - inline const String& getName() const { return name; } @@ -102,7 +100,7 @@ class InternalPin : public Pin { return ::digitalRead(gpio); } - inline uint16_t analogRead() const override { + inline uint16_t analogRead() const { return ::analogRead(gpio); } diff --git a/main/kernel/drivers/BatteryDriver.hpp b/main/kernel/drivers/BatteryDriver.hpp index c4a0e64b..78d75395 100644 --- a/main/kernel/drivers/BatteryDriver.hpp +++ b/main/kernel/drivers/BatteryDriver.hpp @@ -23,7 +23,7 @@ class BatteryDriver : public TelemetryProvider { class AnalogBatteryDriver : public BatteryDriver { public: - AnalogBatteryDriver(PinPtr pin, float voltageDividerRatio) + AnalogBatteryDriver(InternalPinPtr pin, float voltageDividerRatio) : pin(pin) , voltageDividerRatio(voltageDividerRatio) { Log.info("Initializing analog battery driver on pin %s", @@ -38,7 +38,7 @@ class AnalogBatteryDriver } private: - const PinPtr pin; + const InternalPinPtr pin; const float voltageDividerRatio; }; diff --git a/main/peripherals/environment/SoilMoistureSensor.hpp b/main/peripherals/environment/SoilMoistureSensor.hpp index 830ecc69..4bb7fe11 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" }; + Property pin { this, "pin" }; // These values need calibrating for each sensor Property air { this, "air", 3000 }; Property water { this, "water", 1000 }; @@ -60,7 +60,7 @@ class SoilMoistureSensorComponent private: const int airValue; const int waterValue; - PinPtr pin; + InternalPinPtr pin; }; class SoilMoistureSensor From 723c7f969b873068b26042333446ba9523d3f371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 11:12:33 +0100 Subject: [PATCH 04/16] Add support for I2C devices --- main/kernel/I2CManager.hpp | 104 +++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/main/kernel/I2CManager.hpp b/main/kernel/I2CManager.hpp index 03c2fd0e..9c8f3be3 100644 --- a/main/kernel/I2CManager.hpp +++ b/main/kernel/I2CManager.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -12,6 +13,8 @@ namespace farmhub::kernel { +using std::shared_ptr; + using farmhub::devices::PinPtr; using GpioPair = std::pair; @@ -28,6 +31,94 @@ struct I2CConfig { } }; +class I2CTransmission; + +class I2CDevice { +public: + I2CDevice(const String& name, TwoWire& wire, uint8_t address) + : name(name) + , wire(wire) + , address(address) { + } + +private: + const String name; + TwoWire& wire; + const uint8_t address; + + friend class I2CTransmission; +}; + +class I2CTransmission { +public: + I2CTransmission(shared_ptr device) + : device(device) { + device->wire.beginTransmission(device->address); + } + + ~I2CTransmission() { + auto result = device->wire.endTransmission(); + if (result != 0) { + Log.error("Communication unsuccessful with I2C device %s at address 0x%02x, result: %d", + device->name.c_str(), device->address, result); + } + } + + size_t requestFrom(size_t len, bool stopBit = true) { + Log.debug("Requesting %d bytes from I2C device %s at address 0x%02x", + len, device->name.c_str(), device->address); + auto count = device->wire.requestFrom(device->address, len, stopBit); + Log.debug("Received %d bytes from I2C device %s at address 0x%02x", + count, device->name.c_str(), device->address); + return count; + } + + size_t write(uint8_t data) { + Log.debug("Writing 0x%02x to I2C device %s at address 0x%02x", + data, device->name.c_str(), device->address); + auto count = device->wire.write(data); + Log.debug("Wrote %d bytes to I2C device %s at address 0x%02x", + count, device->name.c_str(), device->address); + return count; + } + + size_t write(const uint8_t *data, size_t quantity) { + Log.debug("Writing %d bytes to I2C device %s at address 0x%02x", + quantity, device->name.c_str(), device->address); + auto count = device->wire.write(data, quantity); + Log.debug("Wrote %d bytes to I2C device %s at address 0x%02x", + count, device->name.c_str(), device->address); + return count; + } + + int available() { + return device->wire.available(); + } + + int read() { + auto value = device->wire.read(); + Log.debug("Read 0x%02x from I2C device %s at address 0x%02x", + value, device->name.c_str(), device->address); + return value; + } + + int peek() { + auto value = device->wire.peek(); + Log.debug("Peeked 0x%02x from I2C device %s at address 0x%02x", + value, device->name.c_str(), device->address); + return value; + } + + void flush() { + Log.debug("Flushing I2C device %s at address 0x%02x", + device->name.c_str(), device->address); + device->wire.flush(); + } + +private: + shared_ptr device; +}; + class I2CManager { public: TwoWire& getWireFor(const I2CConfig& config) { @@ -57,6 +148,19 @@ class I2CManager { } } + shared_ptr createDevice(const String& name, const I2CConfig& config) { + return createDevice(name, config.sda, config.scl, config.address); + } + + shared_ptr createDevice(const String& name, InternalPinPtr sda, InternalPinPtr scl, uint8_t address) { + auto device = std::make_shared(name, getWireFor(sda, scl), address); + Log.info("Created I2C device %s at address 0x%02x", + name.c_str(), address); + // Test if communication is possible + I2CTransmission tx(device); + return device; + } + private: uint8_t nextBus = 0; From 4b7b1ef778c40da3131142b97000f09db8b67582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 11:31:39 +0100 Subject: [PATCH 05/16] Use new I2C device for battery --- main/kernel/drivers/Bq27220Driver.hpp | 57 ++++++++++----------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/main/kernel/drivers/Bq27220Driver.hpp b/main/kernel/drivers/Bq27220Driver.hpp index 287ea580..961633f0 100644 --- a/main/kernel/drivers/Bq27220Driver.hpp +++ b/main/kernel/drivers/Bq27220Driver.hpp @@ -13,18 +13,10 @@ namespace farmhub::kernel::drivers { class Bq27220Driver : public BatteryDriver { public: Bq27220Driver(I2CManager& i2c, InternalPinPtr sda, InternalPinPtr scl, const uint8_t address = 0x55) - : wire(i2c.getWireFor(sda, scl)) - , address(address) { + : device(i2c.createDevice("battery:bq27220", sda, scl, address)) { 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) { - // TODO Throw an actual exception? - Log.error("BQ27220 not found at address 0x%02x", address); - return; - } - auto deviceType = readControlWord(0x0001); if (deviceType != 0x0220) { Log.error("BQ27220 at address 0x%02x is not a BQ27220 (0x%04x)", @@ -61,34 +53,28 @@ class Bq27220Driver : public BatteryDriver { private: bool readFrom(uint8_t reg, uint8_t* buffer, size_t length) { - wire.beginTransmission(address); - wire.write(reg); - auto txResult = wire.endTransmission(); - if (txResult != 0) { - Log.error("Failed to write to 0x%02x: %d", reg, txResult); - return false; + { + I2CTransmission tx(device); + tx.write(reg); } - - auto rxResult = wire.requestFrom(address, (uint8_t) length); - if (rxResult != length) { - Log.error("Failed to read from 0x%02x: %d", reg, rxResult); - return false; - } - for (size_t i = 0; i < length; i++) { - buffer[i] = wire.read(); - // Log.trace("Read 0x%02x from 0x%02x", buffer[i], reg); + { + I2CTransmission tx(device); + auto rxResult = tx.requestFrom((uint8_t) length); + if (rxResult != length) { + Log.error("Failed to read from 0x%02x: %d", reg, rxResult); + return false; + } + for (size_t i = 0; i < length; i++) { + buffer[i] = tx.read(); + } } return true; } - bool writeTo(uint8_t reg, const uint8_t* buffer, size_t length) { - wire.beginTransmission(address); - wire.write(reg); - for (size_t i = 0; i < length; i++) { - // Log.trace("Writing 0x%02x to 0x%02x", buffer[i], reg); - wire.write(buffer[i]); - } - return wire.endTransmission() == 0; + void writeTo(uint8_t reg, const uint8_t* buffer, size_t length) { + I2CTransmission tx(device); + tx.write(reg); + tx.write(buffer, length); } uint8_t readByte(uint8_t reg) { @@ -107,9 +93,9 @@ class Bq27220Driver : public BatteryDriver { return static_cast(readWord(reg)); } - bool writeWord(uint8_t reg, uint16_t value) { + void writeWord(uint8_t reg, uint16_t value) { uint16_t buffer = value; - return writeTo(reg, reinterpret_cast(&buffer), 2); + writeTo(reg, reinterpret_cast(&buffer), 2); } uint16_t readControlWord(uint16_t subcommand) { @@ -117,8 +103,7 @@ class Bq27220Driver : public BatteryDriver { return readByte(0x40) | (readByte(0x41) << 8); } - TwoWire& wire; - const uint8_t address; + shared_ptr device; }; } // namespace farmhub::kernel::drivers From 7b273477b6643de4a04a6dd06068d2f7ecab994a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 11:33:08 +0100 Subject: [PATCH 06/16] Add support for XL9535/XL9555 GPIO extender --- main/devices/DeviceDefinition.hpp | 4 + main/devices/Pin.hpp | 8 +- main/peripherals/multiplexer/Xl9535.hpp | 153 ++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 main/peripherals/multiplexer/Xl9535.hpp diff --git a/main/devices/DeviceDefinition.hpp b/main/devices/DeviceDefinition.hpp index e68f9c21..bcd9d312 100644 --- a/main/devices/DeviceDefinition.hpp +++ b/main/devices/DeviceDefinition.hpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace farmhub::kernel; using namespace farmhub::kernel::drivers; @@ -78,6 +79,7 @@ class DeviceDefinition { peripheralManager.registerFactory(electricFenceMonitorFactory); peripheralManager.registerFactory(bh1750Factory); peripheralManager.registerFactory(tsl2591Factory); + peripheralManager.registerFactory(xl9535Factory); registerDeviceSpecificPeripheralFactories(peripheralManager); } @@ -121,6 +123,8 @@ class DeviceDefinition { farmhub::peripherals::light_sensor::Bh1750Factory bh1750Factory; farmhub::peripherals::light_sensor::Tsl2591Factory tsl2591Factory; + + farmhub::peripherals::multiplexer::Xl9535Factory xl9535Factory; }; } // namespace farmhub::devices diff --git a/main/devices/Pin.hpp b/main/devices/Pin.hpp index 151e2314..444ccfa5 100644 --- a/main/devices/Pin.hpp +++ b/main/devices/Pin.hpp @@ -38,15 +38,15 @@ class Pin { return name; } + static void registerPin(const String& name, PinPtr pin) { + BY_NAME[name] = pin; + } + protected: Pin(const String& name) : name(name) { } - static void registerPin(const String& name, PinPtr pin) { - BY_NAME[name] = pin; - } - protected: const String name; diff --git a/main/peripherals/multiplexer/Xl9535.hpp b/main/peripherals/multiplexer/Xl9535.hpp new file mode 100644 index 00000000..cdee809c --- /dev/null +++ b/main/peripherals/multiplexer/Xl9535.hpp @@ -0,0 +1,153 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace farmhub::peripherals::multiplexer { + +class Xl9535DeviceConfig + : public I2CDeviceConfig { +}; + +class Xl9535Component + : public Component { + +public: + Xl9535Component( + const String& name, + shared_ptr mqttRoot, + I2CManager& i2c, + I2CConfig config) + : Component(name, mqttRoot) + , device(i2c.createDevice(name, config)) { + Log.info("Initializing XL9535 multiplexer with %s", + config.toString().c_str()); + } + + void pinMode(uint8_t pin, uint8_t mode) { + if (mode == OUTPUT) { + direction &= ~(1 << pin); + } else { + direction |= 1 << pin; + } + if (pin < 8) { + updateDirection1(); + } else { + updateDirection2(); + } + } + + void digitalWrite(uint8_t pin, uint8_t val) { + if (val == HIGH) { + output |= 1 << pin; + } else { + output &= ~(1 << pin); + } + if (pin < 8) { + updateOutput1(); + } else { + updateOutput2(); + } + } + + int digitalRead(uint8_t pin) { + I2CTransmission tx(device); + tx.write(pin < 8 ? 0x00 : 0x01); + tx.requestFrom(1); + uint8_t data = tx.read(); + return (data >> (pin % 8)) & 1; + } + +private: + void updateDirection1() { + I2CTransmission tx(device); + tx.write(0x06); + tx.write(direction & 0xFF); + } + + void updateDirection2() { + I2CTransmission tx(device); + tx.write(0x07); + tx.write(direction >> 8); + } + + void updateOutput1() { + I2CTransmission tx(device); + tx.write(0x02); + tx.write(output & 0xFF); + } + + void updateOutput2() { + I2CTransmission tx(device); + tx.write(0x03); + tx.write(output >> 8); + } + + shared_ptr device; + + uint16_t polarity = 0; + uint16_t direction = 0xFFFF; + uint16_t output = 0; +}; + +class Xl9535Pin : public Pin { +public: + Xl9535Pin(const String& name, Xl9535Component& mpx, uint8_t pin) + : Pin(name) + , mpx(mpx) + , pin(pin) { + } + + void pinMode(uint8_t mode) const override { + mpx.pinMode(pin, mode); + } + + void digitalWrite(uint8_t val) const override { + mpx.digitalWrite(pin, val); + } + + int digitalRead() const override { + return mpx.digitalRead(pin); + } + +private: + Xl9535Component& mpx; + const uint8_t pin; +}; + +class Xl9535 + : public Peripheral { +public: + Xl9535(const String& name, shared_ptr mqttRoot, I2CManager& i2c, I2CConfig config) + : Peripheral(name, mqttRoot) + , component(name, mqttRoot, i2c, config) { + + // Create a pin for each bit in the pins mask + for (int i = 0; i < 16; i++) { + String pinName = name + ":" + String(i); + auto pin = std::make_shared(pinName, component, i); + Pin::registerPin(pinName, pin); + } + } + +private: + Xl9535Component component; +}; + +class Xl9535Factory + : public PeripheralFactory { +public: + Xl9535Factory() + : PeripheralFactory("multiplexer:xl9535") { + } + + unique_ptr> createPeripheral(const String& name, const Xl9535DeviceConfig& deviceConfig, shared_ptr mqttRoot, PeripheralServices& services) override { + return make_unique(name, mqttRoot, services.i2c, deviceConfig.parse()); + } +}; + +} // namespace farmhub::peripherals::multiplexer From e35d5f2cafff5813fc528f315298d341def8740d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 11:56:26 +0100 Subject: [PATCH 07/16] Log registered external pins --- main/peripherals/multiplexer/Xl9535.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/peripherals/multiplexer/Xl9535.hpp b/main/peripherals/multiplexer/Xl9535.hpp index cdee809c..eb4ea1ac 100644 --- a/main/peripherals/multiplexer/Xl9535.hpp +++ b/main/peripherals/multiplexer/Xl9535.hpp @@ -129,6 +129,8 @@ class Xl9535 // Create a pin for each bit in the pins mask for (int i = 0; i < 16; i++) { String pinName = name + ":" + String(i); + Log.trace("Registering external pin %s", + pinName.c_str()); auto pin = std::make_shared(pinName, component, i); Pin::registerPin(pinName, pin); } From f79d21d7b76e804cca6b36510fa304c14f867478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 20:49:04 +0100 Subject: [PATCH 08/16] Reduce I2C logging level --- main/kernel/I2CManager.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/main/kernel/I2CManager.hpp b/main/kernel/I2CManager.hpp index 9c8f3be3..e19c979f 100644 --- a/main/kernel/I2CManager.hpp +++ b/main/kernel/I2CManager.hpp @@ -65,28 +65,28 @@ class I2CTransmission { } size_t requestFrom(size_t len, bool stopBit = true) { - Log.debug("Requesting %d bytes from I2C device %s at address 0x%02x", + Log.trace("Requesting %d bytes from I2C device %s at address 0x%02x", len, device->name.c_str(), device->address); auto count = device->wire.requestFrom(device->address, len, stopBit); - Log.debug("Received %d bytes from I2C device %s at address 0x%02x", + Log.trace("Received %d bytes from I2C device %s at address 0x%02x", count, device->name.c_str(), device->address); return count; } size_t write(uint8_t data) { - Log.debug("Writing 0x%02x to I2C device %s at address 0x%02x", + Log.trace("Writing 0x%02x to I2C device %s at address 0x%02x", data, device->name.c_str(), device->address); auto count = device->wire.write(data); - Log.debug("Wrote %d bytes to I2C device %s at address 0x%02x", + Log.trace("Wrote %d bytes to I2C device %s at address 0x%02x", count, device->name.c_str(), device->address); return count; } size_t write(const uint8_t *data, size_t quantity) { - Log.debug("Writing %d bytes to I2C device %s at address 0x%02x", + Log.trace("Writing %d bytes to I2C device %s at address 0x%02x", quantity, device->name.c_str(), device->address); auto count = device->wire.write(data, quantity); - Log.debug("Wrote %d bytes to I2C device %s at address 0x%02x", + Log.trace("Wrote %d bytes to I2C device %s at address 0x%02x", count, device->name.c_str(), device->address); return count; } @@ -97,20 +97,20 @@ class I2CTransmission { int read() { auto value = device->wire.read(); - Log.debug("Read 0x%02x from I2C device %s at address 0x%02x", + Log.trace("Read 0x%02x from I2C device %s at address 0x%02x", value, device->name.c_str(), device->address); return value; } int peek() { auto value = device->wire.peek(); - Log.debug("Peeked 0x%02x from I2C device %s at address 0x%02x", + Log.trace("Peeked 0x%02x from I2C device %s at address 0x%02x", value, device->name.c_str(), device->address); return value; } void flush() { - Log.debug("Flushing I2C device %s at address 0x%02x", + Log.trace("Flushing I2C device %s at address 0x%02x", device->name.c_str(), device->address); device->wire.flush(); } @@ -133,7 +133,7 @@ class I2CManager { sda->getName().c_str(), scl->getName().c_str()); return *(it->second); } else { - Log.trace("Creating new I2C bus for SDA: %s, SCL: %s", + Log.debug("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"); From c427fb1774be171fa130a9cc285c2108792dcb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 20:49:12 +0100 Subject: [PATCH 09/16] Reduce MQTT logging level --- main/kernel/drivers/MqttDriver.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/kernel/drivers/MqttDriver.hpp b/main/kernel/drivers/MqttDriver.hpp index 59560a15..4414fbd1 100644 --- a/main/kernel/drivers/MqttDriver.hpp +++ b/main/kernel/drivers/MqttDriver.hpp @@ -400,8 +400,8 @@ class MqttDriver { } else { Log.debug("MQTT: server: %s:%d, client ID is '%s', using TLS", hostname.c_str(), mqttServer.port, clientId.c_str()); - Log.debug("Server cert: %s", serverCert.c_str()); - Log.debug("Client cert: %s", clientCert.c_str()); + Log.trace("Server cert: %s", serverCert.c_str()); + Log.trace("Client cert: %s", clientCert.c_str()); wifiClientSecure.setCACert(serverCert.c_str()); wifiClientSecure.setCertificate(clientCert.c_str()); wifiClientSecure.setPrivateKey(clientKey.c_str()); @@ -490,7 +490,7 @@ class MqttDriver { // Actually subscribe to the given topic bool registerSubscriptionWithMqtt(const Subscription& subscription) { - Log.debug("MQTT: Subscribing to topic '%s' (qos = %d)", + Log.trace("MQTT: Subscribing to topic '%s' (qos = %d)", subscription.topic.c_str(), static_cast(subscription.qos)); bool success = mqttClient.subscribe(subscription.topic, static_cast(subscription.qos), [](const String& payload, const size_t size) { // Global handler will take care of putting the received message on the incoming queue From 4a3105ed7f39336ba494a9f5d5a9c9b3f3268bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 21:14:35 +0100 Subject: [PATCH 10/16] Lock I2C bus during transmission This helps avoid multiple parties transmitting at the same time. --- main/kernel/I2CManager.hpp | 86 +++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/main/kernel/I2CManager.hpp b/main/kernel/I2CManager.hpp index e19c979f..9178064c 100644 --- a/main/kernel/I2CManager.hpp +++ b/main/kernel/I2CManager.hpp @@ -18,7 +18,6 @@ using std::shared_ptr; using farmhub::devices::PinPtr; using GpioPair = std::pair; -using TwoWireMap = std::map; struct I2CConfig { public: @@ -31,19 +30,29 @@ struct I2CConfig { } }; +class I2CBus { +public: + I2CBus(TwoWire& wire) + : wire(wire) { + } + + TwoWire& wire; + Mutex mutex; +}; + class I2CTransmission; class I2CDevice { public: - I2CDevice(const String& name, TwoWire& wire, uint8_t address) + I2CDevice(const String& name, I2CBus& bus, uint8_t address) : name(name) - , wire(wire) + , bus(bus) , address(address) { } private: const String name; - TwoWire& wire; + I2CBus& bus; const uint8_t address; friend class I2CTransmission; @@ -52,12 +61,13 @@ class I2CDevice { class I2CTransmission { public: I2CTransmission(shared_ptr device) - : device(device) { - device->wire.beginTransmission(device->address); + : device(device) + , lock(device->bus.mutex) { + wire().beginTransmission(device->address); } ~I2CTransmission() { - auto result = device->wire.endTransmission(); + auto result = wire().endTransmission(); if (result != 0) { Log.error("Communication unsuccessful with I2C device %s at address 0x%02x, result: %d", device->name.c_str(), device->address, result); @@ -67,7 +77,7 @@ class I2CTransmission { size_t requestFrom(size_t len, bool stopBit = true) { Log.trace("Requesting %d bytes from I2C device %s at address 0x%02x", len, device->name.c_str(), device->address); - auto count = device->wire.requestFrom(device->address, len, stopBit); + auto count = wire().requestFrom(device->address, len, stopBit); Log.trace("Received %d bytes from I2C device %s at address 0x%02x", count, device->name.c_str(), device->address); return count; @@ -76,7 +86,7 @@ class I2CTransmission { size_t write(uint8_t data) { Log.trace("Writing 0x%02x to I2C device %s at address 0x%02x", data, device->name.c_str(), device->address); - auto count = device->wire.write(data); + auto count = wire().write(data); Log.trace("Wrote %d bytes to I2C device %s at address 0x%02x", count, device->name.c_str(), device->address); return count; @@ -85,25 +95,25 @@ class I2CTransmission { size_t write(const uint8_t *data, size_t quantity) { Log.trace("Writing %d bytes to I2C device %s at address 0x%02x", quantity, device->name.c_str(), device->address); - auto count = device->wire.write(data, quantity); + auto count = wire().write(data, quantity); Log.trace("Wrote %d bytes to I2C device %s at address 0x%02x", count, device->name.c_str(), device->address); return count; } int available() { - return device->wire.available(); + return wire().available(); } int read() { - auto value = device->wire.read(); + auto value = wire().read(); Log.trace("Read 0x%02x from I2C device %s at address 0x%02x", value, device->name.c_str(), device->address); return value; } int peek() { - auto value = device->wire.peek(); + auto value = wire().peek(); Log.trace("Peeked 0x%02x from I2C device %s at address 0x%02x", value, device->name.c_str(), device->address); return value; @@ -112,11 +122,16 @@ class I2CTransmission { void flush() { Log.trace("Flushing I2C device %s at address 0x%02x", device->name.c_str(), device->address); - device->wire.flush(); + wire().flush(); } private: + inline TwoWire& wire() const { + return device->bus.wire; + } + shared_ptr device; + Lock lock; }; class I2CManager { @@ -126,9 +141,27 @@ class I2CManager { } TwoWire& getWireFor(InternalPinPtr sda, InternalPinPtr scl) { + return getBusFor(sda, scl).wire; + } + + shared_ptr createDevice(const String& name, const I2CConfig& config) { + return createDevice(name, config.sda, config.scl, config.address); + } + + shared_ptr createDevice(const String& name, InternalPinPtr sda, InternalPinPtr scl, uint8_t address) { + auto device = std::make_shared(name, getBusFor(sda, scl), address); + Log.info("Created I2C device %s at address 0x%02x", + name.c_str(), address); + // Test if communication is possible + I2CTransmission tx(device); + return device; + } + +private: + I2CBus& getBusFor(InternalPinPtr sda, InternalPinPtr scl) { GpioPair key = std::make_pair(sda, scl); - auto it = wireMap.find(key); - if (it != wireMap.end()) { + auto it = busMap.find(key); + if (it != busMap.end()) { Log.trace("Reusing already registered I2C bus for SDA: %s, SCL: %s", sda->getName().c_str(), scl->getName().c_str()); return *(it->second); @@ -143,28 +176,15 @@ class I2CManager { throw std::runtime_error( String("Failed to initialize I2C bus for SDA: " + sda->getName() + ", SCL: " + scl->getName()).c_str()); } - wireMap[key] = wire; - return *wire; + I2CBus* bus = new I2CBus(*wire); + busMap[key] = bus; + return *bus; } } - shared_ptr createDevice(const String& name, const I2CConfig& config) { - return createDevice(name, config.sda, config.scl, config.address); - } - - shared_ptr createDevice(const String& name, InternalPinPtr sda, InternalPinPtr scl, uint8_t address) { - auto device = std::make_shared(name, getWireFor(sda, scl), address); - Log.info("Created I2C device %s at address 0x%02x", - name.c_str(), address); - // Test if communication is possible - I2CTransmission tx(device); - return device; - } - -private: uint8_t nextBus = 0; - TwoWireMap wireMap; + std::map busMap; }; } // namespace farmhub::kernel From 887dd3efa3e9dfd31a39f47fab0d04b410353a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 21:21:53 +0100 Subject: [PATCH 11/16] Move motor into ValveControlStrategy implementations --- main/peripherals/flow_control/FlowControl.hpp | 5 +- main/peripherals/valve/Valve.hpp | 6 +- main/peripherals/valve/ValveComponent.hpp | 89 +++++++++---------- main/peripherals/valve/ValveConfig.hpp | 8 +- 4 files changed, 52 insertions(+), 56 deletions(-) diff --git a/main/peripherals/flow_control/FlowControl.hpp b/main/peripherals/flow_control/FlowControl.hpp index 76fadd58..7963327b 100644 --- a/main/peripherals/flow_control/FlowControl.hpp +++ b/main/peripherals/flow_control/FlowControl.hpp @@ -34,13 +34,12 @@ class FlowControl : public Peripheral { shared_ptr mqttRoot, PcntManager& pcnt, SleepManager& sleepManager, - PwmMotorDriver& controller, ValveControlStrategy& strategy, InternalPinPtr pin, double qFactor, milliseconds measurementFrequency) : Peripheral(name, mqttRoot) - , valve(name, sleepManager, controller, strategy, mqttRoot, [this]() { + , valve(name, sleepManager, strategy, mqttRoot, [this]() { publishTelemetry(); }) , flowMeter(name, mqttRoot, pcnt, pin, qFactor, measurementFrequency) { @@ -95,6 +94,7 @@ class FlowControlFactory ValveControlStrategy* strategy; try { strategy = createValveControlStrategy( + targetMotor, valveConfig.strategy.get(), valveConfig.switchDuration.get(), valveConfig.holdDuty.get() / 100.0); @@ -107,7 +107,6 @@ class FlowControlFactory services.pcntManager, services.sleepManager, - targetMotor, *strategy, flowMeterConfig.pin.get(), diff --git a/main/peripherals/valve/Valve.hpp b/main/peripherals/valve/Valve.hpp index f319c63f..9f07c6a2 100644 --- a/main/peripherals/valve/Valve.hpp +++ b/main/peripherals/valve/Valve.hpp @@ -36,11 +36,10 @@ class Valve Valve( const String& name, SleepManager& sleepManager, - PwmMotorDriver& controller, ValveControlStrategy& strategy, shared_ptr mqttRoot) : Peripheral(name, mqttRoot) - , valve(name, sleepManager, controller, strategy, mqttRoot, [this]() { + , valve(name, sleepManager, strategy, mqttRoot, [this]() { publishTelemetry(); }) { } @@ -77,13 +76,14 @@ class ValveFactory ValveControlStrategy* strategy; try { strategy = createValveControlStrategy( + targetMotor, deviceConfig.strategy.get(), deviceConfig.switchDuration.get(), deviceConfig.holdDuty.get() / 100.0); } catch (const std::exception& e) { throw PeripheralCreationException("failed to create strategy: " + String(e.what())); } - return make_unique(name, services.sleepManager, targetMotor, *strategy, mqttRoot); + return make_unique(name, services.sleepManager, *strategy, mqttRoot); } }; diff --git a/main/peripherals/valve/ValveComponent.hpp b/main/peripherals/valve/ValveComponent.hpp index 8a1b0b6a..78951592 100644 --- a/main/peripherals/valve/ValveComponent.hpp +++ b/main/peripherals/valve/ValveComponent.hpp @@ -35,8 +35,8 @@ namespace farmhub::peripherals::valve { class ValveControlStrategy { public: - virtual void open(PwmMotorDriver& controller) = 0; - virtual void close(PwmMotorDriver& controller) = 0; + virtual void open() = 0; + virtual void close() = 0; virtual ValveState getDefaultState() const = 0; virtual String describe() const = 0; @@ -46,19 +46,20 @@ class HoldingValveControlStrategy : public ValveControlStrategy { public: - HoldingValveControlStrategy(milliseconds switchDuration, double holdDuty) - : switchDuration(switchDuration) + HoldingValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) + : controller(controller) + , switchDuration(switchDuration) , holdDuty(holdDuty) { } protected: - void driveAndHold(PwmMotorDriver& controller, ValveState targetState) { + void driveAndHold(ValveState targetState) { switch (targetState) { case ValveState::OPEN: - driveAndHold(controller, MotorPhase::FORWARD); + driveAndHold(MotorPhase::FORWARD); break; case ValveState::CLOSED: - driveAndHold(controller, MotorPhase::REVERSE); + driveAndHold(MotorPhase::REVERSE); break; default: // Ignore @@ -66,11 +67,12 @@ class HoldingValveControlStrategy } } + PwmMotorDriver& controller; const milliseconds switchDuration; const double holdDuty; private: - void driveAndHold(PwmMotorDriver& controller, MotorPhase phase) { + void driveAndHold(MotorPhase phase) { controller.drive(phase, 1.0); delay(switchDuration.count()); controller.drive(phase, holdDuty); @@ -80,15 +82,15 @@ class HoldingValveControlStrategy class NormallyClosedValveControlStrategy : public HoldingValveControlStrategy { public: - NormallyClosedValveControlStrategy(milliseconds switchDuration, double holdDuty) - : HoldingValveControlStrategy(switchDuration, holdDuty) { + NormallyClosedValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) + : HoldingValveControlStrategy(controller, switchDuration, holdDuty) { } - void open(PwmMotorDriver& controller) override { - driveAndHold(controller, ValveState::OPEN); + void open() override { + driveAndHold(ValveState::OPEN); } - void close(PwmMotorDriver& controller) override { + void close() override { controller.stop(); } @@ -104,16 +106,16 @@ class NormallyClosedValveControlStrategy class NormallyOpenValveControlStrategy : public HoldingValveControlStrategy { public: - NormallyOpenValveControlStrategy(milliseconds switchDuration, double holdDuty) - : HoldingValveControlStrategy(switchDuration, holdDuty) { + NormallyOpenValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) + : HoldingValveControlStrategy(controller, switchDuration, holdDuty) { } - void open(PwmMotorDriver& controller) override { + void open() override { controller.stop(); } - void close(PwmMotorDriver& controller) override { - driveAndHold(controller, ValveState::CLOSED); + void close() override { + driveAndHold(ValveState::CLOSED); } ValveState getDefaultState() const override { @@ -128,18 +130,19 @@ class NormallyOpenValveControlStrategy class LatchingValveControlStrategy : public ValveControlStrategy { public: - LatchingValveControlStrategy(milliseconds switchDuration, double switchDuty = 1.0) - : switchDuration(switchDuration) + LatchingValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double switchDuty = 1.0) + : controller(controller) + , switchDuration(switchDuration) , switchDuty(switchDuty) { } - void open(PwmMotorDriver& controller) override { + void open() override { controller.drive(MotorPhase::FORWARD, switchDuty); delay(switchDuration.count()); controller.stop(); } - void close(PwmMotorDriver& controller) override { + void close() override { controller.drive(MotorPhase::REVERSE, switchDuty); delay(switchDuration.count()); controller.stop(); @@ -154,6 +157,7 @@ class LatchingValveControlStrategy } private: + PwmMotorDriver& controller; const milliseconds switchDuration; const double switchDuty; }; @@ -163,13 +167,11 @@ class ValveComponent : public Component { ValveComponent( const String& name, SleepManager& sleepManager, - PwmMotorDriver& controller, ValveControlStrategy& strategy, shared_ptr mqttRoot, std::function publishTelemetry) : Component(name, mqttRoot) , sleepManager(sleepManager) - , controller(controller) , nvs(name) , strategy(strategy) , publishTelemetry(publishTelemetry) { @@ -177,41 +179,33 @@ class ValveComponent : public Component { Log.info("Creating valve '%s' with strategy %s", name.c_str(), strategy.describe().c_str()); - controller.stop(); - - // Rewrite this to a switch statement - if (strategy.getDefaultState() == ValveState::OPEN) { - state = ValveState::OPEN; - } else if (strategy.getDefaultState() == ValveState::CLOSED) { - state = ValveState::CLOSED; - } - + ValveState initState; switch (strategy.getDefaultState()) { case ValveState::OPEN: Log.info("Assuming valve '%s' is open by default", name.c_str()); - state = ValveState::OPEN; + initState = ValveState::OPEN; break; case ValveState::CLOSED: Log.info("Assuming valve '%s' is closed by default", name.c_str()); - state = ValveState::CLOSED; + initState = ValveState::CLOSED; break; default: // Try to load from NVS ValveState lastStoredState; if (nvs.get("state", lastStoredState)) { - state = lastStoredState; + initState = lastStoredState; Log.info("Restored state for valve '%s' from NVS: %d", name.c_str(), static_cast(state)); } else { - Log.info("No stored state for valve '%s'", + initState = ValveState::CLOSED; + Log.info("No stored state for valve '%s', defaulting to closed", name.c_str()); } break; } - - // TODO Restore stored state? + doTransitionTo(initState); mqttRoot->registerCommand("override", [this](const JsonObject& request, JsonObject& response) { ValveState targetState = request["state"].as(); @@ -313,14 +307,14 @@ class ValveComponent : public Component { void open() { Log.info("Opening valve '%s'", name.c_str()); KeepAwake keepAwake(sleepManager); - strategy.open(controller); + strategy.open(); setState(ValveState::OPEN); } void close() { Log.info("Closing valve '%s'", name.c_str()); KeepAwake keepAwake(sleepManager); - strategy.close(controller); + strategy.close(); setState(ValveState::CLOSED); } @@ -329,7 +323,15 @@ class ValveComponent : public Component { if (this->state == state) { return; } + doTransitionTo(state); + + mqttRoot->publish("events/state", [=](JsonObject& json) { + json["state"] = state; + }); + publishTelemetry(); + } + void doTransitionTo(ValveState state) { switch (state) { case ValveState::OPEN: open(); @@ -341,10 +343,6 @@ class ValveComponent : public Component { // Ignore break; } - mqttRoot->publish("events/state", [=](JsonObject& json) { - json["state"] = state; - }); - publishTelemetry(); } void setState(ValveState state) { @@ -356,7 +354,6 @@ class ValveComponent : public Component { } SleepManager& sleepManager; - PwmMotorDriver& controller; NvsStore nvs; ValveControlStrategy& strategy; std::function publishTelemetry; diff --git a/main/peripherals/valve/ValveConfig.hpp b/main/peripherals/valve/ValveConfig.hpp index 504749ab..5ff591d6 100644 --- a/main/peripherals/valve/ValveConfig.hpp +++ b/main/peripherals/valve/ValveConfig.hpp @@ -24,14 +24,14 @@ enum class ValveControlStrategyType { Latching }; -static ValveControlStrategy* createValveControlStrategy(ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) { +static ValveControlStrategy* createValveControlStrategy(PwmMotorDriver& motor, ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) { switch (strategy) { case ValveControlStrategyType::NormallyOpen: - return new NormallyOpenValveControlStrategy(switchDuration, holdDuty); + return new NormallyOpenValveControlStrategy(motor, switchDuration, holdDuty); case ValveControlStrategyType::NormallyClosed: - return new NormallyClosedValveControlStrategy(switchDuration, holdDuty); + return new NormallyClosedValveControlStrategy(motor, switchDuration, holdDuty); case ValveControlStrategyType::Latching: - return new LatchingValveControlStrategy(switchDuration, holdDuty); + return new LatchingValveControlStrategy(motor, switchDuration, holdDuty); default: throw std::runtime_error("Unknown strategy"); } From 7bfabb46744fd25642f45fbadb6a8573b43e5397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 22:54:23 +0100 Subject: [PATCH 12/16] Make ValveControlStrategy independent of motor controllers --- main/peripherals/flow_control/FlowControl.hpp | 2 +- main/peripherals/valve/Valve.hpp | 2 +- main/peripherals/valve/ValveComponent.hpp | 43 +++++++++++-------- main/peripherals/valve/ValveConfig.hpp | 8 ++-- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/main/peripherals/flow_control/FlowControl.hpp b/main/peripherals/flow_control/FlowControl.hpp index 7963327b..1ac07a21 100644 --- a/main/peripherals/flow_control/FlowControl.hpp +++ b/main/peripherals/flow_control/FlowControl.hpp @@ -93,7 +93,7 @@ class FlowControlFactory PwmMotorDriver& targetMotor = findMotor(valveConfig.motor.get()); ValveControlStrategy* strategy; try { - strategy = createValveControlStrategy( + strategy = createMotorValveControlStrategy( targetMotor, valveConfig.strategy.get(), valveConfig.switchDuration.get(), diff --git a/main/peripherals/valve/Valve.hpp b/main/peripherals/valve/Valve.hpp index 9f07c6a2..cb78bda1 100644 --- a/main/peripherals/valve/Valve.hpp +++ b/main/peripherals/valve/Valve.hpp @@ -75,7 +75,7 @@ class ValveFactory PwmMotorDriver& targetMotor = findMotor(deviceConfig.motor.get()); ValveControlStrategy* strategy; try { - strategy = createValveControlStrategy( + strategy = createMotorValveControlStrategy( targetMotor, deviceConfig.strategy.get(), deviceConfig.switchDuration.get(), diff --git a/main/peripherals/valve/ValveComponent.hpp b/main/peripherals/valve/ValveComponent.hpp index 78951592..77bf60c4 100644 --- a/main/peripherals/valve/ValveComponent.hpp +++ b/main/peripherals/valve/ValveComponent.hpp @@ -42,12 +42,23 @@ class ValveControlStrategy { virtual String describe() const = 0; }; -class HoldingValveControlStrategy +class MotorValveControlStrategy : public ValveControlStrategy { +public: + MotorValveControlStrategy(PwmMotorDriver& controller) + : controller(controller) { + } + +protected: + PwmMotorDriver& controller; +}; + +class HoldingMotorValveControlStrategy + : public MotorValveControlStrategy { public: - HoldingValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) - : controller(controller) + HoldingMotorValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) + : MotorValveControlStrategy(controller) , switchDuration(switchDuration) , holdDuty(holdDuty) { } @@ -67,7 +78,6 @@ class HoldingValveControlStrategy } } - PwmMotorDriver& controller; const milliseconds switchDuration; const double holdDuty; @@ -79,11 +89,11 @@ class HoldingValveControlStrategy } }; -class NormallyClosedValveControlStrategy - : public HoldingValveControlStrategy { +class NormallyClosedMotorValveControlStrategy + : public HoldingMotorValveControlStrategy { public: - NormallyClosedValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) - : HoldingValveControlStrategy(controller, switchDuration, holdDuty) { + NormallyClosedMotorValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) + : HoldingMotorValveControlStrategy(controller, switchDuration, holdDuty) { } void open() override { @@ -103,11 +113,11 @@ class NormallyClosedValveControlStrategy } }; -class NormallyOpenValveControlStrategy - : public HoldingValveControlStrategy { +class NormallyOpenMotorValveControlStrategy + : public HoldingMotorValveControlStrategy { public: - NormallyOpenValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) - : HoldingValveControlStrategy(controller, switchDuration, holdDuty) { + NormallyOpenMotorValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty) + : HoldingMotorValveControlStrategy(controller, switchDuration, holdDuty) { } void open() override { @@ -127,11 +137,11 @@ class NormallyOpenValveControlStrategy } }; -class LatchingValveControlStrategy - : public ValveControlStrategy { +class LatchingMotorValveControlStrategy + : public MotorValveControlStrategy { public: - LatchingValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double switchDuty = 1.0) - : controller(controller) + LatchingMotorValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double switchDuty = 1.0) + : MotorValveControlStrategy(controller) , switchDuration(switchDuration) , switchDuty(switchDuty) { } @@ -157,7 +167,6 @@ class LatchingValveControlStrategy } private: - PwmMotorDriver& controller; const milliseconds switchDuration; const double switchDuty; }; diff --git a/main/peripherals/valve/ValveConfig.hpp b/main/peripherals/valve/ValveConfig.hpp index 5ff591d6..23c10634 100644 --- a/main/peripherals/valve/ValveConfig.hpp +++ b/main/peripherals/valve/ValveConfig.hpp @@ -24,14 +24,14 @@ enum class ValveControlStrategyType { Latching }; -static ValveControlStrategy* createValveControlStrategy(PwmMotorDriver& motor, ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) { +static MotorValveControlStrategy* createMotorValveControlStrategy(PwmMotorDriver& motor, ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) { switch (strategy) { case ValveControlStrategyType::NormallyOpen: - return new NormallyOpenValveControlStrategy(motor, switchDuration, holdDuty); + return new NormallyOpenMotorValveControlStrategy(motor, switchDuration, holdDuty); case ValveControlStrategyType::NormallyClosed: - return new NormallyClosedValveControlStrategy(motor, switchDuration, holdDuty); + return new NormallyClosedMotorValveControlStrategy(motor, switchDuration, holdDuty); case ValveControlStrategyType::Latching: - return new LatchingValveControlStrategy(motor, switchDuration, holdDuty); + return new LatchingMotorValveControlStrategy(motor, switchDuration, holdDuty); default: throw std::runtime_error("Unknown strategy"); } From ba64db092811add3c829678702c85be56a484c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 23:16:46 +0100 Subject: [PATCH 13/16] Add pin-driven latching valve support --- main/peripherals/Motorized.hpp | 1 - main/peripherals/flow_control/FlowControl.hpp | 17 +---- main/peripherals/valve/Valve.hpp | 12 +--- main/peripherals/valve/ValveComponent.hpp | 28 ++++++++ main/peripherals/valve/ValveConfig.hpp | 67 +++++++++++++++---- 5 files changed, 86 insertions(+), 39 deletions(-) diff --git a/main/peripherals/Motorized.hpp b/main/peripherals/Motorized.hpp index 6af9d08e..78a6aee7 100644 --- a/main/peripherals/Motorized.hpp +++ b/main/peripherals/Motorized.hpp @@ -20,7 +20,6 @@ class Motorized { : motors(motors) { } -protected: PwmMotorDriver& findMotor(const String& motorName) { // If there's only one motor and no name is specified, use it if (motorName.isEmpty() && motors.size() == 1) { diff --git a/main/peripherals/flow_control/FlowControl.hpp b/main/peripherals/flow_control/FlowControl.hpp index 1ac07a21..cc8de60c 100644 --- a/main/peripherals/flow_control/FlowControl.hpp +++ b/main/peripherals/flow_control/FlowControl.hpp @@ -87,20 +87,9 @@ class FlowControlFactory } unique_ptr> createPeripheral(const String& name, const FlowControlDeviceConfig& deviceConfig, shared_ptr mqttRoot, PeripheralServices& services) override { - const ValveDeviceConfig& valveConfig = deviceConfig.valve.get(); - const FlowMeterDeviceConfig& flowMeterConfig = deviceConfig.flowMeter.get(); - - PwmMotorDriver& targetMotor = findMotor(valveConfig.motor.get()); - ValveControlStrategy* strategy; - try { - strategy = createMotorValveControlStrategy( - targetMotor, - valveConfig.strategy.get(), - valveConfig.switchDuration.get(), - valveConfig.holdDuty.get() / 100.0); - } catch (const std::exception& e) { - throw PeripheralCreationException("failed to create strategy: " + String(e.what())); - } + auto strategy = deviceConfig.valve.get().createValveControlStrategy(this); + + auto flowMeterConfig = deviceConfig.flowMeter.get(); return make_unique( name, mqttRoot, diff --git a/main/peripherals/valve/Valve.hpp b/main/peripherals/valve/Valve.hpp index cb78bda1..157a7054 100644 --- a/main/peripherals/valve/Valve.hpp +++ b/main/peripherals/valve/Valve.hpp @@ -72,17 +72,7 @@ class ValveFactory } unique_ptr> createPeripheral(const String& name, const ValveDeviceConfig& deviceConfig, shared_ptr mqttRoot, PeripheralServices& services) override { - PwmMotorDriver& targetMotor = findMotor(deviceConfig.motor.get()); - ValveControlStrategy* strategy; - try { - strategy = createMotorValveControlStrategy( - targetMotor, - deviceConfig.strategy.get(), - deviceConfig.switchDuration.get(), - deviceConfig.holdDuty.get() / 100.0); - } catch (const std::exception& e) { - throw PeripheralCreationException("failed to create strategy: " + String(e.what())); - } + auto strategy = deviceConfig.createValveControlStrategy(this); return make_unique(name, services.sleepManager, *strategy, mqttRoot); } }; diff --git a/main/peripherals/valve/ValveComponent.hpp b/main/peripherals/valve/ValveComponent.hpp index 77bf60c4..d45e6828 100644 --- a/main/peripherals/valve/ValveComponent.hpp +++ b/main/peripherals/valve/ValveComponent.hpp @@ -171,6 +171,34 @@ class LatchingMotorValveControlStrategy const double switchDuty; }; +class LatchingPinValveControlStrategy + : public ValveControlStrategy { +public: + LatchingPinValveControlStrategy(PinPtr pin) + : pin(pin) { + pin->pinMode(OUTPUT); + } + + void open() override { + pin->digitalWrite(HIGH); + } + + void close() override { + pin->digitalWrite(LOW); + } + + ValveState getDefaultState() const override { + return ValveState::NONE; + } + + String describe() const override { + return "latching with pin " + pin->getName(); + } + +private: + PinPtr pin; +}; + class ValveComponent : public Component { public: ValveComponent( diff --git a/main/peripherals/valve/ValveConfig.hpp b/main/peripherals/valve/ValveConfig.hpp index 23c10634..d5e5c6bc 100644 --- a/main/peripherals/valve/ValveConfig.hpp +++ b/main/peripherals/valve/ValveConfig.hpp @@ -24,19 +24,6 @@ enum class ValveControlStrategyType { Latching }; -static MotorValveControlStrategy* createMotorValveControlStrategy(PwmMotorDriver& motor, ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) { - switch (strategy) { - case ValveControlStrategyType::NormallyOpen: - return new NormallyOpenMotorValveControlStrategy(motor, switchDuration, holdDuty); - case ValveControlStrategyType::NormallyClosed: - return new NormallyClosedMotorValveControlStrategy(motor, switchDuration, holdDuty); - case ValveControlStrategyType::Latching: - return new LatchingMotorValveControlStrategy(motor, switchDuration, holdDuty); - default: - throw std::runtime_error("Unknown strategy"); - } -} - class ValveConfig : public ConfigurationSection { public: @@ -50,10 +37,64 @@ class ValveDeviceConfig : strategy(this, "strategy", defaultStrategy) { } + /** + * @brief The pin to use to control the valve. + * + * @details This can be an internal or an external pin. When specified, the motor is ignored. + */ + Property pin { this, "pin" }; + + /** + * @brief The name of the motor service to use to control the valve. + * + * @details When the pin is specified, this is ignored. + */ Property motor { this, "motor" }; + + /** + * @brief The strategy to use to control the motorized valve. + * + * @details Ignored when the pin is specified. + */ Property strategy; + + /** + * @brief Duty to use to hold the motorized valve in place. + * + * @details This is a percentage from 0 to 100, default is 100%. This is ignored for latching strategies and when the pin is specified. + */ Property holdDuty { this, "holdDuty", 100 }; // This is a percentage + + /** + * @brief Duration to keep the motor running to switch the motorized valve. + * + * @details This is in milliseconds, default is 500ms. This is ignored when the pin is specified. + */ Property switchDuration { this, "switchDuration", 500ms }; + + ValveControlStrategy* createValveControlStrategy(Motorized* motorOwner) const { + PinPtr pin = this->pin.get(); + if (pin != nullptr) { + return new LatchingPinValveControlStrategy(pin); + } + + PwmMotorDriver& motor = motorOwner->findMotor(this->motor.get()); + ValveControlStrategy* strategy; + + auto switchDuration = this->switchDuration.get(); + auto holdDuty = this->holdDuty.get() / 100.0; + + switch (this->strategy.get()) { + case ValveControlStrategyType::NormallyOpen: + return new NormallyOpenMotorValveControlStrategy(motor, switchDuration, holdDuty); + case ValveControlStrategyType::NormallyClosed: + return new NormallyClosedMotorValveControlStrategy(motor, switchDuration, holdDuty); + case ValveControlStrategyType::Latching: + return new LatchingMotorValveControlStrategy(motor, switchDuration, holdDuty); + default: + throw PeripheralCreationException("unknown strategy"); + } + } }; // JSON: ValveControlStrategyType From e29639805b8be3e1e015f3cdc1dec9b52746196a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 23:24:03 +0100 Subject: [PATCH 14/16] Handle default name via default property value --- main/peripherals/Peripheral.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/main/peripherals/Peripheral.hpp b/main/peripherals/Peripheral.hpp index a23b1afc..e10bce04 100644 --- a/main/peripherals/Peripheral.hpp +++ b/main/peripherals/Peripheral.hpp @@ -197,9 +197,6 @@ class PeripheralManager } String name = deviceConfig.name.get(); - if (name.isEmpty()) { - name = "default"; - } String type = deviceConfig.type.get(); try { Lock lock(stateMutex); @@ -249,7 +246,7 @@ class PeripheralManager private: class PeripheralDeviceConfiguration : public ConfigurationSection { public: - Property name { this, "name" }; + Property name { this, "name", "default" }; Property type { this, "type" }; Property params { this, "params" }; }; From f9cae6ab0f8f8d510605baf0a5bf10d482cb1a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 23:27:21 +0100 Subject: [PATCH 15/16] Document pins --- main/devices/Pin.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main/devices/Pin.hpp b/main/devices/Pin.hpp index 444ccfa5..d11d343a 100644 --- a/main/devices/Pin.hpp +++ b/main/devices/Pin.hpp @@ -18,6 +18,11 @@ using PinPtr = std::shared_ptr; class InternalPin; using InternalPinPtr = std::shared_ptr; +/** + * @brief A GPIO pin abstraction that allows digital reads and writes. + * + * @details This can be implemented by internal pins (GPIO pins of the MCU) or external pins provided by external peripherals. + */ class Pin { public: static PinPtr byName(const String& name) { @@ -55,6 +60,9 @@ class Pin { std::map Pin::BY_NAME; +/** + * @brief An internal GPIO pin of the MCU. These pins can do analog reads as well, and can expose the GPIO number. + */ class InternalPin : public Pin { public: static InternalPinPtr registerPin(const String& name, gpio_num_t gpio) { From 3fe0cddc550a7522f5b2c6ad514f93f3ad15715b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Sun, 27 Oct 2024 23:33:15 +0100 Subject: [PATCH 16/16] Move Pin.hpp to kernel --- main/devices/UglyDucklingMk4.hpp | 6 +++--- main/devices/UglyDucklingMk5.hpp | 6 +++--- main/devices/UglyDucklingMk6.hpp | 2 +- main/devices/UglyDucklingMk7.hpp | 2 +- main/kernel/I2CManager.hpp | 6 +++--- main/{devices => kernel}/Pin.hpp | 12 ++++++------ main/kernel/drivers/BatteryDriver.hpp | 4 ++-- main/kernel/drivers/LedDriver.hpp | 4 ++-- main/kernel/drivers/SwitchManager.hpp | 4 ++-- main/peripherals/multiplexer/Xl9535.hpp | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) rename main/{devices => kernel}/Pin.hpp (95%) diff --git a/main/devices/UglyDucklingMk4.hpp b/main/devices/UglyDucklingMk4.hpp index a76849bb..dd3487d6 100644 --- a/main/devices/UglyDucklingMk4.hpp +++ b/main/devices/UglyDucklingMk4.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,6 @@ #include #include -#include using namespace farmhub::kernel; using namespace farmhub::peripherals::chicken_door; @@ -59,8 +59,8 @@ class UglyDucklingMk4 : public DeviceDefinition { public: UglyDucklingMk4() : DeviceDefinition( - pins::STATUS, - pins::BOOT) { + pins::STATUS, + pins::BOOT) { } void registerDeviceSpecificPeripheralFactories(PeripheralManager& peripheralManager) override { diff --git a/main/devices/UglyDucklingMk5.hpp b/main/devices/UglyDucklingMk5.hpp index 7d1250a0..6ef9d5df 100644 --- a/main/devices/UglyDucklingMk5.hpp +++ b/main/devices/UglyDucklingMk5.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,6 @@ #include #include -#include using namespace farmhub::kernel; using namespace farmhub::peripherals::chicken_door; @@ -79,8 +79,8 @@ class UglyDucklingMk5 : public DeviceDefinition { public: UglyDucklingMk5() : DeviceDefinition( - pins::STATUS, - pins::BOOT) { + pins::STATUS, + pins::BOOT) { } void registerDeviceSpecificPeripheralFactories(PeripheralManager& peripheralManager) override { diff --git a/main/devices/UglyDucklingMk6.hpp b/main/devices/UglyDucklingMk6.hpp index 4c7eb106..16e7fa37 100644 --- a/main/devices/UglyDucklingMk6.hpp +++ b/main/devices/UglyDucklingMk6.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include -#include using namespace farmhub::kernel; using namespace farmhub::peripherals::chicken_door; diff --git a/main/devices/UglyDucklingMk7.hpp b/main/devices/UglyDucklingMk7.hpp index 45a4b4cc..ad693ad5 100644 --- a/main/devices/UglyDucklingMk7.hpp +++ b/main/devices/UglyDucklingMk7.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,6 @@ #include #include -#include using namespace farmhub::kernel; using namespace farmhub::peripherals::chicken_door; diff --git a/main/kernel/I2CManager.hpp b/main/kernel/I2CManager.hpp index 9178064c..b336cb75 100644 --- a/main/kernel/I2CManager.hpp +++ b/main/kernel/I2CManager.hpp @@ -8,14 +8,14 @@ #include #include -#include #include +#include namespace farmhub::kernel { using std::shared_ptr; -using farmhub::devices::PinPtr; +using farmhub::kernel::PinPtr; using GpioPair = std::pair; @@ -92,7 +92,7 @@ class I2CTransmission { return count; } - size_t write(const uint8_t *data, size_t quantity) { + size_t write(const uint8_t* data, size_t quantity) { Log.trace("Writing %d bytes to I2C device %s at address 0x%02x", quantity, device->name.c_str(), device->address); auto count = wire().write(data, quantity); diff --git a/main/devices/Pin.hpp b/main/kernel/Pin.hpp similarity index 95% rename from main/devices/Pin.hpp rename to main/kernel/Pin.hpp index d11d343a..86fb8198 100644 --- a/main/devices/Pin.hpp +++ b/main/kernel/Pin.hpp @@ -10,7 +10,7 @@ #include -namespace farmhub::devices { +namespace farmhub::kernel { class Pin; using PinPtr = std::shared_ptr; @@ -125,14 +125,14 @@ class InternalPin : public Pin { std::map InternalPin::INTERNAL_BY_NAME; std::map InternalPin::INTERNAL_BY_GPIO; -} // namespace farmhub::devices +} // namespace farmhub::kernel namespace ArduinoJson { -using farmhub::devices::Pin; -using farmhub::devices::PinPtr; -using farmhub::devices::InternalPin; -using farmhub::devices::InternalPinPtr; +using farmhub::kernel::InternalPin; +using farmhub::kernel::InternalPinPtr; +using farmhub::kernel::Pin; +using farmhub::kernel::PinPtr; template <> struct Converter { diff --git a/main/kernel/drivers/BatteryDriver.hpp b/main/kernel/drivers/BatteryDriver.hpp index 78d75395..a111a179 100644 --- a/main/kernel/drivers/BatteryDriver.hpp +++ b/main/kernel/drivers/BatteryDriver.hpp @@ -2,11 +2,11 @@ #include -#include #include +#include #include -using farmhub::devices::PinPtr; +using farmhub::kernel::PinPtr; namespace farmhub::kernel::drivers { diff --git a/main/kernel/drivers/LedDriver.hpp b/main/kernel/drivers/LedDriver.hpp index c04257ca..18c8046a 100644 --- a/main/kernel/drivers/LedDriver.hpp +++ b/main/kernel/drivers/LedDriver.hpp @@ -4,14 +4,14 @@ #include #include -#include #include #include +#include #include using namespace std::chrono; -using farmhub::devices::PinPtr; +using farmhub::kernel::PinPtr; namespace farmhub::kernel::drivers { diff --git a/main/kernel/drivers/SwitchManager.hpp b/main/kernel/drivers/SwitchManager.hpp index 98376631..55c10e0f 100644 --- a/main/kernel/drivers/SwitchManager.hpp +++ b/main/kernel/drivers/SwitchManager.hpp @@ -8,14 +8,14 @@ #include -#include #include #include +#include #include using namespace std::chrono; -using farmhub::devices::PinPtr; +using farmhub::kernel::PinPtr; namespace farmhub::kernel::drivers { diff --git a/main/peripherals/multiplexer/Xl9535.hpp b/main/peripherals/multiplexer/Xl9535.hpp index eb4ea1ac..a177f5ab 100644 --- a/main/peripherals/multiplexer/Xl9535.hpp +++ b/main/peripherals/multiplexer/Xl9535.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include