Skip to content

Commit

Permalink
Require an InternalPin for stuff where an actual GPIO is needed
Browse files Browse the repository at this point in the history
  • Loading branch information
lptr committed Oct 26, 2024
1 parent 69a55d6 commit 8cb76ac
Show file tree
Hide file tree
Showing 23 changed files with 265 additions and 203 deletions.
4 changes: 2 additions & 2 deletions main/devices/DeviceDefinition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class DeviceConfiguration : public ConfigurationSection {
template <typename TDeviceConfiguration>
class DeviceDefinition {
public:
DeviceDefinition(PinPtr statusPin, PinPtr bootPin)
DeviceDefinition(PinPtr statusPin, InternalPinPtr bootPin)
: statusLed("status", statusPin)
, bootPin(bootPin) {
}
Expand Down Expand Up @@ -99,7 +99,7 @@ class DeviceDefinition {
LedDriver statusLed;
PcntManager pcnt;
PwmManager pwm;
const PinPtr bootPin;
const InternalPinPtr bootPin;

private:
ConfigurationFile<TDeviceConfiguration> configFile { FileSystem::get(), "/device-config.json" };
Expand Down
120 changes: 91 additions & 29 deletions main/devices/Pin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,11 @@ namespace farmhub::devices {
class Pin;
using PinPtr = std::shared_ptr<Pin>;

class InternalPin;
using InternalPinPtr = std::shared_ptr<InternalPin>;

class Pin {
public:
static PinPtr registerPin(const String& name, gpio_num_t gpio) {
auto pin = std::make_shared<Pin>(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()) {
Expand All @@ -32,70 +28,111 @@ 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<String, PinPtr> BY_NAME;
};

std::map<String, PinPtr> Pin::BY_NAME;

class InternalPin : public Pin {
public:
static InternalPinPtr registerPin(const String& name, gpio_num_t gpio) {
auto pin = std::make_shared<InternalPin>(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 {
return it->second;
}
}

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<gpio_num_t, PinPtr> BY_GPIO;
static std::map<String, PinPtr> BY_NAME;
static std::map<String, InternalPinPtr> INTERNAL_BY_NAME;
static std::map<gpio_num_t, InternalPinPtr> INTERNAL_BY_GPIO;
};

std::map<gpio_num_t, PinPtr> Pin::BY_GPIO;
std::map<String, PinPtr> Pin::BY_NAME;
std::map<String, InternalPinPtr> InternalPin::INTERNAL_BY_NAME;
std::map<gpio_num_t, InternalPinPtr> InternalPin::INTERNAL_BY_GPIO;

} // namespace farmhub::devices

namespace ArduinoJson {

using farmhub::devices::Pin;
using farmhub::devices::PinPtr;
using farmhub::devices::InternalPin;
using farmhub::devices::InternalPinPtr;

template <>
struct Converter<PinPtr> {
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<int>(src->getGpio()));
} else {
dst.set(src->getName());
}
Expand All @@ -105,7 +142,32 @@ struct Converter<PinPtr> {
if (src.is<const char*>()) {
return Pin::byName(src.as<const char*>());
} else {
return Pin::byGpio(static_cast<gpio_num_t>(src.as<int>()));
throw std::runtime_error(String("Invalid pin name: " + src.as<String>()).c_str());
}
}

static bool checkJson(JsonVariantConst src) {
return src.is<const char*>();
}
};

template <>
struct Converter<InternalPinPtr> {
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<int>(src->getGpio()));
} else {
dst.set(src->getName());
}
}

static InternalPinPtr fromJson(JsonVariantConst src) {
if (src.is<const char*>()) {
return InternalPin::byName(src.as<const char*>());
} else {
return InternalPin::byGpio(static_cast<gpio_num_t>(src.as<int>()));
}
}

Expand Down
38 changes: 19 additions & 19 deletions main/devices/UglyDucklingMk4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mk4Config> {
Expand Down
80 changes: 40 additions & 40 deletions main/devices/UglyDucklingMk5.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mk5Config> {
Expand Down
Loading

0 comments on commit 8cb76ac

Please sign in to comment.