From d77fe461107ae09ae5bd763d70e124bec5b2fe51 Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Wed, 29 Oct 2025 15:16:51 +0800 Subject: [PATCH 1/5] add module ac --- src/modules/M5StamPLC_AC.cpp | 96 +++++++++++++++++++++ src/modules/M5StamPLC_AC.h | 43 ++++++++++ src/utils/make_unique_compat.h | 33 ++++++++ src/utils/pi4ioe5v6408/pi4ioe5v6408.cpp | 108 ------------------------ src/utils/pi4ioe5v6408/pi4ioe5v6408.h | 38 --------- 5 files changed, 172 insertions(+), 146 deletions(-) create mode 100644 src/modules/M5StamPLC_AC.cpp create mode 100644 src/modules/M5StamPLC_AC.h create mode 100644 src/utils/make_unique_compat.h delete mode 100644 src/utils/pi4ioe5v6408/pi4ioe5v6408.cpp delete mode 100644 src/utils/pi4ioe5v6408/pi4ioe5v6408.h diff --git a/src/modules/M5StamPLC_AC.cpp b/src/modules/M5StamPLC_AC.cpp new file mode 100644 index 0000000..c6c5c0f --- /dev/null +++ b/src/modules/M5StamPLC_AC.cpp @@ -0,0 +1,96 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include "M5StamPLC_AC.h" +#include "utils/make_unique_compat.h" +#include +#include + +static const char* _tag = "M5StamPLC_AC"; + +static const uint8_t _ioe_address = 0x44; +static const uint8_t _pin_ac_relay = 2; +static const uint8_t _pin_status_light_r = 5; +static const uint8_t _pin_status_light_g = 6; +static const uint8_t _pin_status_light_b = 7; + +bool M5StamPLC_AC::begin() +{ + if (_ioe) { + ESP_LOGW(_tag, "IOExpander already initialized"); + return true; + } + + _ioe = std::make_unique(_ioe_address); + if (!_ioe->begin()) { + ESP_LOGE(_tag, "IOExpander initialization failed"); + return false; + } + + // AC relay + _ioe->setDirection(_pin_ac_relay, true); + _ioe->setPullMode(_pin_ac_relay, false); + _ioe->setHighImpedance(_pin_ac_relay, false); + + // Status light + auto setup_status_light_pin = [](m5::PI4IOE5V6408_Class* ioe, uint8_t pin) { + ioe->setDirection(pin, true); + ioe->setPullMode(pin, true); + ioe->setHighImpedance(pin, false); + ioe->digitalWrite(pin, true); + }; + setup_status_light_pin(_ioe.get(), _pin_status_light_r); + setup_status_light_pin(_ioe.get(), _pin_status_light_g); + setup_status_light_pin(_ioe.get(), _pin_status_light_b); + + return true; +} + +bool M5StamPLC_AC::readAcRelay() +{ + if (!is_ioe_valid()) { + return false; + } + + return _ioe->digitalRead(_pin_ac_relay); +} + +void M5StamPLC_AC::writeAcRelay(const bool& state) +{ + if (!is_ioe_valid()) { + return; + } + + _ioe->digitalWrite(_pin_ac_relay, state); +} + +void M5StamPLC_AC::setStatusLight(const uint8_t& r, const uint8_t& g, const uint8_t& b) +{ + if (!is_ioe_valid()) { + return; + } + + auto set_channel = [](m5::PI4IOE5V6408_Class* ioe, uint8_t pin, uint8_t value) { + if (value == 0) { + ioe->setHighImpedance(pin, true); + } else { + ioe->setHighImpedance(pin, false); + ioe->digitalWrite(pin, false); + } + }; + + set_channel(_ioe.get(), _pin_status_light_r, r); + set_channel(_ioe.get(), _pin_status_light_g, g); + set_channel(_ioe.get(), _pin_status_light_b, b); +} + +bool M5StamPLC_AC::is_ioe_valid() +{ + if (!_ioe) { + ESP_LOGE(_tag, "IOExpander not initialized"); + return false; + } + return true; +} diff --git a/src/modules/M5StamPLC_AC.h b/src/modules/M5StamPLC_AC.h new file mode 100644 index 0000000..1af7678 --- /dev/null +++ b/src/modules/M5StamPLC_AC.h @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include +#include +#include +#include + +class M5StamPLC_AC { +public: + bool begin(); + + /** + * @brief Read AC Relay state + * + * @return true if ON, false if OFF + */ + bool readAcRelay(); + + /** + * @brief Write AC Relay state + * + * @param state true if ON, false if OFF + */ + void writeAcRelay(const bool& state); + + /** + * @brief Set Status Light + * + * @param r + * @param g + * @param b + */ + void setStatusLight(const uint8_t& r, const uint8_t& g, const uint8_t& b); + +protected: + std::unique_ptr _ioe; + + bool is_ioe_valid(); +}; diff --git a/src/utils/make_unique_compat.h b/src/utils/make_unique_compat.h new file mode 100644 index 0000000..aefe4fe --- /dev/null +++ b/src/utils/make_unique_compat.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include +#include +#include +#include + +#if __cplusplus < 201402L +namespace std { + +template +typename std::enable_if::value, std::unique_ptr>::type make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +template +typename std::enable_if::value && std::extent::value == 0, std::unique_ptr>::type make_unique( + std::size_t n) +{ + using U = typename std::remove_extent::type; + return std::unique_ptr(new U[n]()); +} + +template +typename std::enable_if<(std::extent::value != 0), void>::type make_unique(Args&&...) = delete; + +} // namespace std +#endif diff --git a/src/utils/pi4ioe5v6408/pi4ioe5v6408.cpp b/src/utils/pi4ioe5v6408/pi4ioe5v6408.cpp deleted file mode 100644 index a2cfb0e..0000000 --- a/src/utils/pi4ioe5v6408/pi4ioe5v6408.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD - * - * SPDX-License-Identifier: MIT - */ -#include "pi4ioe5v6408.h" - -bool PI4IOE5V6408_Class::begin() -{ - auto id = readRegister8(0x01); - // printf("id: %d\n", id); - if (id == 0) { - return false; - } - return true; -} - -// false input, true output -void PI4IOE5V6408_Class::setDirection(uint8_t pin, bool direction) -{ - // Input, set 0 - if (!direction) { - auto data = readRegister8(0x03); - data &= ~(1 << pin); - writeRegister8(0x03, data); - } - // Output, set 1 - else { - auto data = readRegister8(0x03); - data |= (1 << pin); - writeRegister8(0x03, data); - } -} - -void PI4IOE5V6408_Class::enablePull(uint8_t pin, bool enablePull) -{ - if (enablePull) { - auto data = readRegister8(0x0B); - data |= (1 << pin); - writeRegister8(0x0B, data); - } else { - auto data = readRegister8(0x0B); - data &= ~(1 << pin); - writeRegister8(0x0B, data); - } -} - -// false down, true up -void PI4IOE5V6408_Class::setPullMode(uint8_t pin, bool mode) -{ - if (mode) { - auto data = readRegister8(0x0D); - data |= (1 << pin); - writeRegister8(0x0D, data); - } else { - auto data = readRegister8(0x0D); - data &= ~(1 << pin); - writeRegister8(0x0D, data); - } -} - -void PI4IOE5V6408_Class::setHighImpedance(uint8_t pin, bool enable) -{ - auto data = readRegister8(0x07); - - if (enable) { - data |= (1 << pin); - } else { - data &= ~(1 << pin); - } - - writeRegister8(0x07, data); -} - -void PI4IOE5V6408_Class::digitalWrite(uint8_t pin, bool level) -{ - auto data = readRegister8(0x05); - // spdlog::info("data: {}", data); - - if (level) { - data |= (1 << pin); - } else { - data &= ~(1 << pin); - } - - writeRegister8(0x05, data); -} - -bool PI4IOE5V6408_Class::digitalRead(uint8_t pin) -{ - auto data = readRegister8(0x0F); - return (data & (1 << pin)) != 0; -} - -void PI4IOE5V6408_Class::resetIrq() -{ - readRegister8(0x13); -} - -void PI4IOE5V6408_Class::disableIrq() -{ - writeRegister8(0x11, 0B11111111); -} - -void PI4IOE5V6408_Class::enableIrq() -{ - writeRegister8(0x11, 0x0); -} diff --git a/src/utils/pi4ioe5v6408/pi4ioe5v6408.h b/src/utils/pi4ioe5v6408/pi4ioe5v6408.h deleted file mode 100644 index ba37853..0000000 --- a/src/utils/pi4ioe5v6408/pi4ioe5v6408.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD - * - * SPDX-License-Identifier: MIT - */ -#pragma once -#include - -// https://www.diodes.com/assets/Datasheets/PI4IOE5V6408.pdf -class PI4IOE5V6408_Class : public m5::I2C_Device { -public: - PI4IOE5V6408_Class(std::uint8_t i2c_addr = 0x43, std::uint32_t freq = 400000, m5::I2C_Class* i2c = &m5::In_I2C) - : I2C_Device(i2c_addr, freq, i2c) - { - } - - bool begin(); - - // false input, true output - void setDirection(uint8_t pin, bool direction); - - void enablePull(uint8_t pin, bool enablePull); - - // false down, true up - void setPullMode(uint8_t pin, bool mode); - - void setHighImpedance(uint8_t pin, bool enable); - - void digitalWrite(uint8_t pin, bool level); - - bool digitalRead(uint8_t pin); - - void resetIrq(); - - void disableIrq(); - - void enableIrq(); -}; From 40e95e95fa9f0890e42242e4c012cb420d066226 Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Wed, 29 Oct 2025 15:48:47 +0800 Subject: [PATCH 2/5] add module ac examples --- examples/Modules/StamPLC_AC/Relay/Relay.ino | 33 +++++++++++++ .../StamPLC_AC/StatusLight/StatusLight.ino | 49 +++++++++++++++++++ src/M5StamPLC.h | 1 + src/modules/M5StamPLC_AC.cpp | 19 +++---- src/modules/M5StamPLC_AC.h | 6 +-- 5 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 examples/Modules/StamPLC_AC/Relay/Relay.ino create mode 100644 examples/Modules/StamPLC_AC/StatusLight/StatusLight.ino diff --git a/examples/Modules/StamPLC_AC/Relay/Relay.ino b/examples/Modules/StamPLC_AC/Relay/Relay.ino new file mode 100644 index 0000000..8de2885 --- /dev/null +++ b/examples/Modules/StamPLC_AC/Relay/Relay.ino @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include +#include + +M5StamPLC_AC stamplc_ac; + +void setup() +{ + /* Init M5StamPLC */ + M5StamPLC.begin(); + + /* Init M5StamPLC-AC */ + while (!stamplc_ac.begin()) { + printf("M5StamPLC-AC init failed, retry in 1s...\n"); + delay(1000); + } +} + +void loop() +{ + static bool relay_state = false; + + /* Toggle M5StamPLC-AC relay state */ + relay_state = !relay_state; + stamplc_ac.writeRelay(relay_state); + printf("Write M5StamPLC-AC Relay to %s\n", stamplc_ac.readRelay() ? "ON" : "OFF"); + + delay(1000); +} diff --git a/examples/Modules/StamPLC_AC/StatusLight/StatusLight.ino b/examples/Modules/StamPLC_AC/StatusLight/StatusLight.ino new file mode 100644 index 0000000..7ffce42 --- /dev/null +++ b/examples/Modules/StamPLC_AC/StatusLight/StatusLight.ino @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include +#include + +M5StamPLC_AC stamplc_ac; + +void setup() +{ + /* Init M5StamPLC */ + M5StamPLC.begin(); + + /* Init M5StamPLC-AC */ + while (!stamplc_ac.begin()) { + printf("M5StamPLC-AC init failed, retry in 1s...\n"); + delay(1000); + } +} + +void loop() +{ + /* Set status light to red */ + stamplc_ac.setStatusLight(1, 0, 0); + printf("Set M5StamPLC-AC status light to red\n"); + delay(1000); + + /* Set status light to green */ + stamplc_ac.setStatusLight(0, 1, 0); + printf("Set M5StamPLC-AC status light to green\n"); + delay(1000); + + /* Set status light to blue */ + stamplc_ac.setStatusLight(0, 0, 1); + printf("Set M5StamPLC-AC status light to blue\n"); + delay(1000); + + /* Set status light to white */ + stamplc_ac.setStatusLight(1, 1, 1); + printf("Set M5StamPLC-AC status light to white\n"); + delay(1000); + + /* Set status light to black */ + stamplc_ac.setStatusLight(0, 0, 0); + printf("Set M5StamPLC-AC status light to black\n"); + delay(1000); +} diff --git a/src/M5StamPLC.h b/src/M5StamPLC.h index d743d9d..7ad30c9 100644 --- a/src/M5StamPLC.h +++ b/src/M5StamPLC.h @@ -8,6 +8,7 @@ #include "utils/aw9523/aw9523.h" #include "utils/lm75b/lm75b.h" #include "utils/rx8130/rx8130.h" +#include "modules/M5StamPLC_AC.h" #include #include #include diff --git a/src/modules/M5StamPLC_AC.cpp b/src/modules/M5StamPLC_AC.cpp index c6c5c0f..e415a20 100644 --- a/src/modules/M5StamPLC_AC.cpp +++ b/src/modules/M5StamPLC_AC.cpp @@ -11,7 +11,7 @@ static const char* _tag = "M5StamPLC_AC"; static const uint8_t _ioe_address = 0x44; -static const uint8_t _pin_ac_relay = 2; +static const uint8_t _pin_relay = 2; static const uint8_t _pin_status_light_r = 5; static const uint8_t _pin_status_light_g = 6; static const uint8_t _pin_status_light_b = 7; @@ -23,16 +23,17 @@ bool M5StamPLC_AC::begin() return true; } - _ioe = std::make_unique(_ioe_address); + _ioe = std::make_unique(_ioe_address, 400000, &m5::In_I2C); if (!_ioe->begin()) { + _ioe.reset(); ESP_LOGE(_tag, "IOExpander initialization failed"); return false; } // AC relay - _ioe->setDirection(_pin_ac_relay, true); - _ioe->setPullMode(_pin_ac_relay, false); - _ioe->setHighImpedance(_pin_ac_relay, false); + _ioe->setDirection(_pin_relay, true); + _ioe->setPullMode(_pin_relay, false); + _ioe->setHighImpedance(_pin_relay, false); // Status light auto setup_status_light_pin = [](m5::PI4IOE5V6408_Class* ioe, uint8_t pin) { @@ -48,22 +49,22 @@ bool M5StamPLC_AC::begin() return true; } -bool M5StamPLC_AC::readAcRelay() +bool M5StamPLC_AC::readRelay() { if (!is_ioe_valid()) { return false; } - return _ioe->digitalRead(_pin_ac_relay); + return _ioe->digitalRead(_pin_relay); } -void M5StamPLC_AC::writeAcRelay(const bool& state) +void M5StamPLC_AC::writeRelay(const bool& state) { if (!is_ioe_valid()) { return; } - _ioe->digitalWrite(_pin_ac_relay, state); + _ioe->digitalWrite(_pin_relay, state); } void M5StamPLC_AC::setStatusLight(const uint8_t& r, const uint8_t& g, const uint8_t& b) diff --git a/src/modules/M5StamPLC_AC.h b/src/modules/M5StamPLC_AC.h index 1af7678..51eb738 100644 --- a/src/modules/M5StamPLC_AC.h +++ b/src/modules/M5StamPLC_AC.h @@ -14,18 +14,18 @@ class M5StamPLC_AC { bool begin(); /** - * @brief Read AC Relay state + * @brief Read Relay state * * @return true if ON, false if OFF */ - bool readAcRelay(); + bool readRelay(); /** * @brief Write AC Relay state * * @param state true if ON, false if OFF */ - void writeAcRelay(const bool& state); + void writeRelay(const bool& state); /** * @brief Set Status Light From 0567e45d8ca94f42092c85ffda38b254494d1885 Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Wed, 29 Oct 2025 15:53:11 +0800 Subject: [PATCH 3/5] bump version --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 0beb511..8c51e55 100644 --- a/library.json +++ b/library.json @@ -13,7 +13,7 @@ "M5Unified": "*", "M5GFX": "*" }, - "version": "1.1.0", + "version": "1.2.0", "frameworks": "arduino", "platforms": "espressif32" } \ No newline at end of file diff --git a/library.properties b/library.properties index badfdc4..87c2f0f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=M5StamPLC -version=1.1.0 +version=1.2.0 author=M5Stack maintainer=M5Stack sentence=M5StamPLC is a library for M5StamPLC From ca96425950fc34da0a19e54682f0814bcbfeb63b Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Thu, 30 Oct 2025 09:24:51 +0800 Subject: [PATCH 4/5] better format --- src/modules/M5StamPLC_AC.cpp | 1 + src/modules/M5StamPLC_AC.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/modules/M5StamPLC_AC.cpp b/src/modules/M5StamPLC_AC.cpp index e415a20..2b5f141 100644 --- a/src/modules/M5StamPLC_AC.cpp +++ b/src/modules/M5StamPLC_AC.cpp @@ -42,6 +42,7 @@ bool M5StamPLC_AC::begin() ioe->setHighImpedance(pin, false); ioe->digitalWrite(pin, true); }; + setup_status_light_pin(_ioe.get(), _pin_status_light_r); setup_status_light_pin(_ioe.get(), _pin_status_light_g); setup_status_light_pin(_ioe.get(), _pin_status_light_b); diff --git a/src/modules/M5StamPLC_AC.h b/src/modules/M5StamPLC_AC.h index 51eb738..3ed7b24 100644 --- a/src/modules/M5StamPLC_AC.h +++ b/src/modules/M5StamPLC_AC.h @@ -11,6 +11,12 @@ class M5StamPLC_AC { public: + /** + * @brief Initialize M5StamPLC-AC + * + * @return true + * @return false + */ bool begin(); /** From cc3424756ce3037822528fba37b6c6f0f37e999f Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Wed, 3 Dec 2025 14:43:31 +0800 Subject: [PATCH 5/5] fix read relay --- src/modules/M5StamPLC_AC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/M5StamPLC_AC.cpp b/src/modules/M5StamPLC_AC.cpp index 2b5f141..2d70426 100644 --- a/src/modules/M5StamPLC_AC.cpp +++ b/src/modules/M5StamPLC_AC.cpp @@ -56,7 +56,7 @@ bool M5StamPLC_AC::readRelay() return false; } - return _ioe->digitalRead(_pin_relay); + return _ioe->getWriteValue(_pin_relay); } void M5StamPLC_AC::writeRelay(const bool& state)