Name updated, Categories folder to ModbuPoints, less generic to be self documented

This commit is contained in:
2025-09-15 12:51:34 -05:00
parent 5a0b02ccdf
commit 14cf23281d
24 changed files with 274 additions and 297 deletions

View File

@@ -0,0 +1,86 @@
/**
* @file Modbus_Coil.h
* @brief Defines the Modbus_Coil class for handling Modbus coils.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-04
*
* This file contains the definition of the Modbus_Coil class, which is a specific
* implementation of the Modbus_Point for handling coils (digital outputs).
*/
#ifndef Modbus_Coil_h
#define Modbus_Coil_h
#include "Modbus_Point.h"
/**
* @class Modbus_Coil
* @brief Represents a Modbus coil point.
*
* This class provides a concrete implementation for a Modbus coil,
* which is a single bit digital output. It inherits from Modbus_Point
* and implements its virtual functions for coil-specific operations.
*/
template<typename T>
class Modbus_Coil : public Modbus_Point<T>{
public:
/**
* @brief Constructor for the Modbus_Coil class.
* @param server Pointer to the ModbusIP server instance.
* @param address The Modbus address of the coil.
* @param value The initial value of the coil.
* @param description A description of the coil.
*/
Modbus_Coil(T* server, int address, int value, const char* description);
/**
* @brief Adds the coil to the Modbus server.
*/
void addToModbusServer() override;
/**
* @brief Sets the internal value of the coil.
* @param value The new value for the coil.
*/
void setValue(int value) override;
/**
* @brief Gets the current internal value of the coil.
* @return The current value of the coil.
*/
int getValue() const override;
};
template<typename T>
Modbus_Coil<T>::Modbus_Coil(T* server, int address, int value, const char* description)
: Modbus_Point<T>(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<typename T>
void Modbus_Coil<T>::addToModbusServer(){
this->_server->addCoil(this->_address, this->_value);
}
/**
* @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<typename T>
void Modbus_Coil<T>::setValue(int value){
this->_server->Coil(this->_address, value);
}
/**
* @brief Gets the current value of the coil from the Modbus server.
* @return The current value.
*/
template<typename T>
int Modbus_Coil<T>::getValue() const{
return this->_server->Coil(this->_address);
}
#endif

View File

@@ -0,0 +1,115 @@
/**
* @file Modbus_FloatDecorator.h
* @brief Defines the Modbus_FloatDecorator class for handling 32-bit float values.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for a decorator that combines two 16-bit
* Modbus registers to represent a single 32-bit floating-point value.
*/
#ifndef Modbus_FloatDecorator_h
#define Modbus_FloatDecorator_h
#include <stdint.h>
#include "Modbus_PointDecorator.h"
/**
* @union cracked_float_t
* @brief A union to easily convert between a 32-bit float and two 16-bit integers.
*
* 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. */
int16_t as_int[2]; /**< @brief The value as two 16-bit integers. */
} cracked_float_t;
/**
* @class Modbus_FloatDecorator
* @brief A decorator that combines two 16-bit registers into a 32-bit float.
*
* This class wraps two consecutive Modbus_Point objects (a low-word and a
* high-word point) and treats them as a single 32-bit float value. It
* overrides the necessary methods to handle reading, writing, and value
* conversion across both underlying registers.
*/
template<typename T>
class Modbus_FloatDecorator : public Modbus_PointDecorator<T> {
public:
/**
* @brief Constructs a new Modbus_FloatDecorator object.
* @param point A pointer to the Modbus_Point for the low-order word (LSW).
* @param highOrderPoint A pointer to the Modbus_Point for the high-order word.
*/
Modbus_FloatDecorator(Modbus_Point<T>* point, Modbus_Point<T>* highOrderPoint)
: Modbus_PointDecorator<T>(point), _highOrderPoint(highOrderPoint) {}
/**
* @brief Returns the logical type of the point.
* @return Always returns `PointType::FLOAT`.
*/
PointType getType() const override { return PointType::FLOAT; }
/**
* @brief Sets the 32-bit float value by casting an integer.
* This method is an override for the base class and calls `setFloatValue`.
* @param value The integer value to set (will be cast to float).
*/
void setValue(int value) override {
setFloatValue(static_cast<float>(value));
}
/**
* @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 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) {
cracked_float_t buffer;
buffer.v = value;
this->_point->setValue(buffer.as_int[0]);
_highOrderPoint->setValue(buffer.as_int[1]);
}
/**
* @brief Gets the 32-bit float value, cast to an integer.
* @return The integer representation of the full float value.
*/
int getValue() const override {
return static_cast<int>(getFloatValue());
}
/**
* @brief Gets the combined 32-bit float value from the two registers.
*
* This method reads the 16-bit integer values from the two underlying
* 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;
// 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;
}
// --- Housekeeping Methods ---
/** @brief Adds both underlying registers to the Modbus server. */
void addToModbusServer() override {
this->_point->addToModbusServer();
_highOrderPoint->addToModbusServer();
}
private:
Modbus_Point<T>* _highOrderPoint; /**< @brief Pointer to the Modbus_Point for the high-order word. */
};
#endif

View File

@@ -0,0 +1,90 @@
/**
* @file Modbus_Hreg.h
* @brief Defines the Modbus_Hreg class for handling Modbus holding registers.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-04
*
* This file contains the definition of the Modbus_Hreg class, which is a specific
* implementation of the Modbus_Point for handling holding registers (16-bit).
*/
#ifndef Modbus_Hreg_h
#define Modbus_Hreg_h
#include "Modbus_Point.h"
/**
* @class Modbus_Hreg
* @brief Represents a Modbus holding register point.
*
* This class provides a concrete implementation for a Modbus holding register,
* which is a 16-bit read/write register. It inherits from Modbus_Point
* and implements its virtual functions for holding register-specific operations.
*/
template<typename T>
class Modbus_Hreg : public Modbus_Point<T>{
public:
/**
* @brief Constructor for the Modbus_Hreg class.
* @param server Pointer to the ModbusIP server instance.
* @param address The Modbus address of the holding register.
* @param value The initial value of the holding register.
* @param description A description of the holding register.
*/
Modbus_Hreg(T* server, int address, int value, const char* description);
/**
* @brief Adds the holding register to the Modbus server.
*/
void addToModbusServer() override;
/**
* @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 value of the holding register from the Modbus server.
* @return The current value of the holding register.
*/
int getValue() const override;
};
template<typename T>
Modbus_Hreg<T>::Modbus_Hreg(T* server, int address, int value, const char* description)
: Modbus_Point<T>(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<typename T>
void Modbus_Hreg<T>::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<typename T>
void Modbus_Hreg<T>::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<typename T>
int Modbus_Hreg<T>::getValue() const {
return this->_server->Hreg(this->_address);
}
#endif

View File

@@ -0,0 +1,86 @@
/**
* @file Modbus_Ireg.h
* @brief Defines the Modbus_Ireg class for handling Modbus Input Registers.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-04
*
* This file contains the definition of the Modbus_Ireg class, which is a specific
* implementation of the Modbus_Point for handling input registers (16-bit read-only).
*/
#ifndef Modbus_Ireg_h
#define Modbus_Ireg_h
#include "Modbus_Point.h"
/**
* @class Modbus_Ireg
* @brief Represents a Modbus Input Register point.
*
* This class provides a concrete implementation for a Modbus input register,
* which is a 16-bit read-only register. It inherits from Modbus_Point
* and implements its virtual functions for input register-specific operations.
*/
template<typename T>
class Modbus_Ireg : public Modbus_Point<T>{
public:
/**
* @brief Constructor for the Modbus_Ireg class.
* @param server Pointer to the ModbusIP server instance.
* @param address The Modbus address of the input register.
* @param value The initial value of the input register.
* @param description A description of the input register.
*/
Modbus_Ireg(T* server, int address, int value, const char* description);
/**
* @brief Adds the input register to the Modbus server.
*/
void addToModbusServer() override;
/**
* @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 value of the input register from the Modbus server.
* @return The current value of the input register.
*/
int getValue() const override;
};
template<typename T>
Modbus_Ireg<T>::Modbus_Ireg(T* server, int address, int value, const char* description)
: Modbus_Point<T>(server, address, value, description){}
/**
* @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<typename T>
void Modbus_Ireg<T>::setValue(int value){
this->_server->Ireg(this->_address, value);
}
/**
* @brief Gets the current value of the input register from the Modbus server.
* @return The current 16-bit value from the register.
*/
template<typename T>
int Modbus_Ireg<T>::getValue() const {
return this->_server->Ireg(this->_address);
}
/**
* @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<typename T>
void Modbus_Ireg<T>::addToModbusServer(){
this->_server->addIreg(this->_address, this->_value);
}
#endif

View File

@@ -0,0 +1,86 @@
/**
* @file Modbus_Ists.h
* @brief Defines the Modbus_Ists class for handling Modbus Input Status (Discrete Inputs).
* @author Emmanuel Hernandez Cruz
* @date 2025-09-04
*
* This file contains the definition of the Modbus_Ists class, which is a specific
* implementation of the Modbus_Point for handling discrete inputs (read-only coils).
*/
#ifndef Modbus_Ists_h
#define Modbus_Ists_h
#include "Modbus_Point.h"
/**
* @class Modbus_Ists
* @brief Represents a Modbus Input Status (Discrete Input) point.
*
* This class provides a concrete implementation for a Modbus discrete input,
* which is a single bit read-only value. It inherits from Modbus_Point
* and implements its virtual functions for discrete input-specific operations.
*/
template<typename T>
class Modbus_Ists : public Modbus_Point<T>{
public:
/**
* @brief Constructor for the Modbus_Ists class.
* @param server Pointer to the ModbusIP server instance.
* @param address The Modbus address of the discrete input.
* @param value The initial value of the discrete input.
* @param description A description of the discrete input.
*/
Modbus_Ists(T* server, int address, int value, const char* description);
/**
* @brief Adds the discrete input to the Modbus server.
*/
void addToModbusServer() override;
/**
* @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 value of the discrete input from the Modbus server.
* @return The current value of the discrete input.
*/
int getValue() const override;
};
template<typename T>
Modbus_Ists<T>::Modbus_Ists(T* server, int address, int value, const char* description)
: Modbus_Point<T>(server, address, value, description) {}
/**
* @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<typename T>
void Modbus_Ists<T>::setValue(int value){
this->_server->Ists(this->_address, value);
}
/**
* @brief Gets the current value of the discrete input from the Modbus server.
* @return The current value.
*/
template<typename T>
int Modbus_Ists<T>::getValue() const{
return this->_server->Ists(this->_address);
}
/**
* @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<typename T>
void Modbus_Ists<T>::addToModbusServer(){
this->_server->addIsts(this->_address, this->_value);
}
#endif

View File

@@ -0,0 +1,97 @@
/**
* @file Modbus_LongDecorator.h
* @brief Defines the Modbus_LongDecorator class for handling 32-bit long values.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for a decorator that combines two 16-bit
* Modbus registers to represent a single 32-bit long integer value.
*/
#ifndef Modbus_LongDecorator_h
#define Modbus_LongDecorator_h
#include "Modbus_PointDecorator.h"
/**
* @class Modbus_LongDecorator
* @brief A decorator that combines two 16-bit registers into a 32-bit long.
*
* This class wraps two consecutive Modbus_Point objects (a low-word and a
* high-word point) and treats them as a single 32-bit long integer. It
* overrides the necessary methods to handle reading, writing, and value
* conversion across both underlying registers.
*/
template<typename T>
class Modbus_LongDecorator : public Modbus_PointDecorator<T> {
public:
/**
* @brief Constructs a new Modbus_LongDecorator.
* @param point A pointer to the Modbus_Point for the low-order word (LSW).
* @param highOrderPoint A pointer to the Modbus_Point for the high-order word (MSW).
*/
Modbus_LongDecorator(Modbus_Point<T>* point, Modbus_Point<T>* highOrderPoint)
: Modbus_PointDecorator<T>(point), _highOrderPoint(highOrderPoint) {}
/**
* @brief Returns the logical type of the point.
* @return Always returns `PointType::LONG`.
*/
PointType getType() const override { return PointType::LONG; }
// --- Housekeeping Methods ---
/** @brief Adds both underlying registers to the Modbus server. */
void addToModbusServer() override {
this->_point->addToModbusServer();
_highOrderPoint->addToModbusServer();
}
// --- Value Getters and Setters ---
/**
* @brief Sets the 32-bit long value by splitting it into two 16-bit words.
* This method is an override for the base class and calls `setLongValue`.
* @param value The integer value to set (will be cast to long).
*/
void setValue(int value) override {
setLongValue(static_cast<long>(value));
}
/**
* @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 (LSW)
_highOrderPoint->setValue((value >> 16) & 0xFFFF); // High Word (MSW)
}
/**
* @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 lsw = this->_point->getValue();
long msw = _highOrderPoint->getValue();
return (msw << 16) | lsw;
}
/** @brief Gets the 32-bit long value, cast to an integer. */
int getValue() const override {
return static_cast<int>(getLongValue());
}
private:
Modbus_Point<T>* _highOrderPoint; /**< @brief Pointer to the Modbus_Point for the high-order word. */
};
#endif

View File

@@ -0,0 +1,100 @@
/**
* @file Modbus_Point.h
* @brief Defines the abstract base class for all Modbus points.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-04
*
* This file contains the definition of the abstract Modbus_Point class, which
* serves as the base for all specific Modbus point types (Coils, Registers, etc.).
* It defines the common interface for interacting with Modbus points.
*/
#ifndef Modbus_Point_h
#define Modbus_Point_h
#include <string.h>
/**
* @enum PointType
* @brief Identifies the logical type of a Modbus point.
*
* This enum is used to distinguish between simple points and decorated points
* that represent more complex data types like floats or longs.
*/
enum class PointType {
GENERIC, /**< @brief A standard, non-decorated point. */
FLOAT, /**< @brief A point decorated to handle 32-bit float values. */
LONG, /**< @brief A point decorated to handle 32-bit long integer values. */
SCALE /**< @brief A point decorated to apply a scaling factor (e.g., 10x). */
};
/**
* @class Modbus_Point
* @brief Abstract base class representing a single point in the Modbus map.
*
* This class defines the common interface and data for all types of Modbus
* points. Concrete implementations (e.g., Modbus_Coil, Modbus_Hreg) and decorators
* must inherit from this class and implement its pure virtual functions.
*/
template<typename T>
class Modbus_Point{
public:
/**
* @brief Constructs a new Modbus_Point object.
* @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.
*/
Modbus_Point(T* server, int address, int value, const char* description);
// --- Getters ---
/** @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. */
int getInitialValue() const { return _value; }
/** @brief Gets the descriptive name of the point. */
const char* getDescription() const { return _description; }
// --- Virtual Interface ---
/** @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 register map. */
virtual void addToModbusServer() = 0;
/** @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 value from the Modbus server. */
virtual int getValue() const = 0;
// --- Dirty Flag ---
/**
* @brief Checks if the point's value has changed since the last write.
* @return True if the value is dirty, false otherwise.
*/
bool isDirty() const { return _dirty; }
/**
* @brief Sets the dirty flag for the point.
* @param dirty The new state of the dirty flag.
*/
void setDirty(bool dirty) { _dirty = dirty; }
/** @brief Virtual destructor to ensure proper cleanup of derived classes. */
virtual ~Modbus_Point() = default;
protected:
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. */
bool _dirty = false; /**< @brief Flag to track if the value has changed and needs to be written. */
};
template<typename T>
Modbus_Point<T>::Modbus_Point(T* server, int address, int value, const char* description)
: _server(server), _address(address), _value(value) {
strncpy(_description, description, sizeof(_description) - 1);
_description[sizeof(_description) - 1] = '\0';
}
#endif

View File

@@ -0,0 +1,82 @@
/**
* @file Modbus_PointDecorator.h
* @brief Defines the base decorator class for Modbus points.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for Modbus_PointDecorator, which is the
* abstract base class for all decorators in the Decorator design pattern.
* It wraps a Modbus_Point and forwards all calls to it by default.
*/
#ifndef Modbus_PointDecorator_h
#define Modbus_PointDecorator_h
#include "Modbus_Point.h"
/**
* @class Modbus_PointDecorator
* @brief An abstract base class for decorating Modbus_Point objects.
*
* This class follows the Decorator pattern. It wraps a `Modbus_Point` object
* and provides a default implementation for all virtual methods that simply
* delegate the call to the wrapped object. Concrete decorators should inherit
* from this class and override the specific methods they need to modify.
*/
template<typename T>
class Modbus_PointDecorator : public Modbus_Point<T>{
public:
/**
* @brief Constructs a new Modbus_PointDecorator object.
*
* Initializes the base Modbus_Point 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 Modbus_Point object to be decorated.
*/
Modbus_PointDecorator(Modbus_Point<T>* point) : Modbus_Point<T>(
point->getServer(),
point->getAddress(),
point->getInitialValue(),
point->getDescription()),
_point(point) {}
/**
* @brief Virtual destructor.
* Does not delete the wrapped `_point` as it does not own it.
*/
virtual ~Modbus_PointDecorator() = 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 `Modbus_Point` object.
*/
void addToModbusServer() override{
_point->addToModbusServer();
}
/**
* @brief Delegates the call to set the point's value.
* Forwards the `setValue` call to the wrapped `Modbus_Point` 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 `Modbus_Point` object.
* @return The value from the wrapped point.
*/
int getValue() const override{
return _point->getValue();
}
protected:
Modbus_Point<T>* _point; /**< @brief Pointer to the wrapped Modbus_Point object. */
};
#endif

View File

@@ -0,0 +1,120 @@
/**
* @file Modbus_PointFactory.h
* @brief Defines the factory function for creating Modbus_Point objects.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file provides the interface for a factory function that simplifies the
* creation of various Modbus_Point types (e.g., Coils, Holding Registers) and
* their decorators (e.g., for scaling, float, or long values).
*/
#ifndef Modbus_PointFactory_h
#define Modbus_PointFactory_h
#include "Modbus_Point.h"
#include "Modbus_Coil.h"
#include "Modbus_Ists.h"
#include "Modbus_Ireg.h"
#include "Modbus_Hreg.h"
#include "Modbus_ScaleDecorator.h"
#include "Modbus_LongDecorator.h"
#include "Modbus_FloatDecorator.h"
#include <Arduino.h>
/**
* @brief Creates and decorates a Modbus_Point object based on its type.
*
* This factory function acts as a centralized point for instantiating different
* concrete Modbus_Point 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.
*
* @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, 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 the newly created Modbus_Point object.
* @retval Modbus_Point* 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<typename T>
Modbus_Point<T>* createModbus_Point(T* server, int category, int address, int value, const char* description);
/**
* @brief Implementation of the Modbus_Point factory function.
*
* This function contains the switch-case logic to determine which concrete
* Modbus_Point class to instantiate and which decorators to apply.
*/
template<typename T>
Modbus_Point<T>* createModbus_Point(T* server, int category, int address, int value, const char* description) {
switch (category) {
case COIL:
Serial.printf("Creating Coil: %s\n", description);
return new Modbus_Coil<T>(server, address, value, description);
case DI:
Serial.printf("Creating Digital Input: %s\n", description);
return new Modbus_Ists<T>(server, address, value, description);
case IR:
Serial.printf("Creating Input Register: %s\n", description);
return new Modbus_Ireg<T>(server, address, value, description);
case IR_10X: {
Serial.printf("Creating Scaled Input Register (10x): %s\n", description);
Modbus_Point<T>* point = new Modbus_Ireg<T>(server, address, value, description);
return new Modbus_ScaleDecorator<T>(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
Modbus_Point<T>* point = new Modbus_Ireg<T>(server, address, 0, description);
Modbus_Point<T>* highOrderPoint = new Modbus_Ireg<T>(server, address + 1, 0, "");
return new Modbus_LongDecorator<T>(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
Modbus_Point<T>* point = new Modbus_Ireg<T>(server, address, 0, description);
Modbus_Point<T>* highOrderPoint = new Modbus_Ireg<T>(server, address + 1, 0, "");
return new Modbus_FloatDecorator<T>(point, highOrderPoint);
}
case HR:
Serial.printf("Creating Holding Register: %s\n", description);
return new Modbus_Hreg<T>(server, address, value, description);
case HR_10x: {
Serial.printf("Creating Scaled Holding Register (10x): %s\n", description);
// Create a base holding register and wrap it with the scaling decorator
Modbus_Point<T>* point = new Modbus_Hreg<T>(server, address, value, description);
return new Modbus_ScaleDecorator<T>(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
Modbus_Point<T>* point = new Modbus_Hreg<T>(server, address, 0, description);
Modbus_Point<T>* highOrderPoint = new Modbus_Hreg<T>(server, address + 1 , 0, "");
return new Modbus_LongDecorator<T>(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
Modbus_Point<T>* point = new Modbus_Hreg<T>(server, address, 0, description);
Modbus_Point<T>* highOrderPoint = new Modbus_Hreg<T>(server, address + 1 , 0, "");
return new Modbus_FloatDecorator<T>(point, highOrderPoint);
}
default:
Serial.printf("ERROR: Unknown Modbus category %d for '%s'\n", category, description);
return nullptr;
}
}
#endif

View File

@@ -0,0 +1,60 @@
/**
* @file Modbus_ScaleDecorator.h
* @brief Defines the Modbus_ScaleDecorator class for scaling Modbus point values.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for a decorator that applies a 10x scaling
* factor to a Modbus point. This is useful for representing decimal values
* in integer registers (e.g., storing 12.3 as 123).
*/
#ifndef Modbus_ScaleDecorator_h
#define Modbus_ScaleDecorator_h
#include "Modbus_PointDecorator.h"
/**
* @class Modbus_ScaleDecorator
* @brief A decorator that multiplies/divides a Modbus point's value by 10.
*
* This class wraps a Modbus_Point and intercepts its `getValue` and `setValue`
* 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<typename T>
class Modbus_ScaleDecorator : public Modbus_PointDecorator<T> {
public:
/**
* @brief Constructs a new Modbus_ScaleDecorator.
* @param point A pointer to the Modbus_Point object to be decorated.
*/
Modbus_ScaleDecorator<T>(Modbus_Point<T>* point) : Modbus_PointDecorator<T>(point) {}
/**
* @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 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;
}
};
#endif