/** * @file Equipment.h * @brief Defines the main Equipment class for the device emulator. * @author Emmanuel Hernandez Cruz * @date 2025-09-02 * * This file contains the definition for the Equipment class, which acts as the * central context for the State design pattern. It manages the current state * of the device and holds all of its Modbus points. */ #ifndef Equipment_h #define Equipment_h #include #include #include #include #include "States/State_Standby.h" // Forward Declarations template class State; template class Modbus_Point; /** * @class Equipment * @brief The main class representing the emulated device. * * This class orchestrates the device's behavior. It holds a collection of all * Modbus points and manages the device's current operational state (e.g., * Standby, Running) by delegating actions to a concrete State object. */ template 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(); /** @brief Delegates the enter state logic to the current state object. */ void enterState(); /** @brief Delegates the exit state logic to the current state object. */ void exitState(); /** * @brief Sets a simple integer identifier for the current state. * @param stateId The integer ID representing the state. */ void setState(int stateId); /** * @brief Gets the simple integer identifier for the current state. * @return The integer ID of the state. */ int getState(); /** * @brief Transitions the equipment to a new state. * Handles exiting the old state, deleting it, and entering the new one. * @param newState A pointer to the new State object. The Equipment takes ownership. */ void changeState(State* newState); /** * @brief Adds a Modbus point to the equipment's internal map. * @param description The unique string description used as a key. * @param point A pointer to the Modbus_Point object. */ void addModbus_Point(const std::string& description, Modbus_Point* point); /** * @brief Retrieves a Modbus point by its description. * @param description The string key for the Modbus point. * @return A pointer to the Modbus_Point object, or nullptr if not found. */ Modbus_Point* getModbus_Point(const std::string& description); /** * @brief Sets the value of a specific Modbus point. * @param description The string key for the Modbus point. * @param value The value to set. Note: This float may be truncated or cast * depending on the underlying point's `setValue` implementation. */ void setModbus_Point(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. */ T* _server; }; template Equipment::Equipment() : _server(nullptr) { this->_state = new StandbyState(); 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) { this->_state = new StandbyState(); this->_state->enterState(this); } /** * @brief The main update loop for the equipment. * * This method delegates the update logic to the current state object. If the * state's update method returns a pointer to a new state, this method * triggers a state transition. */ template void Equipment::update() { State* newState = this->_state->update(this); if (newState != nullptr) { changeState(newState); } } /** * @brief Delegates the enter state logic to the current state object. */ template void Equipment::enterState() { this->_state->enterState(this); } /** * @brief Delegates the exit state logic to the current state object. */ template void Equipment::exitState() { this->_state->exitState(this); } /** * @brief Adds a Modbus point to the equipment's internal collections. * The point is added to a map for quick lookup by description and to a * vector for simple iteration. * @param description The unique string description used as a key. * @param point A pointer to the Modbus_Point object. */ template void Equipment::addModbus_Point(const std::string& description, Modbus_Point* point) { this->_points[description] = point; } /** * @brief Retrieves a Modbus point by its description. * @param description The string key for the Modbus point. * @return A pointer to the Modbus_Point object, or nullptr if not found. */ template Modbus_Point* Equipment::getModbus_Point(const std::string& description) { auto it = this->_points.find(description); if (it != this->_points.end()) { return it->second; } return nullptr; } /** * @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. This float is cast to an int before being passed. */ template void Equipment::setModbus_Point(const std::string& description, float value) { Modbus_Point* point = getModbus_Point(description); if (point != nullptr) { point->setValue(value); } } /** * @brief Gets the simple integer identifier for the current state. * @return The integer ID of the state. */ template int Equipment::getState() { return _stateId; } /** * @brief Sets a simple integer identifier for the current state. * @param stateId The integer ID representing the state. */ template void Equipment::setState(int stateId) { this->_stateId = stateId; } /** * @brief Transitions the equipment to a new state. * * This method handles the full lifecycle of a state transition: it calls * `exitState` on the current state, deletes the old state object to prevent * memory leaks, assigns the new state, and finally calls `enterState` on the * new state. * * @param newState A pointer to the new State object. The Equipment takes ownership. */ template void Equipment::changeState(State* newState) { if (this->_state != nullptr) { this->_state->exitState(this); delete this->_state; } this->_state = newState; if (this->_state != nullptr) { this->_state->enterState(this); } } #endif