From 5a0b02ccdfcaaba337bcb6314678db9fd8c1b752 Mon Sep 17 00:00:00 2001 From: Emmanuel Hernandez Cruz Date: Mon, 15 Sep 2025 09:19:13 -0500 Subject: [PATCH] Documentation updated --- lib/Core/README.md => README.md | 0 lib/Core/Categories/ModbusCoil.h | 23 ++---- lib/Core/Categories/ModbusFloatDecorator.h | 27 +++---- lib/Core/Categories/ModbusHreg.h | 19 ++++- lib/Core/Categories/ModbusIreg.h | 22 +++--- lib/Core/Categories/ModbusIsts.h | 21 ++--- lib/Core/Categories/ModbusLongDecorator.h | 29 ++++--- lib/Core/Categories/ModbusPoint.h | 15 ++-- lib/Core/Categories/ModbusPointDecorator.h | 22 ++++++ lib/Core/Categories/ModbusPointFactory.h | 41 +++++++--- lib/Core/Categories/ModbusScaleDecorator.h | 24 ++++-- lib/Core/Equipment/Equipment.h | 25 +++--- lib/Core/States/State.h | 44 +++++++++-- lib/Core/States/State_Fail.h | 22 ++++-- lib/Core/States/State_Running.h | 18 ++++- lib/Core/States/State_Standby.h | 19 ++++- lib/Core/Strategies/Strategy_Behavior.h | 10 +++ lib/Core/Strategies/Strategy_PID.cpp | 49 +++++++++--- lib/Core/Strategies/Strategy_PID.h | 72 +++++++++++++---- lib/Core/Strategies/Strategy_Ramp.cpp | 5 ++ lib/Core/Strategies/Strategy_Ramp.h | 12 ++- lib/Core/Strategies/Strategy_Saw.cpp | 8 ++ lib/Core/Strategies/Strategy_Saw.h | 8 ++ lib/Core/Strategies/Strategy_SingleValue.cpp | 5 ++ lib/Core/Strategies/Strategy_SingleValue.h | 34 ++++---- lib/Core/Strategies/Strategy_Square.cpp | 15 +++- lib/Core/Strategies/Strategy_Square.h | 8 ++ lib/Core/Strategies/Strategy_Totalizer.cpp | 15 ++-- lib/Core/Strategies/Strategy_Totalizer.h | 31 ++++---- lib/Core/core.h | 17 +++- platformio.ini | 2 +- src/CH_Daikin_AWV026B_RTU/State_Fail.cpp | 25 +++--- src/CH_Daikin_AWV026B_RTU/State_Running.cpp | 83 +++++--------------- src/CH_Daikin_AWV026B_RTU/State_Standby.cpp | 41 +++------- src/CH_Daikin_AWV026B_RTU/config.h | 41 ++++++++-- src/CH_Daikin_AWV026B_RTU/main.cpp | 45 ++++++----- src/CRAH_PAHHC_600_C6_TCP/State_Fail.cpp | 23 +++--- src/CRAH_PAHHC_600_C6_TCP/State_Running.cpp | 34 ++++++-- src/CRAH_PAHHC_600_C6_TCP/State_Standby.cpp | 27 +++++-- src/CRAH_PAHHC_600_C6_TCP/config.h | 42 +++++++--- src/CRAH_PAHHC_600_C6_TCP/main.cpp | 27 +++---- 41 files changed, 673 insertions(+), 377 deletions(-) rename lib/Core/README.md => README.md (100%) diff --git a/lib/Core/README.md b/README.md similarity index 100% rename from lib/Core/README.md rename to README.md diff --git a/lib/Core/Categories/ModbusCoil.h b/lib/Core/Categories/ModbusCoil.h index 9122406..bcef6e1 100644 --- a/lib/Core/Categories/ModbusCoil.h +++ b/lib/Core/Categories/ModbusCoil.h @@ -9,7 +9,6 @@ */ #ifndef ModbusCoil_h #define ModbusCoil_h - #include "ModbusPoint.h" /** @@ -37,8 +36,6 @@ public: */ void addToModbusServer() override; - - /** * @brief Sets the internal value of the coil. * @param value The new value for the coil. @@ -50,32 +47,26 @@ public: * @return The current value of the coil. */ int getValue() const override; - - }; template ModbusCoil::ModbusCoil(T* server, int address, int value, const char* description) - : ModbusPoint(server, address, value, description){ - -} + : ModbusPoint(server, address, value, description) {} /** * @brief Adds the coil to the Modbus server's register map. + * This method uses the underlying Modbus library to register a new coil + * at the specified address with its initial value. */ template void ModbusCoil::addToModbusServer(){ this->_server->addCoil(this->_address, this->_value); } - /** - * @brief Sets the internal value of the coil. - * - * If the new value is different from the current value, it updates the - * internal value and marks the point as dirty, indicating it needs to be - * written to the Modbus server. - * + * @brief Sets the value of the coil on the Modbus server. + * This method directly calls the Modbus library function to write the + * new value to the coil's address. * @param value The new value for the coil. */ template @@ -84,7 +75,7 @@ void ModbusCoil::setValue(int value){ } /** - * @brief Gets the current internal value of the coil. + * @brief Gets the current value of the coil from the Modbus server. * @return The current value. */ template diff --git a/lib/Core/Categories/ModbusFloatDecorator.h b/lib/Core/Categories/ModbusFloatDecorator.h index 25f5115..e96ac11 100644 --- a/lib/Core/Categories/ModbusFloatDecorator.h +++ b/lib/Core/Categories/ModbusFloatDecorator.h @@ -16,9 +16,9 @@ * @union cracked_float_t * @brief A union to easily convert between a 32-bit float and two 16-bit integers. * - * This union allows type-punning between a `float` and an array of two `int16_t` - * values, which simplifies splitting a float into high and low words for Modbus - * transmission. + * This union allows for type-punning between a `float` and an array of two + * `int16_t` values. This simplifies splitting a float into high and low words + * for Modbus transmission or reconstructing it from two registers. */ typedef union{ float v; /**< @brief The value as a 32-bit float. */ @@ -39,7 +39,7 @@ class ModbusFloatDecorator : public ModbusPointDecorator { public: /** * @brief Constructs a new ModbusFloatDecorator object. - * @param point A pointer to the ModbusPoint for the low-order word. + * @param point A pointer to the ModbusPoint for the low-order word (LSW). * @param highOrderPoint A pointer to the ModbusPoint for the high-order word. */ ModbusFloatDecorator(ModbusPoint* point, ModbusPoint* highOrderPoint) @@ -63,10 +63,10 @@ public: * @brief Sets the 32-bit float value by splitting it into two 16-bit words. * * This method uses a union to split the float into two 16-bit integers - * and sets the values on the two underlying Modbus points. - * @note The order of `as_int[0]` vs `as_int[1]` might need to be swapped - * depending on the endianness of the target Modbus device. + * and then writes these values to the two underlying Modbus points. * + * @note The order of `as_int[0]` (LSW) and `as_int[1]` (MSW) might need to be + * swapped depending on the endianness of the target Modbus device. * @param value The 32-bit float value to set. */ void setFloatValue(float value) { @@ -87,15 +87,16 @@ public: * @brief Gets the combined 32-bit float value from the two registers. * * This method reads the 16-bit integer values from the two underlying - * points and uses a union to reconstruct the 32-bit float value. + * Modbus points and uses a union to reconstruct the 32-bit float value. * * @return The reconstructed 32-bit float value. */ float getFloatValue() const { - cracked_float_t buffer; - // Directly read the two 16-bit words from the Modbus server - buffer.as_int[0] = this->_point->getServer()->Hreg(this->_point->getAddress()); - buffer.as_int[1] = _highOrderPoint->getServer()->Hreg(_highOrderPoint->getAddress()); + cracked_float_t buffer; + // Read the two 16-bit words from the underlying points and combine them. + // Note: This assumes a specific word order (endianness). + buffer.as_int[0] = this->_point->getValue(); + buffer.as_int[1] = _highOrderPoint->getValue(); return buffer.v; } @@ -107,8 +108,6 @@ public: _highOrderPoint->addToModbusServer(); } - - private: ModbusPoint* _highOrderPoint; /**< @brief Pointer to the ModbusPoint for the high-order word. */ }; diff --git a/lib/Core/Categories/ModbusHreg.h b/lib/Core/Categories/ModbusHreg.h index d315d03..1fff5e0 100644 --- a/lib/Core/Categories/ModbusHreg.h +++ b/lib/Core/Categories/ModbusHreg.h @@ -40,13 +40,13 @@ public: /** - * @brief Sets the internal value of the holding register. + * @brief Sets the value of the holding register on the Modbus server. * @param value The new value for the holding register. */ void setValue(int value) override; /** - * @brief Gets the current internal value of the holding register. + * @brief Gets the current value of the holding register from the Modbus server. * @return The current value of the holding register. */ int getValue() const override; @@ -58,16 +58,31 @@ template ModbusHreg::ModbusHreg(T* server, int address, int value, const char* description) : ModbusPoint(server, address, value, description) {} +/** + * @brief Adds the holding register to the Modbus server's register map. + * This method uses the underlying Modbus library to register a new holding + * register at the specified address with its initial value. + */ template void ModbusHreg::addToModbusServer() { this->_server->addHreg(this->_address, this->_value); } +/** + * @brief Sets the value of the holding register on the Modbus server. + * This method directly calls the Modbus library function to write the + * new value to the holding register's address. + * @param value The new 16-bit value for the register. + */ template void ModbusHreg::setValue(int value) { this->_server->Hreg(this->_address, value); } +/** + * @brief Gets the current value of the holding register from the Modbus server. + * @return The current 16-bit value from the register. + */ template int ModbusHreg::getValue() const { return this->_server->Hreg(this->_address); diff --git a/lib/Core/Categories/ModbusIreg.h b/lib/Core/Categories/ModbusIreg.h index 9c7def8..53578ac 100644 --- a/lib/Core/Categories/ModbusIreg.h +++ b/lib/Core/Categories/ModbusIreg.h @@ -36,14 +36,14 @@ public: * @brief Adds the input register to the Modbus server. */ void addToModbusServer() override; - + /** - * @brief Sets the internal value of the input register. + * @brief Sets the value of the input register on the Modbus server. * @param value The new value for the input register. */ void setValue(int value) override; /** - * @brief Gets the current internal value of the input register. + * @brief Gets the current value of the input register from the Modbus server. * @return The current value of the input register. */ int getValue() const override; @@ -51,20 +51,22 @@ public: template ModbusIreg::ModbusIreg(T* server, int address, int value, const char* description) - : ModbusPoint(server, address, value, description){ + : ModbusPoint(server, address, value, description){} -} /** - * @brief Sets the internal value of the input register and marks it as dirty. - * @param value The new value for the input register. + * @brief Sets the value of the input register on the Modbus server. + * This method directly calls the Modbus library function to write the + * new value to the input register's address. This is how the emulator's + * internal logic updates the value that a Modbus master can read. + * @param value The new 16-bit value for the register. */ template void ModbusIreg::setValue(int value){ this->_server->Ireg(this->_address, value); } /** - * @brief Gets the current internal value of the input register. - * @return The current value. + * @brief Gets the current value of the input register from the Modbus server. + * @return The current 16-bit value from the register. */ template int ModbusIreg::getValue() const { @@ -73,6 +75,8 @@ int ModbusIreg::getValue() const { /** * @brief Adds the input register to the Modbus server's register map. + * This method uses the underlying Modbus library to register a new input + * register at the specified address with its initial value. */ template void ModbusIreg::addToModbusServer(){ diff --git a/lib/Core/Categories/ModbusIsts.h b/lib/Core/Categories/ModbusIsts.h index 3b33dfd..13d2b5e 100644 --- a/lib/Core/Categories/ModbusIsts.h +++ b/lib/Core/Categories/ModbusIsts.h @@ -36,14 +36,14 @@ public: * @brief Adds the discrete input to the Modbus server. */ void addToModbusServer() override; - + /** - * @brief Sets the internal value of the discrete input. + * @brief Sets the value of the discrete input on the Modbus server. * @param value The new value for the discrete input. */ void setValue(int value) override; /** - * @brief Gets the current internal value of the discrete input. + * @brief Gets the current value of the discrete input from the Modbus server. * @return The current value of the discrete input. */ int getValue() const override; @@ -52,19 +52,21 @@ public: template ModbusIsts::ModbusIsts(T* server, int address, int value, const char* description) - : ModbusPoint(server, address, value, description){ + : ModbusPoint(server, address, value, description) {} -} /** - * @brief Sets the internal value of the discrete input and marks it as dirty. + * @brief Sets the value of the discrete input on the Modbus server. + * This method directly calls the Modbus library function to write the + * new value to the discrete input's address. This is how the emulator's + * internal logic updates the value that a Modbus master can read. * @param value The new value for the discrete input. */ template void ModbusIsts::setValue(int value){ this->_server->Ists(this->_address, value); } -/**ss - * @brief Gets the current internal value of the discrete input. +/** + * @brief Gets the current value of the discrete input from the Modbus server. * @return The current value. */ template @@ -73,11 +75,12 @@ int ModbusIsts::getValue() const{ } /** * @brief Adds the discrete input to the Modbus server's register map. + * This method uses the underlying Modbus library to register a new discrete + * input at the specified address with its initial value. */ template void ModbusIsts::addToModbusServer(){ this->_server->addIsts(this->_address, this->_value); } - #endif \ No newline at end of file diff --git a/lib/Core/Categories/ModbusLongDecorator.h b/lib/Core/Categories/ModbusLongDecorator.h index 4e4189a..2a5ae5e 100644 --- a/lib/Core/Categories/ModbusLongDecorator.h +++ b/lib/Core/Categories/ModbusLongDecorator.h @@ -25,9 +25,9 @@ template class ModbusLongDecorator : public ModbusPointDecorator { public: /** - * @brief Constructs a new ModbusLongDecorator object. - * @param point A pointer to the ModbusPoint for the low-order word (LSB). - * @param highOrderPoint A pointer to the ModbusPoint for the high-order word (MSB). + * @brief Constructs a new ModbusLongDecorator. + * @param point A pointer to the ModbusPoint for the low-order word (LSW). + * @param highOrderPoint A pointer to the ModbusPoint for the high-order word (MSW). */ ModbusLongDecorator(ModbusPoint* point, ModbusPoint* highOrderPoint) : ModbusPointDecorator(point), _highOrderPoint(highOrderPoint) {} @@ -61,18 +61,29 @@ public: /** * @brief Sets the 32-bit long value by splitting it into two 16-bit words. + * + * This method uses bitwise operations to extract the low word (Least + * Significant Word) and the high word (Most Significant Word) from the + * 32-bit long value. It then writes these 16-bit words to their + * respective underlying Modbus points. + * * @param value The 32-bit long value to set. */ void setLongValue(long value) { - this->_point->setValue(value & 0xFFFF); // Low Word (LSB) - _highOrderPoint->setValue((value >> 16) & 0xFFFF); // High Word (MSB) + this->_point->setValue(value & 0xFFFF); // Low Word (LSW) + _highOrderPoint->setValue((value >> 16) & 0xFFFF); // High Word (MSW) } - /** @brief Gets the combined 32-bit long value from the two registers. */ + /** + * @brief Gets the combined 32-bit long value from the two registers. + * This method reads the 16-bit values from the two underlying Modbus points + * and reconstructs the 32-bit long value using bitwise operations. + * @return The reconstructed 32-bit long value. + */ long getLongValue() const { - long lsb = this->_point->getValue(); - long msb = _highOrderPoint->getValue(); - return (msb << 16) | lsb; + long lsw = this->_point->getValue(); + long msw = _highOrderPoint->getValue(); + return (msw << 16) | lsw; } /** @brief Gets the 32-bit long value, cast to an integer. */ diff --git a/lib/Core/Categories/ModbusPoint.h b/lib/Core/Categories/ModbusPoint.h index 85adb6a..7d0f37c 100644 --- a/lib/Core/Categories/ModbusPoint.h +++ b/lib/Core/Categories/ModbusPoint.h @@ -38,7 +38,7 @@ class ModbusPoint{ public: /** * @brief Constructs a new ModbusPoint object. - * @param server Pointer to the ModbusIP server instance. + * @param server Pointer to the Modbus server instance (e.g., ModbusIP or ModbusRTU). * @param address The Modbus address of the point. * @param value The initial value of the point. * @param description A descriptive name for the point. @@ -46,12 +46,12 @@ public: ModbusPoint(T* server, int address, int value, const char* description); // --- Getters --- - /** @brief Gets a pointer to the ModbusIP server instance. */ + /** @brief Gets a pointer to the Modbus server instance. */ T* getServer() const { return _server; } /** @brief Gets the Modbus address of the point. */ int getAddress() const { return _address; } /** @brief Gets the initial value assigned to the point at creation. */ - float getInitialValue() const { return _value; } + int getInitialValue() const { return _value; } /** @brief Gets the descriptive name of the point. */ const char* getDescription() const { return _description; } @@ -59,13 +59,12 @@ public: /** @brief Returns the logical type of the point (e.g., FLOAT, LONG). */ virtual PointType getType() const { return PointType::GENERIC; } - /** @brief Pure virtual function to add the point to the Modbus server's registers. */ + /** @brief Pure virtual function to add the point to the Modbus server's register map. */ virtual void addToModbusServer() = 0; - /** @brief Pure virtual function to read the point's value from the Modbus server. */ - /** @brief Pure virtual function to set the point's internal value. */ + /** @brief Pure virtual function to set the point's value on the Modbus server. */ virtual void setValue(int value) = 0; - /** @brief Pure virtual function to get the point's internal value. */ + /** @brief Pure virtual function to get the point's value from the Modbus server. */ virtual int getValue() const = 0; // --- Dirty Flag --- @@ -85,7 +84,7 @@ public: virtual ~ModbusPoint() = default; protected: - T* _server; /**< @brief Pointer to the global ModbusIP server instance. */ + T* _server; /**< @brief Pointer to the global Modbus server instance. */ int _address; /**< @brief The Modbus address of this point. */ int _value; /**< @brief The current internal value of this point. */ char _description[35]; /**< @brief A descriptive name for this point. */ diff --git a/lib/Core/Categories/ModbusPointDecorator.h b/lib/Core/Categories/ModbusPointDecorator.h index 858fb6f..fe8d9ff 100644 --- a/lib/Core/Categories/ModbusPointDecorator.h +++ b/lib/Core/Categories/ModbusPointDecorator.h @@ -30,6 +30,9 @@ public: * Initializes the base ModbusPoint with the properties of the wrapped point * and stores a pointer to the wrapped point. * + * @note The decorator does not take ownership of the wrapped point. The + * caller is responsible for managing its lifecycle. + * * @param point A pointer to the ModbusPoint object to be decorated. */ ModbusPointDecorator(ModbusPoint* point) : ModbusPoint( @@ -38,18 +41,37 @@ public: point->getInitialValue(), point->getDescription()), _point(point) {} + + /** + * @brief Virtual destructor. + * Does not delete the wrapped `_point` as it does not own it. + */ + virtual ~ModbusPointDecorator() = default; // --- Delegated Methods --- // These methods simply forward the call to the wrapped _point object. // Concrete decorators can override them to add new behavior. + /** + * @brief Delegates the call to add the point to the Modbus server. + * Forwards the `addToModbusServer` call to the wrapped `ModbusPoint` object. + */ void addToModbusServer() override{ _point->addToModbusServer(); } + /** + * @brief Delegates the call to set the point's value. + * Forwards the `setValue` call to the wrapped `ModbusPoint` object. + */ void setValue(int value) override { _point->setValue(value); } + /** + * @brief Delegates the call to get the point's value. + * Forwards the `getValue` call to the wrapped `ModbusPoint` object. + * @return The value from the wrapped point. + */ int getValue() const override{ return _point->getValue(); } diff --git a/lib/Core/Categories/ModbusPointFactory.h b/lib/Core/Categories/ModbusPointFactory.h index 7fc1fab..9526d20 100644 --- a/lib/Core/Categories/ModbusPointFactory.h +++ b/lib/Core/Categories/ModbusPointFactory.h @@ -22,25 +22,37 @@ /** - * @brief Creates a specific ModbusPoint object based on a category code. + * @brief Creates and decorates a ModbusPoint object based on its type. * * This factory function acts as a centralized point for instantiating different - * concrete ModbusPoint classes and applying decorators. It takes a category - * code and other parameters, and returns a pointer to the appropriate object. + * concrete ModbusPoint classes and applying decorators (e.g., for scaling, + * floats, or longs). It encapsulates the logic for building both simple + * single-register points and complex multi-register points. * - * @param server Pointer to the ModbusIP server instance. + * @tparam T The type of the Modbus server object (e.g., ModbusIP, ModbusRTU). + * @param server Pointer to the Modbus server instance. * @param category An integer code representing the type of Modbus point to create - * (e.g., COIL, HR, IR_FLOAT from config.h). - * @param address The Modbus address for the point. - * @param value The initial value for the point. + * (e.g., COIL, HR, HR_FLOAT). + * @param address The starting Modbus address for the point. For multi-register + * types (float, long), this factory will also use `address + 1`. + * @param value The initial value for the point. Note: This is ignored for + * multi-register types, which are initialized to 0. * @param description A descriptive name for the point. - * @return A pointer to a newly created ModbusPoint object. The caller is - * responsible for managing the memory of this object. Returns nullptr - * if the category is not recognized. + * @return A pointer to the newly created ModbusPoint object. + * @retval ModbusPoint* A pointer to the fully constructed (and possibly + * decorated) Modbus point. The caller is responsible for + * managing the memory of this object. + * @retval nullptr If the category code is not recognized. */ template ModbusPoint* createModbusPoint(T* server, int category, int address, int value, const char* description); +/** + * @brief Implementation of the ModbusPoint factory function. + * + * This function contains the switch-case logic to determine which concrete + * ModbusPoint class to instantiate and which decorators to apply. + */ template ModbusPoint* createModbusPoint(T* server, int category, int address, int value, const char* description) { switch (category) { @@ -57,18 +69,20 @@ ModbusPoint* createModbusPoint(T* server, int category, int address, int valu return new ModbusIreg(server, address, value, description); case IR_10X: { - Serial.printf("Creating Input Register 10x: %s\n", description); + Serial.printf("Creating Scaled Input Register (10x): %s\n", description); ModbusPoint* point = new ModbusIreg(server, address, value, description); return new ModbusScaleDecorator(point); } case IR_LONG: { Serial.printf("Creating Input Register Long: %s\n", description); + // Create the low and high word registers for the 32-bit long ModbusPoint* point = new ModbusIreg(server, address, 0, description); ModbusPoint* highOrderPoint = new ModbusIreg(server, address + 1, 0, ""); return new ModbusLongDecorator(point, highOrderPoint); } case IR_FLOAT: { Serial.printf("Creating Input Register Float: %s\n", description); + // Create the low and high word registers for the 32-bit float ModbusPoint* point = new ModbusIreg(server, address, 0, description); ModbusPoint* highOrderPoint = new ModbusIreg(server, address + 1, 0, ""); return new ModbusFloatDecorator(point, highOrderPoint); @@ -78,18 +92,21 @@ ModbusPoint* createModbusPoint(T* server, int category, int address, int valu return new ModbusHreg(server, address, value, description); case HR_10x: { - Serial.printf("Creating Holding Register 10x: %s\n", description); + Serial.printf("Creating Scaled Holding Register (10x): %s\n", description); + // Create a base holding register and wrap it with the scaling decorator ModbusPoint* point = new ModbusHreg(server, address, value, description); return new ModbusScaleDecorator(point); } case HR_LONG: { Serial.printf("Creating Holding Register Long: %s\n", description); + // Create the low and high word registers for the 32-bit long ModbusPoint* point = new ModbusHreg(server, address, 0, description); ModbusPoint* highOrderPoint = new ModbusHreg(server, address + 1 , 0, ""); return new ModbusLongDecorator(point, highOrderPoint); } case HR_FLOAT: { Serial.printf("Creating Holding Register Float: %s\n", description); + // Create the low and high word registers for the 32-bit float ModbusPoint* point = new ModbusHreg(server, address, 0, description); ModbusPoint* highOrderPoint = new ModbusHreg(server, address + 1 , 0, ""); return new ModbusFloatDecorator(point, highOrderPoint); diff --git a/lib/Core/Categories/ModbusScaleDecorator.h b/lib/Core/Categories/ModbusScaleDecorator.h index 281a48b..e2336fc 100644 --- a/lib/Core/Categories/ModbusScaleDecorator.h +++ b/lib/Core/Categories/ModbusScaleDecorator.h @@ -18,29 +18,39 @@ * @brief A decorator that multiplies/divides a Modbus point's value by 10. * * This class wraps a ModbusPoint and intercepts its `getValue` and `setValue` - * calls. When setting a value, it multiplies the input by 10 before storing it. - * When getting a value, it divides the stored value by 10. + * calls to implement fixed-point arithmetic. It allows a 16-bit integer + * register to represent a value with one decimal place (e.g., storing the + * logical value 12.3 as the integer 123). + * + * - `setValue(123)` will store the integer `123` in the underlying point. + * - `getValue()` will read `123` from the underlying point and return `12`. */ template class ModbusScaleDecorator : public ModbusPointDecorator { public: /** - * @brief Constructs a new ModbusScaleDecorator object. + * @brief Constructs a new ModbusScaleDecorator. * @param point A pointer to the ModbusPoint object to be decorated. */ ModbusScaleDecorator(ModbusPoint* point) : ModbusPointDecorator(point) {} /** - * @brief Sets the value of the underlying point after scaling it up by 10. - * @param value The logical value to set (e.g., 12 for 12.0). + * @brief Sets the raw integer value on the underlying point. + * This method directly passes the provided integer value to the wrapped + * Modbus point. It is intended to be used with values that are already + * scaled (e.g., to set a logical value of 25.5, call `setValue(255)`). + * @param value The scaled integer value to store (e.g., 123 to represent 12.3). */ void setValue(int value) override { this->_point->setValue(value * 10); } /** - * @brief Gets the value from the underlying point after scaling it down by 10. - * @return The logical, scaled-down value (e.g., 12 if the stored value is 120). + * @brief Gets the integer part of the logical value. + * This method retrieves the raw integer from the underlying point and + * divides it by 10 to get the integer component of the logical value. + * @return The integer part of the logical value (e.g., returns 12 if the + * stored value is 123). */ int getValue() const override { return this->_point->getValue() / 10; diff --git a/lib/Core/Equipment/Equipment.h b/lib/Core/Equipment/Equipment.h index d310e35..13db705 100644 --- a/lib/Core/Equipment/Equipment.h +++ b/lib/Core/Equipment/Equipment.h @@ -29,13 +29,14 @@ template class ModbusPoint; * Standby, Running) by delegating actions to a concrete State object. */ template -class Equipment{ +class Equipment { public: /** * @brief Constructs a new Equipment object. * Initializes the device in the default initial state (Standby). */ Equipment(); + Equipment(T* server); /** @brief The main update loop for the equipment, called repeatedly. Delegates to the current state. */ void update(); @@ -53,14 +54,6 @@ public: * @return The integer ID of the state. */ int getState(); - /** - * @brief Reads all the points generated for the equipment from the Modbus server to the objects - */ - void readAllPoints(); - /** - * @brief Writes all the points generated for the equipment from the objects to the Modbus server - */ - void writeAllPoints(); /** * @brief Transitions the equipment to a new state. * Handles exiting the old state, deleting it, and entering the new one. @@ -82,15 +75,15 @@ public: /** * @brief Sets the value of a specific Modbus point. * @param description The string key for the Modbus point. - * @param value The value to set. + * @param value The value to set. Note: This float may be truncated or cast + * depending on the underlying point's `setValue` implementation. */ void setModbusPoint(const std::string& description, float value); private: State* _state; /**< @brief Pointer to the current state object. */ std::map*> _points;/**< @brief Map of all Modbus points, keyed by description. */ - int _stateId; /**< @brief A simple integer identifier for the current state. */ - std::vector*> _allPoints; /**< @brief Vector of all Modbus points. */ + int _stateId; /**< @brief A simple integer identifier for the current state. */ T* _server; }; @@ -100,6 +93,10 @@ Equipment::Equipment() : _server(nullptr) { this->_state->enterState(this); } +/** + * @brief Constructs a new Equipment object with a server instance. + * @param server Pointer to the Modbus server instance (e.g., ModbusIP, ModbusRTU). + */ template Equipment::Equipment(T* server) : _server(server) @@ -149,7 +146,6 @@ void Equipment::exitState() { template void Equipment::addModbusPoint(const std::string& description, ModbusPoint* point) { this->_points[description] = point; - this->_allPoints.push_back(point); } /** @@ -168,8 +164,9 @@ ModbusPoint* Equipment::getModbusPoint(const std::string& description) { /** * @brief Sets the value of a specific Modbus point. + * Finds the point by its description and calls its `setValue` method. * @param description The string key for the Modbus point. - * @param value The value to set. + * @param value The value to set. This float is cast to an int before being passed. */ template void Equipment::setModbusPoint(const std::string& description, float value) { diff --git a/lib/Core/States/State.h b/lib/Core/States/State.h index 8de12f1..7850c17 100644 --- a/lib/Core/States/State.h +++ b/lib/Core/States/State.h @@ -56,7 +56,7 @@ public: */ virtual void exitState(Equipment* equipment) {} /** - * @brief Logic to apply all strategies created. + * @brief Applies all registered strategies for the current state. * @param equipment Pointer to the Equipment instance. */ virtual void _applyStrategies(Equipment* equipment); @@ -64,14 +64,30 @@ public: protected: /** - * @brief Adds a behavior strategy for a specific Modbus point. - * @param pointDescription The description of the Modbus point to apply the strategy to. - * @param strategy A pointer to the Strategy_Behavior object. The State will take ownership. + * @brief Gets the value of a Modbus point, handling float types correctly. + * This is a helper function to safely read a value from a point, whether it's + * a standard integer register or a `ModbusFloatDecorator`. + * @param equipment Pointer to the Equipment instance. + * @param pointName The description key of the Modbus point to read. + * @return The value of the point as a float. Returns 0.0f if not found. */ float getPointValue(Equipment* equipment, const std::string& pointName); + /** + * @brief Sets the value of a Modbus point, handling float types correctly. + * This is a helper function to safely write a value to a point, whether it's + * a standard integer register or a `ModbusFloatDecorator`. + * @param equipment Pointer to the Equipment instance. + * @param pointName The description key of the Modbus point to write to. + * @param value The float value to set. It will be rounded for integer points. + */ void setPointValue(Equipment* equipment, const std::string& pointName, float value); + /** + * @brief Adds a behavior strategy for a specific Modbus point in this state. + * @param pointDescription The description of the Modbus point to apply the strategy to. + * @param strategy A pointer to the Strategy_Behavior object. The State takes ownership. + */ void addStrategy(const std::string& pointDescription, Strategy_Behavior* strategy); - std::map _strategies; + std::map _strategies; /**< @brief Map of strategies active in this state, keyed by point description. */ }; template @@ -95,6 +111,15 @@ void State::addStrategy(const std::string& pointDescription, Strategy_Behavio this->_strategies[pointDescription] = strategy; } +/** + * @brief Gets the value of a Modbus point, correctly handling float types. + * This helper function checks if the point is a `ModbusFloatDecorator` and calls + * `getFloatValue()` if it is. Otherwise, it gets the standard integer value and + * casts it to a float. + * @param equipment Pointer to the Equipment instance. + * @param pointName The description key of the Modbus point. + * @return The point's value as a float. Returns 0.0f if the point is not found. + */ template float State::getPointValue(Equipment* equipment, const std::string& pointName) { ModbusPoint* point = equipment->getModbusPoint(pointName); @@ -109,6 +134,15 @@ float State::getPointValue(Equipment* equipment, const std::string& pointN } } +/** + * @brief Sets the value of a Modbus point, correctly handling float types. + * This helper function checks if the point is a `ModbusFloatDecorator` and calls + * `setFloatValue()` if it is. Otherwise, it rounds the float to the nearest + * integer and calls the standard `setValue()`. + * @param equipment Pointer to the Equipment instance. + * @param pointName The description key of the Modbus point. + * @param value The value to set. + */ template void State::setPointValue(Equipment* equipment, const std::string& pointName, float value) { ModbusPoint* point = equipment->getModbusPoint(pointName); diff --git a/lib/Core/States/State_Fail.h b/lib/Core/States/State_Fail.h index b05e577..75befe2 100644 --- a/lib/Core/States/State_Fail.h +++ b/lib/Core/States/State_Fail.h @@ -30,21 +30,33 @@ template class FailState : public State { public: /** - * @brief Constructs a new FailState object. - * This is where strategies for failure behavior would be initialized. + * @brief Constructs a new FailState object with a list of active alarms. + * @param activeAlarms A vector of strings, where each string is the + * description of a Modbus point to be set as an active alarm. */ FailState(const std::vector& activeAlarms); /** * @brief Executes the fail state's logic for one update cycle. - * This method applies the state's strategies and checks for a state transition command. + * This method applies any failure-related strategies and checks for a + * command to clear the alarm (e.g., via a Modbus write), which would + * trigger a transition back to a safe state like Standby. * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. */ State* update(Equipment* equipment) override; - /** @brief Logic to execute once when entering the fail state. */ + /** + * @brief Logic to execute once when entering the fail state. + * Typically sets alarm bits and brings the equipment to a safe, non-operational condition. + */ void enterState(Equipment* equipment) override; - /** @brief Logic to execute once when exiting the fail state. */ + /** + * @brief Logic to execute once when exiting the fail state. + * Typically clears alarm bits before transitioning to the next state. + */ void exitState(Equipment* equipment) override; + +private: + std::vector _activeAlarms; /**< @brief Stores the descriptions of points to be set as active alarms. */ }; #endif \ No newline at end of file diff --git a/lib/Core/States/State_Running.h b/lib/Core/States/State_Running.h index 438801f..6bf0ccf 100644 --- a/lib/Core/States/State_Running.h +++ b/lib/Core/States/State_Running.h @@ -34,14 +34,26 @@ public: /** * @brief Executes the running state's logic for one update cycle. - * This method applies the state's strategies and checks for a state transition command. + * This method applies all active strategies (e.g., for fan speeds, temperatures) + * and checks for conditions that would trigger a state transition, such as a + * command to stop or a fault condition. * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. */ State* update(Equipment* equipment) override; - /** @brief Logic to execute once when entering the running state. */ + /** + * @brief Logic to execute once when entering the running state. + * Typically sets status bits to indicate the equipment is active (e.g., + * setting an "On/Off" point to 1). + * @param equipment Pointer to the Equipment instance. + */ void enterState(Equipment* equipment) override; - /** @brief Logic to execute once when exiting the running state. */ + /** + * @brief Logic to execute once when exiting the running state. + * Typically resets status bits to indicate the equipment is no longer + * active before transitioning to the next state. + * @param equipment Pointer to the Equipment instance. + */ void exitState(Equipment* equipment) override; }; #endif \ No newline at end of file diff --git a/lib/Core/States/State_Standby.h b/lib/Core/States/State_Standby.h index 979b28b..6bcabd6 100644 --- a/lib/Core/States/State_Standby.h +++ b/lib/Core/States/State_Standby.h @@ -35,14 +35,27 @@ public: /** * @brief Executes the standby state's logic for one update cycle. - * This method applies the state's strategies and checks for a state transition command. + * This method applies any standby-specific strategies and checks for conditions + * that would trigger a state transition, such as a "start" command received + * via a Modbus write. * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. */ State* update(Equipment* equipment) override; - /** @brief Logic to execute once when entering the standby state. */ + /** + * @brief Logic to execute once when entering the standby state. + * Typically sets status bits to indicate the equipment is idle (e.g., + * setting an "On/Off" point to 0). + * @param equipment Pointer to the Equipment instance. + */ void enterState(Equipment* equipment) override; - /** @brief Logic to execute once when exiting the standby state. */ + /** + * @brief Logic to execute once when exiting the standby state. + * This method is called just before transitioning to a new state. It can be + * used to perform any cleanup specific to the standby state before the new + * state's `enterState` is called. + * @param equipment Pointer to the Equipment instance. + */ void exitState(Equipment* equipment) override; }; #endif \ No newline at end of file diff --git a/lib/Core/Strategies/Strategy_Behavior.h b/lib/Core/Strategies/Strategy_Behavior.h index 3549f3c..8a50ac8 100644 --- a/lib/Core/Strategies/Strategy_Behavior.h +++ b/lib/Core/Strategies/Strategy_Behavior.h @@ -31,6 +31,7 @@ public: /** * @brief Virtual destructor. + * Ensures that derived strategy objects are properly destroyed. */ virtual ~Strategy_Behavior() = default; @@ -44,6 +45,9 @@ public: /** * @brief Checks if the strategy's update interval has elapsed. + * This method manages the execution frequency of the strategy. It should be + * called in each update loop to determine if it's time to execute the + * strategy's logic again. * @param currentMillis The current time from `millis()`. * @return True if the strategy should be executed, false otherwise. */ @@ -55,6 +59,12 @@ public: return false; } + /** + * @brief Identifies if the strategy is a PID controller. + * This virtual method provides a way to check for a specific strategy type + * without using `dynamic_cast`. It is overridden by `PIDStrategy` to return true. + * @return `false` for all non-PID strategies, `true` for PID strategies. + */ virtual bool isPID() const { return false; } protected: diff --git a/lib/Core/Strategies/Strategy_PID.cpp b/lib/Core/Strategies/Strategy_PID.cpp index 37dd2cd..7b65ced 100644 --- a/lib/Core/Strategies/Strategy_PID.cpp +++ b/lib/Core/Strategies/Strategy_PID.cpp @@ -7,8 +7,15 @@ #include "Strategy_PID.h" #include -// CORRECTED CONSTRUCTOR -// You should pass in your gains here, but for now we'll add setters and initialize to 0. +/** + * @brief Constructs a new PIDStrategy object. + * Initializes the PID controller with default gains and stores the names of the + * Modbus points used for the setpoint and the process variable input. + * @param setpointName The description key for the Modbus point that holds the setpoint value. + * @param interval The update interval in milliseconds, passed to the base class. + * @param inputSensorName The description key for the Modbus point that provides the + * process variable (the input to the PID controller). + */ PIDStrategy::PIDStrategy(const std::string& setpointName, unsigned long interval, const std::string& inputSensorName) : Strategy_Behavior(interval), _setpointName(setpointName), _inputSensorName(inputSensorName) { @@ -21,23 +28,47 @@ PIDStrategy::PIDStrategy(const std::string& setpointName, unsigned long interval _lastTime = millis(); } -// It's good practice to have methods to set your gains +/** + * @brief Sets the gains for the PID controller. + * @param kp The proportional gain (P). Determines the reaction to the current error. + * @param ki The integral gain (I). Determines the reaction based on the sum of recent errors. + * @param kd The derivative gain (D). Determines the reaction based on the rate at which the error has been changing. + */ void PIDStrategy::setGains(float kp, float ki, float kd) { _kp = kp; _ki = ki; _kd = kd; } +/** + * @brief Updates the target setpoint for the PID controller. + * This value is typically read from a Modbus register in the `_applyStrategies` loop. + * @param setpoint The new target value for the process variable. + */ void PIDStrategy::setSetpoint(float setpoint) { _setpoint = setpoint; } -// This function is less necessary if execute() takes the current value, but can be used for setting an initial state. +/** + * @brief Manually sets the process variable (input) value. + * @note This is typically not needed as the `execute` method receives the current + * input value on each call from the `_applyStrategies` loop. + * @param input The new process variable value. + */ void PIDStrategy::setInput(float input) { _input = input; } - +/** + * @brief Executes one cycle of the PID control algorithm. + * + * This method calculates the error between the setpoint and the current input, + * computes the proportional, integral (with anti-windup), and derivative terms, + * and returns a new control output value. The final output is clamped between 0.0 and 100.0. + * + * @param currentValue The current process variable (e.g., temperature) read from the input sensor. + * @return The calculated control output (e.g., fan speed), clamped between 0.0 and 100.0. + */ float PIDStrategy::execute(float currentValue) { unsigned long now = millis(); float timeChange = (float)(now - _lastTime); @@ -60,14 +91,6 @@ float PIDStrategy::execute(float currentValue) { if (output > 100.0) output = 100.0; if (output < 0.0) output = 0.0; - Serial.printf("PID timeChange: %f.\n", timeChange); - Serial.printf("PID _input: %f.\n", _input); - Serial.printf("PID error: %f.\n", error); - Serial.printf("PID _integral: %f.\n", _integral); - Serial.printf("PID derivative: %f.\n", derivative); - Serial.printf("PID _kp: %f.\n", _kp); - Serial.printf("PID _ki: %f.\n", _ki); - Serial.printf("PID _kd: %f.\n", _kd); Serial.printf("PID output: %f.\n", output); return output; } \ No newline at end of file diff --git a/lib/Core/Strategies/Strategy_PID.h b/lib/Core/Strategies/Strategy_PID.h index 5a0546c..b8d08aa 100644 --- a/lib/Core/Strategies/Strategy_PID.h +++ b/lib/Core/Strategies/Strategy_PID.h @@ -1,4 +1,13 @@ -// In BaseEmulator/Strategies/Strategy_PID.h +/** + * @file Strategy_PID.h + * @brief Defines the PIDStrategy class for PID control logic. + * @author Emmanuel Hernandez Cruz + * @date 2025-09-06 + * + * This file contains the definition for a behavior strategy that implements a + * Proportional-Integral-Derivative (PID) controller. It's used to control a + * process variable by adjusting an output based on a setpoint. + */ #ifndef PID_Strategy_h #define PID_Strategy_h @@ -6,38 +15,69 @@ #include "Strategy_Behavior.h" #include +/** + * @class PIDStrategy + * @brief A strategy that implements a PID (Proportional-Integral-Derivative) controller. + * + * This class inherits from Strategy_Behavior and provides the logic for a PID + * controller. It calculates an output value designed to drive a process variable + * (read from an input sensor) towards a desired setpoint. The setpoint itself + * is also read from a Modbus point. + */ class PIDStrategy : public Strategy_Behavior { public: - // MODIFIED CONSTRUCTOR: Takes the setpoint, interval, and the name of the input sensor. + /** + * @brief Constructs a new PIDStrategy object. + * @param setpointName The description key for the Modbus point that holds the setpoint value. + * @param interval The update interval in milliseconds for the PID calculation. + * @param inputSensorName The description key for the Modbus point that provides the + * process variable (the input to the PID controller). + */ PIDStrategy(const std::string& setpointName, unsigned long interval, const std::string& inputSensorName); + /** + * @brief Executes one cycle of the PID control algorithm. + * @param currentValue The current process variable (e.g., temperature) read from the input sensor. + * @return The calculated control output (e.g., fan speed), clamped between 0.0 and 100.0. + */ float execute(float currentValue) override; - // Add a getter for the sensor name + /** + * @brief Gets the name of the Modbus point used as the process variable input. + * @return The description key of the input sensor point. + */ std::string getInputSensorName() const { return _inputSensorName; } + /** + * @brief Gets the name of the Modbus point used as the setpoint. + * @return The description key of the setpoint point. + */ std::string getSetpointName() const { return _setpointName; } - // Add this virtual function to easily identify this strategy as a PID + /** + * @brief Identifies this strategy as a PID controller. + * @return Always returns `true`. + */ bool isPID() const override { return true; } - // ... (other methods like setSetpoint, setGains) + /** @brief Updates the target setpoint for the PID controller. */ void setSetpoint(float setpoint); + /** @brief Sets the gains for the PID controller (Proportional, Integral, Derivative). */ void setGains(float kp, float ki, float kd); + /** @brief Manually sets the process variable (input) value. */ void setInput(float input); private: - // ... (PID variables like _kp, _ki, _kd, etc.) - float _kp; - float _ki; - float _kd; - unsigned long _lastTime; - float _setpoint; - float _input; - float _lastError; - float _integral; - std::string _inputSensorName; // <-- Add this to store the name of our input - std::string _setpointName; // <-- Add this to store the name of our input + float _kp; /**< @brief Proportional gain. */ + float _ki; /**< @brief Integral gain. */ + float _kd; /**< @brief Derivative gain. */ + unsigned long _lastTime; /**< @brief Timestamp of the last calculation. */ + float _setpoint; /**< @brief The target value for the process variable. */ + float _input; /**< @brief The current value of the process variable. */ + float _lastError; /**< @brief The error from the previous calculation. */ + float _integral; /**< @brief The accumulated integral term. */ + std::string _inputSensorName; /**< @brief The description key for the input sensor point. */ + std::string _setpointName; /**< @brief The description key for the setpoint point. */ }; #endif \ No newline at end of file diff --git a/lib/Core/Strategies/Strategy_Ramp.cpp b/lib/Core/Strategies/Strategy_Ramp.cpp index 5c93f40..273a84b 100644 --- a/lib/Core/Strategies/Strategy_Ramp.cpp +++ b/lib/Core/Strategies/Strategy_Ramp.cpp @@ -46,6 +46,11 @@ float RampStrategy::execute(float currentValue) { } +/** + * @brief Sets a new target value for the ramp. + * This allows the ramp's destination to be changed dynamically at runtime. + * @param targetValue The new target value for the ramp. + */ void RampStrategy::setTarget(float targetValue) { _targetValue = targetValue; } \ No newline at end of file diff --git a/lib/Core/Strategies/Strategy_Ramp.h b/lib/Core/Strategies/Strategy_Ramp.h index 768c050..0968547 100644 --- a/lib/Core/Strategies/Strategy_Ramp.h +++ b/lib/Core/Strategies/Strategy_Ramp.h @@ -30,12 +30,18 @@ public: */ RampStrategy(float targetValue, float step, unsigned long interval); /** - * @brief Executes the strategy to set the target setpoint in the ramp strategy. - * @param targetValue The target value that is going to be set. + * @brief Sets a new target value for the ramp. + * This allows the ramp's destination to be changed dynamically at runtime. + * @param targetValue The new target value for the ramp. */ void setTarget(float targetValue); /** - * @brief Executes the strategy to get the next value in the ramp sequence. + * @brief Calculates the next value in the ramp sequence towards a target. + * + * This method compares the current value to the target value and returns + * the current value incremented or decremented by the step amount. To prevent + * overshooting, if the next step would pass the target, it returns the target + * value directly. * @param currentValue The current value, used to determine the next step. * @return The next value in the ramp sequence. */ diff --git a/lib/Core/Strategies/Strategy_Saw.cpp b/lib/Core/Strategies/Strategy_Saw.cpp index fa9eed5..b03a5e0 100644 --- a/lib/Core/Strategies/Strategy_Saw.cpp +++ b/lib/Core/Strategies/Strategy_Saw.cpp @@ -20,10 +20,18 @@ SawStrategy::SawStrategy(float minValue, float maxValue, float step, unsigned long interval) : Strategy_Behavior(interval), _minValue(minValue), _maxValue(maxValue), _step(step) {} +/** + * @brief Sets a new minimum value for the sawtooth wave. + * @param minValue The new lower bound for the wave. + */ void SawStrategy::setMinValue(float minValue) { _minValue = minValue; } +/** + * @brief Sets a new maximum value for the sawtooth wave. + * @param maxValue The new upper bound for the wave. + */ void SawStrategy::setMaxValue(float maxValue) { _maxValue = maxValue; } diff --git a/lib/Core/Strategies/Strategy_Saw.h b/lib/Core/Strategies/Strategy_Saw.h index e0f0a76..abd8a95 100644 --- a/lib/Core/Strategies/Strategy_Saw.h +++ b/lib/Core/Strategies/Strategy_Saw.h @@ -39,8 +39,16 @@ public: */ float execute(float currentValue) override; + /** + * @brief Sets a new minimum value for the sawtooth wave. + * @param minValue The new lower bound for the wave. + */ void setMinValue(float minValue); + /** + * @brief Sets a new maximum value for the sawtooth wave. + * @param maxValue The new upper bound for the wave. + */ void setMaxValue(float maxValue); diff --git a/lib/Core/Strategies/Strategy_SingleValue.cpp b/lib/Core/Strategies/Strategy_SingleValue.cpp index 29e2f0c..7ae4eab 100644 --- a/lib/Core/Strategies/Strategy_SingleValue.cpp +++ b/lib/Core/Strategies/Strategy_SingleValue.cpp @@ -19,6 +19,11 @@ SingleValueStrategy::SingleValueStrategy(float setpoint, float noiseMagnitude, unsigned long interval) : Strategy_Behavior(interval), _setpoint(setpoint), _noiseMagnitude(noiseMagnitude) {} + +/** + * @brief Sets a setpoint value for the single value strategy. + * @param setpoint The new setpoint target for the single value strategy. + */ void SingleValueStrategy::setSetpoint(float setpoint) { _setpoint = setpoint; } diff --git a/lib/Core/Strategies/Strategy_SingleValue.h b/lib/Core/Strategies/Strategy_SingleValue.h index 3d9624e..ab074c4 100644 --- a/lib/Core/Strategies/Strategy_SingleValue.h +++ b/lib/Core/Strategies/Strategy_SingleValue.h @@ -1,11 +1,11 @@ /** * @file Strategy_SingleValue.h - * @brief Defines the SingleValueStrategy class for setup a value with noise. + * @brief Defines the SingleValueStrategy class for generating a value with random noise. * @author Emmanuel Hernandez Cruz * @date 2025-09-05 * - * This file contains the definition for a behavior strategy that sets the - * value to a setpoint and the generates simulates noise with a random number. + * This file contains the definition for a behavior strategy that maintains a + * value around a given setpoint by adding random noise. */ #ifndef SingleValue_strategy_h #define SingleValue_strategy_h @@ -13,32 +13,38 @@ /** * @class SingleValueStrategy - * @brief A strategy that sets a value to a setpoint and generates noise around it. + * @brief A strategy that generates a value that fluctuates around a setpoint. * - * This class implements the Strategy_Behavior interface to produce a noise - * pattern. Each time `execute` is called, it add a random number (+/-10) to - * emulate noise around the value + * This class implements the Strategy_Behavior interface to produce a value that + * fluctuates around a central setpoint. Each time `execute` is called, it adds + * a small, random amount of noise to the setpoint value. */ class SingleValueStrategy : public Strategy_Behavior { public: /** - * @brief Constructs a new SquareStrategy object. - * @param setpoiny Target value. - * @param interval The time in milliseconds between each value toggle. + * @brief Constructs a new SingleValueStrategy object. + * @param setpoint The base value around which noise will be generated. + * @param noiseMagnitude The maximum amount of noise to add or subtract. + * @param interval The time in milliseconds between each value generation. */ SingleValueStrategy(float setpoint, float noiseMagnitude, unsigned long interval); + /** - * @brief Executes the strategy to get the next random value around setpoint. + * @brief Generates a new value by adding random noise to the setpoint. * @param currentValue The current value of the Modbus point (ignored in this strategy). - * @return The next value in the sequence, either the lower or upper bound. + * @return The setpoint with added random noise. */ float execute(float currentValue) override; + /** + * @brief Sets a setpoint value for the single value strategy. + * @param setpoint The new setpoint target for the single value strategy. + */ void setSetpoint(float setpoint); private: - float _setpoint; - float _noiseMagnitude; + float _setpoint; /**< @brief The setpoint for the single value strategy. */ + float _noiseMagnitude; /**< @brief The noise magnitude for the target value. */ }; #endif \ No newline at end of file diff --git a/lib/Core/Strategies/Strategy_Square.cpp b/lib/Core/Strategies/Strategy_Square.cpp index 490d572..46b5e98 100644 --- a/lib/Core/Strategies/Strategy_Square.cpp +++ b/lib/Core/Strategies/Strategy_Square.cpp @@ -19,19 +19,28 @@ SquareStrategy::SquareStrategy(float lowerValue, float upperValue, unsigned long interval) : Strategy_Behavior(interval), _lowerValue(lowerValue), _upperValue(upperValue) {} + /** - * @brief Toggles between the upper and lower values on each execution. - * @param currentValue The current value of the Modbus point (ignored). - * @return The next value in the square wave sequence. + * @brief Sets a new lower value for the square wave. + * @param lowerValue The new lower bound for the wave. */ void SquareStrategy::setLowerValue(float lowerValue) { _lowerValue = lowerValue; } +/** + * @brief Sets a new upper value for the square wave. + * @param upperValue The new upper bound for the wave. + */ void SquareStrategy::setUpperValue(float upperValue) { _upperValue = upperValue; } +/** + * @brief Toggles between the upper and lower values on each execution. + * @param currentValue The current value of the Modbus point (ignored). + * @return The next value in the square wave sequence. + */ float SquareStrategy::execute(float currentValue) { _upState = !_upState; if(_upState){ diff --git a/lib/Core/Strategies/Strategy_Square.h b/lib/Core/Strategies/Strategy_Square.h index 586b41b..6805112 100644 --- a/lib/Core/Strategies/Strategy_Square.h +++ b/lib/Core/Strategies/Strategy_Square.h @@ -34,7 +34,15 @@ public: * @return The next value in the sequence, either the lower or upper bound. */ float execute(float currentValue) override; + /** + * @brief Sets a new lower value for the square wave. + * @param lowerValue The new lower bound for the wave. + */ void setLowerValue(float lowerValue); + /** + * @brief Sets a new upper value for the square wave. + * @param upperValue The new upper bound for the wave. + */ void setUpperValue(float upperValue); private: diff --git a/lib/Core/Strategies/Strategy_Totalizer.cpp b/lib/Core/Strategies/Strategy_Totalizer.cpp index d70d906..c81e6d1 100644 --- a/lib/Core/Strategies/Strategy_Totalizer.cpp +++ b/lib/Core/Strategies/Strategy_Totalizer.cpp @@ -10,12 +10,11 @@ /** * @brief Constructs a new TotalizerStrategy object. * - * Initializes the square wave strategy by passing the update interval to the - * base Strategy_Behavior class and storing the lower and upper bounds. + * Initializes the totalizer by passing the update interval to the base + * Strategy_Behavior class and setting the initial value to a random number + * between 0 and 1000. * - * @param lowerValue The lower value of the square wave. - * @param upperValue The upper value of the square wave. - * @param interval The time in milliseconds between each value toggle. + * @param interval The time in milliseconds between each increment. */ TotalizerStrategy::TotalizerStrategy(unsigned long interval) : Strategy_Behavior(interval) { @@ -24,9 +23,9 @@ TotalizerStrategy::TotalizerStrategy(unsigned long interval) } /** - * @brief Toggles between the upper and lower values on each execution. - * @param currentValue The current value of the Modbus point (ignored). - * @return The next value in the square wave sequence. + * @brief Increments the totalizer's value on each execution. + * @param currentValue The current value of the Modbus point (ignored in this strategy). + * @return The new, incremented value. The value resets to 0 if it exceeds 60000. */ float TotalizerStrategy::execute(float currentValue) { _currentValue += 1; diff --git a/lib/Core/Strategies/Strategy_Totalizer.h b/lib/Core/Strategies/Strategy_Totalizer.h index 9b02f4c..47ef71b 100644 --- a/lib/Core/Strategies/Strategy_Totalizer.h +++ b/lib/Core/Strategies/Strategy_Totalizer.h @@ -1,42 +1,39 @@ /** - * @file Strategy_Square.h - * @brief Defines the SquareStrategy class for generating a square wave pattern. + * @file Strategy_Totalizer.h + * @brief Defines the TotalizerStrategy class for simulating an accumulating value. * @author Emmanuel Hernandez Cruz * @date 2025-09-05 * - * This file contains the definition for a behavior strategy that alternates - * between a lower and an upper value, creating a square wave effect. + * This file contains the definition for a behavior strategy that increments + * a value at a regular interval, simulating a run-time counter or totalizer. */ #ifndef totalizer_strategy_h #define totalizer_strategy_h #include "Strategy_Behavior.h" /** - * @class SquareStrategy - * @brief A strategy that alternates between a lower and an upper value on each execution. + * @class TotalizerStrategy + * @brief A strategy that increments a value on each execution. * - * This class implements the Strategy_Behavior interface to produce a square wave - * pattern. Each time `execute` is called, it toggles between returning the - * `_lowerValue` and the `_upperValue`. + * This class implements the Strategy_Behavior interface to produce a continuously + * increasing value. Each time `execute` is called, it increments its internal + * counter and returns the new value. */ class TotalizerStrategy : public Strategy_Behavior { public: /** - * @brief Constructs a new SquareStrategy object. - * @param lowerValue The lower value of the square wave. - * @param upperValue The upper value of the square wave. - * @param interval The time in milliseconds between each value toggle. + * @brief Constructs a new TotalizerStrategy object. + * @param interval The time in milliseconds between each increment. */ TotalizerStrategy(unsigned long interval); /** - * @brief Executes the strategy to get the next value in the square wave. + * @brief Executes the strategy to get the next incremented value. * @param currentValue The current value of the Modbus point (ignored in this strategy). - * @return The next value in the sequence, either the lower or upper bound. + * @return The new, incremented value. */ float execute(float currentValue) override; private: - float _currentValue; /**< @brief The lower bound of the square wave. */ - + float _currentValue; /**< @brief The current accumulated value of the totalizer. */ }; #endif \ No newline at end of file diff --git a/lib/Core/core.h b/lib/Core/core.h index dd24064..f3c8015 100644 --- a/lib/Core/core.h +++ b/lib/Core/core.h @@ -23,6 +23,12 @@ #include // Or your specific Modbus RTU library #endif +/** + * @defgroup ModbusCategoryCodes Modbus Point Category Codes + * @brief Integer constants used in the `modbusMap` to identify the type of Modbus point. + * These codes determine which `ModbusPoint` subclass is created by the factory. + * @{ + */ const int COIL = 0; /**< @brief 0x: R/W Coil */ const int DI = 1; /**< @brief 1x: R Discrete Inputs */ const int IR = 3; /**< @brief 3x: R Input Register - Single word */ @@ -33,6 +39,7 @@ const int HR = 4; /**< @brief 4x: R/W Holding Register - Single word * const int HR_10x = 41; /**< @brief 4x: R/W Holding Register - Single word, 10x scaled */ const int HR_LONG = 42; /**< @brief 4x: R/W Holding Register - Double word, Long type */ const int HR_FLOAT = 43; /**< @brief 4x: R/W Holding Register - Double word, Float encoding */ +/** @} */ /** * @struct modbusMap @@ -47,10 +54,16 @@ struct modbusMap }; /** - * @brief The main loop previous milliseconds. + * @brief Timestamp for managing the main application loop interval. + * Used in the main `.cpp` file to control the frequency of the `EquipmentInstance.update()` call. */ unsigned long previousMillis = 0; +/** + * @defgroup GlobalInstances Global Instances + * @brief Globally accessible objects for the Modbus server and Equipment. + * @{ + */ /** * @brief Global Modbus object instance. * The type is determined at compile time based on the USE_MODBUS_IP flag. @@ -64,6 +77,6 @@ extern ModbusRTU mb; // Use ModbusRTU class /** @brief An instance of the Equipment class, representing the emulated Equipment unit. */ Equipment EquipmentInstance(&mb); #endif - +/** @} */ #endif // CORE_H diff --git a/platformio.ini b/platformio.ini index b230a01..8301863 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = CRAH_PAHHC_600_C6_TCP +default_envs = CH_Daikin_AWV026B_RTU [common_env_options] framework = arduino diff --git a/src/CH_Daikin_AWV026B_RTU/State_Fail.cpp b/src/CH_Daikin_AWV026B_RTU/State_Fail.cpp index f9d5820..6666ff4 100644 --- a/src/CH_Daikin_AWV026B_RTU/State_Fail.cpp +++ b/src/CH_Daikin_AWV026B_RTU/State_Fail.cpp @@ -27,9 +27,9 @@ /** * @brief Constructs a new FailState object. * - * This constructor initializes behavior strategies to simulate a failure - * scenario. In this example, it sets a common alarm bit, triggers a specific - * alarm for "EC Fan #1", and ramps down all fan speeds to zero. + * This constructor receives a list of alarm descriptions and creates strategies + * to set the corresponding Modbus points to a value of 1, indicating an + * active alarm. It also initializes a PID strategy for the valve position. */ template<> FailState::FailState(const std::vector& activeAlarms) { @@ -44,10 +44,9 @@ FailState::FailState(const std::vector& activeAlarms) { /** * @brief Executes the fail state's logic for one update cycle. * - * This method checks the "State Control" Modbus point for a command to - * transition back to Standby, which would typically happen after a fault - * is cleared. If no transition is requested, it applies the failure - * strategies (e.g., keeping fans off and alarms active). + * This method checks the "Clear Alm" Modbus point for a command to transition + * back to Standby, which would typically happen after a fault is cleared by a + * user. If no transition is requested, it continues to apply the failure strategies. * * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. @@ -56,8 +55,8 @@ template<> State* FailState::update(Equipment* equipment) { // STATE control, add conditions if change to a different state is needed Serial.println("Fail update function"); - ModbusPoint* alarmReset = equipment->getModbusPoint("Alarm Reset"); - int nextStateId = alarmReset ? alarmReset->getValue() : 0; + ModbusPoint* clearAlm = equipment->getModbusPoint("Clear Alm"); + int nextStateId = clearAlm ? clearAlm->getValue() : 0; if (nextStateId == 1){ return new StandbyState(); } @@ -66,8 +65,8 @@ State* FailState::update(Equipment* equipment) } /** - * @brief Logic to execute once when entering the fail state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * @brief Logic to execute once when entering the fail state. Sets the main alarm bit. + * @param equipment Pointer to the Equipment instance. */ template<> void FailState::enterState(Equipment* equipment) { @@ -78,8 +77,8 @@ void FailState::enterState(Equipment* equipment) { } /** - * @brief Logic to execute once when exiting the fail state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * @brief Logic to execute once when exiting the fail state. Clears the main alarm bit. + * @param equipment Pointer to the Equipment instance. */ template<> void FailState::exitState(Equipment* equipment) { diff --git a/src/CH_Daikin_AWV026B_RTU/State_Running.cpp b/src/CH_Daikin_AWV026B_RTU/State_Running.cpp index 192ac8c..5eab11e 100644 --- a/src/CH_Daikin_AWV026B_RTU/State_Running.cpp +++ b/src/CH_Daikin_AWV026B_RTU/State_Running.cpp @@ -29,9 +29,9 @@ /** * @brief Constructs a new RunningState object. * - * This constructor initializes the behavior strategies for various Modbus points - * that are active during the running state. For example, it sets different - * dynamic behaviors for the speeds of EC fans 1 through 5. + * This constructor initializes behavior strategies active during the running + * state, such as a PID controller for the 'CW Valve Position' and totalizers + * for the run-hours of each EC fan. */ template<> RunningState::RunningState() { @@ -50,9 +50,12 @@ RunningState::RunningState() { /** * @brief Executes the running state's logic for one update cycle. * - * This method checks the "State Control" Modbus point for a command to - * transition to a different state (e.g., back to Standby). If no transition - * is requested, it applies the strategies defined for the running state. + * This method first checks for state transition commands: + * 1. It reads the "ON/OFF Command By BMS" point. If it's 0, it transitions to StandbyState. + * 2. It reads the "Fault Code" point. If it's non-zero, it transitions to FailState, + * passing the corresponding alarm description. + * + * If no transition occurs, it applies the strategies defined for the running state. * * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. @@ -70,62 +73,14 @@ State* RunningState::update(Equipment* equipmen ModbusPoint* faultCode = equipment->getModbusPoint("Fault Code"); int faultCodeValue = faultCode ? faultCode->getValue() : 0; - switch (faultCodeValue){ - case 1: - return new FailState({"Alarm SAT Sensor Fault"}); - case 2: - return new FailState({"Alarm RAH Sensor Fault"}); - case 3: - return new FailState({"Alarm RAT Sensor Fault"}); - case 4: - return new FailState({"Alarm Filter DP Sensor Fault"}); - case 5: - return new FailState({"Alarm Flooding"}); - case 6: - return new FailState({"Alarm Dirty Filter"}); - case 7: - return new FailState({"Alarm High RAT"}); - case 8: - return new FailState({"Alarm Low RAT"}); - case 9: - return new FailState({"Alarm High SAT"}); - case 10: - return new FailState({"Alarm Low SAT"}); - case 11: - return new FailState({"Alarm High RAH"}); - case 12: - return new FailState({"Alarm Low RAH"}); - case 13: - return new FailState({"Alarm Phase Failure"}); - case 14: - return new FailState({"Alarm Condensate Pump"}); - case 15: - return new FailState({"Alarm Smoke"}); - case 16: - return new FailState({"Alarm Fire"}); - case 17: - return new FailState({"Alarm EC Fan #1"}); - case 18: - return new FailState({"Alarm EC Fan #2"}); - case 19: - return new FailState({"Alarm EC Fan #3"}); - case 20: - return new FailState({"Alarm EC Fan #4"}); - case 21: - return new FailState({"Alarm EC Fan #5"}); - case 22: - return new FailState({"Alarm EC Fan #6"}); - case 23: - return new FailState({"Alarm EC Fan #7"}); - case 24: - return new FailState({"Alarm EC Fan #8"}); - case 25: - return new FailState({"Alarm EC Fan #9"}); - default: - break; + if (faultCodeValue != 0) { + // A fault has been triggered, transition to FailState + // This assumes a mapping between fault codes and alarm descriptions exists + // For this example, we'll just use a generic alarm name based on the code + std::string alarmDesc = "Fault Alm Code " + std::to_string(faultCodeValue); + return new FailState({alarmDesc}); } - ModbusPoint* point = equipment->getModbusPoint("Setting the EC Fan Max Speed"); - point->setValue(45); + // Apply any strategies defined for the standby state _applyStrategies(equipment); return nullptr; @@ -133,7 +88,8 @@ State* RunningState::update(Equipment* equipmen /** * @brief Logic to execute once when entering the running state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * Sets the "Chiller Sts" point to indicate the unit is running. + * @param equipment Pointer to the Equipment instance. */ template<> void RunningState::enterState(Equipment* equipment) { @@ -158,7 +114,8 @@ void RunningState::enterState(Equipment* equipment) { /** * @brief Logic to execute once when exiting the running state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * Sets the "Chiller Sts" point to indicate the unit is no longer running. + * @param equipment Pointer to the Equipment instance. */ template<> void RunningState::exitState(Equipment* equipment) { diff --git a/src/CH_Daikin_AWV026B_RTU/State_Standby.cpp b/src/CH_Daikin_AWV026B_RTU/State_Standby.cpp index 7083ad0..46508a0 100644 --- a/src/CH_Daikin_AWV026B_RTU/State_Standby.cpp +++ b/src/CH_Daikin_AWV026B_RTU/State_Standby.cpp @@ -8,6 +8,7 @@ * the behavior of the equipment when it is in an idle or standby mode. */ #include "States/State_Standby.h" +#include "States/State_Running.h" #include "Categories/ModbusPoint.h" #include "Categories/ModbusFloatDecorator.h" #include "Equipment/Equipment.h" @@ -24,26 +25,12 @@ /** * @brief Constructs a new StandbyState object. * - * In this state, the equipment is idle. This constructor can be used to - * define specific behaviors for Modbus points that should occur during standby, - * such as setting fan speeds to zero. + * In this state, the equipment is idle. This constructor initializes several + * strategies to generate random values for various status points, simulating + * a live but non-operational unit. */ template<> StandbyState::StandbyState() { - // You can add initialization code here if needed - /* - addStrategy("SAT Reading", new SingleValueStrategy(100.0f, 0.1f, 1000)); - addStrategy("CW Valve Position", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #1", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #2", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #3", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #4", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #5", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #6", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #7", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #8", new RampStrategy(0.0f, 5.0f, 1000)); - addStrategy("Speed EC Fan #9", new RampStrategy(0.0f, 5.0f, 1000)); - */ addStrategy("Chiller Local-Network", new RandomStrategy(1000)); addStrategy("Chiller Enable Output", new RandomStrategy(1000)); addStrategy("Run Enabled", new RandomStrategy(1000)); @@ -53,11 +40,11 @@ StandbyState::StandbyState() { } /** - * @brief Executes the running state's logic for one update cycle. + * @brief Executes the standby state's logic for one update cycle. * - * This method checks the "State Control" Modbus point for a command to - * transition to a different state (e.g., back to Standby). If no transition - * is requested, it applies the strategies defined for the running state. + * This method checks the "Chiller On-Off" Modbus point for a command to + * transition to the Running state. If no transition is requested, it applies + * the strategies defined for the standby state. * * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. @@ -66,14 +53,12 @@ template<> State* StandbyState::update(Equipment* equipment) { // STATE control, add conditions if change to a different state is needed Serial.println("Standby update function"); - /* - ModbusPoint* On_Off_Command = equipment->getModbusPoint("ON/OFF Command By BMS"); - int nextStateId = On_Off_Command ? On_Off_Command->getValue() : 0; + ModbusPoint* chillerOnOff = equipment->getModbusPoint("Chiller On-Off"); + int nextStateId = chillerOnOff ? chillerOnOff->getValue() : 0; Serial.println(nextStateId); if (nextStateId == 1){ - return new RunningState(); + return new RunningState(); } - */ // Apply any strategies defined for the standby state _applyStrategies(equipment); return nullptr; @@ -81,15 +66,13 @@ State* StandbyState::update(Equipment* equipmen /** * @brief Logic to execute once when entering the standby state. + * Sets the "Chiller Sts" point to indicate the unit is not running. * @param equipment Pointer to the Equipment instance. */ template<> void StandbyState::enterState(Equipment* equipment) { // Logic to run when the equipment enters this state - // A list of all alarm descriptions Serial.println("Enter Standby State..."); - - int CH_ON_OFF = getPointValue(equipment, "Chiller On-Off"); int Ch_Sts = getPointValue(equipment, "Chiller Sts"); diff --git a/src/CH_Daikin_AWV026B_RTU/config.h b/src/CH_Daikin_AWV026B_RTU/config.h index 9cccbaa..f36d192 100644 --- a/src/CH_Daikin_AWV026B_RTU/config.h +++ b/src/CH_Daikin_AWV026B_RTU/config.h @@ -1,11 +1,11 @@ /** * @file config.h - * @brief Main configuration file for the Equipment emulator. + * @brief Main configuration file for the Daikin Chiller (RTU) emulator. * @author Emmanuel Hernandez Cruz * @date 2025-09-02 * - * This file contains two important configurations: WiFi network parameters - * and the Modbus register map for the device. + * This file contains important configurations for the Modbus RTU communication + * and the specific register map for the emulated device. */ #ifndef CONFIG_H @@ -14,6 +14,39 @@ #include "core.h" #include "Equipment/Equipment.h" + +#if defined(USE_MODBUS_IP) +/** + * @defgroup ModbusTCPConfig Modbus IP Configuration + * @brief Parameters for Modbus TCP communication. + * @{ + */ + #include + const char *ssid = "esrlok_portable"; /**< @brief The SSID of the WiFi network. */ + const char *password = "m7g6eNMe?cy8S@z"; /**< @brief The password for the WiFi network. */ + IPAddress local_IP(192, 168, 1, 234); /**< @brief The static IP address for the device. */ + IPAddress gateway(192, 168, 1, 1); /**< @brief The gateway IP address. */ + IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ + + ModbusIP mb; +#else + /** + * @defgroup ModbusRTUConfig Modbus RTU Configuration + * @brief Parameters for serial Modbus RTU communication. + * @{ + */ + #include + const int BAUDRATE = 19200; /**< @brief The serial communication speed in bits per second. */ + const int RX_PIN = 17; /**< @brief The GPIO pin used for receiving data (RX). */ + const int TX_PIN = 16; /**< @brief The GPIO pin used for transmitting data (TX). */ + const int RST_PIN = 4; /**< @brief The GPIO pin connected to the RS485 driver's DE/RE pins for direction control. */ + const int MODBUS_ID = 1; /**< @brief The unique slave ID for this device on the Modbus bus. */ + /** @} */ + + /** @brief Global instance of the Modbus RTU server. */ + ModbusRTU mb; +#endif + /** * @brief The Modbus map for the Equipment device. * This array defines all the Modbus points available on the emulated device. @@ -94,6 +127,4 @@ const int map_size = sizeof(mb_map) / sizeof(mb_map[0]); */ int interval = 250; - -ModbusRTU mb; #endif // CONFIG_H diff --git a/src/CH_Daikin_AWV026B_RTU/main.cpp b/src/CH_Daikin_AWV026B_RTU/main.cpp index 5526236..cacad11 100644 --- a/src/CH_Daikin_AWV026B_RTU/main.cpp +++ b/src/CH_Daikin_AWV026B_RTU/main.cpp @@ -1,28 +1,27 @@ /** - * @file BaseEmulator.ino - * @brief Main execution program for the Arduino Emulator. + * @file main.cpp + * @brief Main execution program for the Daikin Chiller (RTU) Emulator. * @author Emmanuel Hernandez Cruz * @date 2025-09-02 * - * @details This file contains the main execution program for an Arduino-based emulator of a equipment unit. - * The program uses a Wi-Fi connection to communicate via the Modbus IP protocol. + * @details This file contains the main execution program for an Arduino-based + * emulator of a Daikin Chiller unit. The program communicates via the + * Modbus RTU protocol over a serial connection. * * The setup() function initializes the following: * - Serial communication for debugging. - * - Wi-Fi connection using credentials from config.h. - * - A Modbus IP server. + * - A Modbus RTU server with parameters from config.h. * - Modbus points (Coils, Holding Registers, etc.) based on a predefined map in config.h. * * The loop() function continuously: - * - Services the Modbus IP server. - * - Reads values from the Modbus server into internal data structures. - * - Updates the state of the emulated equipment. - * - Writes updated values back to the Modbus server. + * - Services the Modbus RTU server to handle incoming requests. + * - Periodically calls the main update loop for the emulated equipment, which + * manages state transitions and behavior strategies. * - * @see config.h for Wi-Fi and Modbus configuration. + * @see config.h for Modbus RTU and register map configuration. * @see Equipment.h for the main equipment logic. * @see State.h for different equipment states. - * @see Strategies/Strategy_Behavior.h for different value generation strategies. + * @see Strategies/Strategy_Behavior.h for value generation strategies. * @see ModbusPoint.h for the base class for all Modbus points. */ //================================================================================================================================= @@ -34,18 +33,18 @@ //================================================================================================================================= /** * @brief Initializes the application. - * @details This function runs once at startup. It configures the serial communication, - * Wi-Fi, and the Modbus server. It also creates and initializes all the Modbus points - * based on the `mb_map` array in `config.h`. + * @details This function runs once at startup. It configures the serial communication + * for debugging and the Modbus RTU server. It then creates and initializes all + * the Modbus points based on the `mb_map` array in `config.h`. */ const int rtsPin = 4; void setup() { Serial.begin(115200); Serial.println("Setup function started"); - Serial2.begin(19200, SERIAL_8N1, 17, 16); - mb.begin(&Serial2, 4); // Start the server - mb.slave(1); // Set the slave ID + Serial2.begin(BAUDRATE, SERIAL_8N1, RX_PIN, TX_PIN); + mb.begin(&Serial2, RST_PIN); // Start the server + mb.slave(MODBUS_ID); // Set the slave ID for(int i = 0; i < map_size; i++){ ModbusPoint* point = createModbusPoint(&mb, mb_map[i].category, mb_map[i].address, mb_map[i].value, mb_map[i].description); @@ -59,11 +58,11 @@ void setup() { //================================================================================================================================= /** * @brief The main application loop. - * @details This function runs repeatedly after setup() has completed. It performs the following actions in order: - * 1. Services the Modbus server by calling `mb.task()`. - * 2. Reads the current values from the Modbus registers into the `ModbusPoint` objects by calling `readRegisters()`. - * 3. After a specified interval, it updates the equipment's state by calling `EquipmentInstance.update()`. - * 4. Writes any changed values from the `ModbusPoint` objects back to the Modbus registers by calling `writeRegisters()`. + * @details This function runs repeatedly after setup() has completed. It performs two main actions: + * 1. It continuously services the Modbus server by calling `mb.task()` to handle + * incoming requests from a Modbus master. + * 2. At a fixed interval (defined in `config.h`), it calls `EquipmentInstance.update()` + * to run the emulator's internal state machine and behavior logic. */ void loop() { mb.task(); diff --git a/src/CRAH_PAHHC_600_C6_TCP/State_Fail.cpp b/src/CRAH_PAHHC_600_C6_TCP/State_Fail.cpp index 87c27f8..fd5a185 100644 --- a/src/CRAH_PAHHC_600_C6_TCP/State_Fail.cpp +++ b/src/CRAH_PAHHC_600_C6_TCP/State_Fail.cpp @@ -22,11 +22,14 @@ #endif /** - * @brief Constructs a new FailState object. + * @brief Constructs a new FailState object with a list of active alarms. * - * This constructor initializes behavior strategies to simulate a failure - * scenario. In this example, it sets a common alarm bit, triggers a specific - * alarm for "EC Fan #1", and ramps down all fan speeds to zero. + * This constructor receives a list of alarm descriptions and creates strategies + * to set the corresponding Modbus points to a value of 1, indicating an + * active alarm. It also initializes a PID strategy for the 'CW Valve Position' + * to maintain its state during the fault. + * @param activeAlarms A vector of strings, where each string is the + * description of a Modbus point to be set as an active alarm. */ template<> FailState::FailState(const std::vector& activeAlarms) { @@ -41,10 +44,10 @@ FailState::FailState(const std::vector& activeAlarms) { /** * @brief Executes the fail state's logic for one update cycle. * - * This method checks the "State Control" Modbus point for a command to + * This method checks the "Alarm Reset" Modbus point for a command to * transition back to Standby, which would typically happen after a fault - * is cleared. If no transition is requested, it applies the failure - * strategies (e.g., keeping fans off and alarms active). + * is cleared by a user. If no transition is requested, it continues to apply + * the failure strategies (e.g., keeping alarm bits active). * * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. @@ -64,7 +67,8 @@ State* FailState::update(Equipment* equipment) { /** * @brief Logic to execute once when entering the fail state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * Sets the "Alarm Common" point to 1 to indicate a general fault condition. + * @param equipment Pointer to the Equipment instance. */ template<> void FailState::enterState(Equipment* equipment) { @@ -76,7 +80,8 @@ void FailState::enterState(Equipment* equipment) { /** * @brief Logic to execute once when exiting the fail state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * Clears the "Alarm Common" point to 0 before transitioning to the next state. + * @param equipment Pointer to the Equipment instance. */ template<> void FailState::exitState(Equipment* equipment) { diff --git a/src/CRAH_PAHHC_600_C6_TCP/State_Running.cpp b/src/CRAH_PAHHC_600_C6_TCP/State_Running.cpp index 083972b..c9c25ff 100644 --- a/src/CRAH_PAHHC_600_C6_TCP/State_Running.cpp +++ b/src/CRAH_PAHHC_600_C6_TCP/State_Running.cpp @@ -32,9 +32,9 @@ /** * @brief Constructs a new RunningState object. * - * This constructor initializes the behavior strategies for various Modbus points - * that are active during the running state. For example, it sets different - * dynamic behaviors for the speeds of EC fans 1 through 5. + * This constructor initializes behavior strategies active during the running + * state, such as a PID controller for the 'CW Valve Position' and totalizers + * for the run-hours of each EC fan. */ template<> RunningState::RunningState() { @@ -53,9 +53,12 @@ RunningState::RunningState() { /** * @brief Executes the running state's logic for one update cycle. * - * This method checks the "State Control" Modbus point for a command to - * transition to a different state (e.g., back to Standby). If no transition - * is requested, it applies the strategies defined for the running state. + * This method first checks for state transition commands: + * 1. It reads the "ON/OFF Command By BMS" point. If it's 0, it transitions to StandbyState. + * 2. It reads the "Fault Code" point. If it's non-zero, it transitions to FailState, + * passing the corresponding alarm description. + * + * If no transition occurs, it applies the strategies defined for the running state. * * @param equipment Pointer to the Equipment instance. * @return A pointer to a new State if a transition should occur, otherwise nullptr. @@ -135,7 +138,8 @@ State* RunningState::update(Equipment* equipment) /** * @brief Logic to execute once when entering the running state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * Sets the "Run Status" for all EC fans to 1 to indicate they are active. + * @param equipment Pointer to the Equipment instance. */ template<> void RunningState::enterState(Equipment* equipment) { @@ -160,10 +164,24 @@ void RunningState::enterState(Equipment* equipment) { /** * @brief Logic to execute once when exiting the running state. - * @param equipment Pointer to the Equipment instance (unused in this implementation). + * Sets the "Run Status" for all EC fans to 0 before transitioning to the next state. + * @param equipment Pointer to the Equipment instance. */ template<> void RunningState::exitState(Equipment* equipment) { // Cleanup logic to run when the equipment leaves this state Serial.println("Exit Running State..."); + const std::vector motorStatusDescriptions = { + "Run Status EC Fan #1", "Run Status EC Fan #2", "Run Status EC Fan #3", + "Run Status EC Fan #4", "Run Status EC Fan #5", "Run Status EC Fan #6", + "Run Status EC Fan #7", "Run Status EC Fan #8", "Run Status EC Fan #9" + }; + + // Loop through and set all motor statuses to 0 + for (const auto& desc : motorStatusDescriptions) { + ModbusPoint* point = equipment->getModbusPoint(desc); + if (point) { + point->setValue(0); + } + } } \ No newline at end of file diff --git a/src/CRAH_PAHHC_600_C6_TCP/State_Standby.cpp b/src/CRAH_PAHHC_600_C6_TCP/State_Standby.cpp index 239413e..6c27ac1 100644 --- a/src/CRAH_PAHHC_600_C6_TCP/State_Standby.cpp +++ b/src/CRAH_PAHHC_600_C6_TCP/State_Standby.cpp @@ -30,9 +30,10 @@ /** * @brief Constructs a new StandbyState object. * - * In this state, the equipment is idle. This constructor can be used to - * define specific behaviors for Modbus points that should occur during standby, - * such as setting fan speeds to zero. + * In this state, the equipment is idle. This constructor initializes strategies + * to bring the system to a safe, idle condition. It sets a stable value for + * the SAT reading and creates ramp strategies to bring the CW valve and all + * EC fan speeds down to zero. */ template<> StandbyState::StandbyState() { @@ -52,19 +53,27 @@ StandbyState::StandbyState() { } /** - * @brief Executes the running state's logic for one update cycle. + * @brief Executes the standby state's logic for one update cycle. * - * This method checks the "State Control" Modbus point for a command to - * transition to a different state (e.g., back to Standby). If no transition - * is requested, it applies the strategies defined for the running state. + * This method applies the strategies defined for the standby state (e.g., + * ramping values to zero). * - * @param equipment Pointer to the Equipment instance. + * @warning This method currently does not check for a command to transition to the + * Running state. This logic needs to be added to allow the unit to start. * @return A pointer to a new State if a transition should occur, otherwise nullptr. */ template<> State* StandbyState::update(Equipment* equipment) { // STATE control, add conditions if change to a different state is needed Serial.println("Standby update function"); + int On_Off_Command = getPointValue(equipment, "ON/OFF Command By BMS"); + Serial.printf("ON_OFF COmmand %f. \n", On_Off_Command); + if (On_Off_Command == 1){ + return new RunningState(); + } + + + // Apply any strategies defined for the standby state _applyStrategies(equipment); @@ -73,6 +82,8 @@ State* StandbyState::update(Equipment* equipment) /** * @brief Logic to execute once when entering the standby state. + * This method performs cleanup by setting all alarm points and all EC fan + * run status points to 0. * @param equipment Pointer to the Equipment instance. */ template<> diff --git a/src/CRAH_PAHHC_600_C6_TCP/config.h b/src/CRAH_PAHHC_600_C6_TCP/config.h index e9c5728..61500a7 100644 --- a/src/CRAH_PAHHC_600_C6_TCP/config.h +++ b/src/CRAH_PAHHC_600_C6_TCP/config.h @@ -1,6 +1,6 @@ /** * @file config.h - * @brief Main configuration file for the Equipment emulator. + * @brief Main configuration file for the CRAH Unit (TCP) emulator. * @author Emmanuel Hernandez Cruz * @date 2025-09-02 * @@ -8,12 +8,6 @@ * and the Modbus register map for the device. */ -/** - * @defgroup WiFiConfig WiFi Configuration - * @brief Network parameters for WiFi connection. - * @{ - */ - #ifndef CONFIG_H #define CONFIG_H @@ -21,6 +15,11 @@ #include "Equipment/Equipment.h" #if defined(USE_MODBUS_IP) +/** + * @defgroup ModbusTCPConfig Modbus IP Configuration + * @brief Parameters for Modbus TCP communication. + * @{ + */ #include const char *ssid = "esrlok_portable"; /**< @brief The SSID of the WiFi network. */ const char *password = "m7g6eNMe?cy8S@z"; /**< @brief The password for the WiFi network. */ @@ -30,15 +29,30 @@ ModbusIP mb; #else + /** + * @defgroup ModbusRTUConfig Modbus RTU Configuration + * @brief Parameters for serial Modbus RTU communication. + * @{ + */ #include + const int BAUDRATE = 19200; /**< @brief The serial communication speed in bits per second. */ + const int RX_PIN = 17; /**< @brief The GPIO pin used for receiving data (RX). */ + const int TX_PIN = 16; /**< @brief The GPIO pin used for transmitting data (TX). */ + const int RST_PIN = 4; /**< @brief The GPIO pin connected to the RS485 driver's DE/RE pins for direction control. */ + const int MODBUS_ID = 1; /**< @brief The unique slave ID for this device on the Modbus bus. */ + /** @} */ + + /** @brief Global instance of the Modbus RTU server. */ + ModbusRTU mb; #endif -/** - * @brief The main loop update interval in milliseconds. - */ -int interval = 250; +/** + * @defgroup ModbusMapConfig Modbus Map Configuration + * @brief Defines the Modbus register map and related parameters for the emulator. + * @{ + */ /** * @brief The Modbus map for the Equipment device. * This array defines all the Modbus points available on the emulated device. @@ -124,11 +138,15 @@ modbusMap mb_map[] = {COIL, 264, 0, "Alarm Reset"} }; //Size of modbus map used in FOR cycles, automatically calculated. + /** * @brief The total number of entries in the `mb_map` array. * This is calculated at compile time and used for iterating over the map. */ const int map_size = sizeof(mb_map) / sizeof(mb_map[0]); -/** @} */ + +/** @brief The main loop update interval in milliseconds. */ +int interval = 250; +/** @} */ // End of ModbusMapConfig group #endif // CONFIG_H diff --git a/src/CRAH_PAHHC_600_C6_TCP/main.cpp b/src/CRAH_PAHHC_600_C6_TCP/main.cpp index 2ffb050..f911995 100644 --- a/src/CRAH_PAHHC_600_C6_TCP/main.cpp +++ b/src/CRAH_PAHHC_600_C6_TCP/main.cpp @@ -1,28 +1,27 @@ /** - * @file BaseEmulator.ino - * @brief Main execution program for the Arduino Emulator. + * @file main.cpp + * @brief Main execution program for the CRAH Unit (TCP) Emulator. * @author Emmanuel Hernandez Cruz * @date 2025-09-02 * - * @details This file contains the main execution program for an Arduino-based emulator of a equipment unit. + * @details This file contains the main execution program for an Arduino-based emulator of a CRAH unit. * The program uses a Wi-Fi connection to communicate via the Modbus IP protocol. * * The setup() function initializes the following: * - Serial communication for debugging. * - Wi-Fi connection using credentials from config.h. - * - A Modbus IP server. + * - A Modbus TCP server. * - Modbus points (Coils, Holding Registers, etc.) based on a predefined map in config.h. * * The loop() function continuously: - * - Services the Modbus IP server. - * - Reads values from the Modbus server into internal data structures. - * - Updates the state of the emulated equipment. - * - Writes updated values back to the Modbus server. + * - Services the Modbus TCP server to handle incoming requests. + * - Periodically calls the main update loop for the emulated equipment, which + * manages state transitions and behavior strategies. * * @see config.h for Wi-Fi and Modbus configuration. * @see Equipment.h for the main equipment logic. * @see State.h for different equipment states. - * @see Strategy_Behavior.h for different value generation strategies. + * @see Strategies/Strategy_Behavior.h for value generation strategies. * @see ModbusPoint.h for the base class for all Modbus points. */ //================================================================================================================================= @@ -67,11 +66,11 @@ void setup() { //================================================================================================================================= /** * @brief The main application loop. - * @details This function runs repeatedly after setup() has completed. It performs the following actions in order: - * 1. Services the Modbus server by calling `mb.task()`. - * 2. Reads the current values from the Modbus registers into the `ModbusPoint` objects by calling `readRegisters()`. - * 3. After a specified interval, it updates the equipment's state by calling `EquipmentInstance.update()`. - * 4. Writes any changed values from the `ModbusPoint` objects back to the Modbus registers by calling `writeRegisters()`. + * @details This function runs repeatedly after setup() has completed. It performs two main actions: + * 1. It continuously services the Modbus server by calling `mb.task()` to handle + * incoming requests from a Modbus master. + * 2. At a fixed interval (defined in `config.h`), it calls `EquipmentInstance.update()` + * to run the emulator's internal state machine and behavior logic. */ void loop() { mb.task();