First stable compilation with ModbusRTU and ModbusTCP

This commit is contained in:
2025-09-14 12:01:55 -05:00
commit ac20b82496
59 changed files with 6841 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
/**
* @file Strategy_Behavior.h
* @brief Defines the abstract base class for all behavior strategies.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the interface for the Strategy design pattern. All concrete
* value-generation algorithms (e.g., Ramp, Saw, Random) will inherit from
* the Strategy_Behavior class defined here.
*/
#ifndef strategy_behavior_h
#define strategy_behavior_h
/**
* @class Strategy_Behavior
* @brief Abstract base class for a value-generation strategy.
*
* This class defines the common interface for all strategies. It includes a
* pure virtual `execute` method that must be implemented by concrete strategies
* and a helper method `isReady` to manage the update timing.
*/
class Strategy_Behavior {
public:
/**
* @brief Constructs a new Strategy_Behavior object.
* @param interval The update interval in milliseconds. The strategy will only
* be ready to execute after this interval has passed.
*/
Strategy_Behavior(unsigned long interval)
: _interval(interval), _previousMillis(0) {}
/**
* @brief Virtual destructor.
*/
virtual ~Strategy_Behavior() = default;
/**
* @brief Pure virtual method to execute the strategy's logic.
* Concrete classes must implement this to define their behavior.
* @param currentValue The current value of the point, which can be used by the strategy.
* @return The newly calculated value.
*/
virtual float execute(float currentValue) = 0;
/**
* @brief Checks if the strategy's update interval has elapsed.
* @param currentMillis The current time from `millis()`.
* @return True if the strategy should be executed, false otherwise.
*/
bool isReady(unsigned long currentMillis) {
if (currentMillis - _previousMillis >= _interval) {
_previousMillis = currentMillis;
return true;
}
return false;
}
virtual bool isPID() const { return false; }
protected:
unsigned long _previousMillis; /**< @brief The timestamp of the last execution. */
unsigned long _interval; /**< @brief How often the strategy should run, in milliseconds. */
};
#endif

View File

@@ -0,0 +1,73 @@
/**
* @file Strategy_PID.cpp
* @brief Implementation of the PIDStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-08
*/
#include "Strategy_PID.h"
#include <Arduino.h>
// CORRECTED CONSTRUCTOR
// You should pass in your gains here, but for now we'll add setters and initialize to 0.
PIDStrategy::PIDStrategy(const std::string& setpointName, unsigned long interval, const std::string& inputSensorName)
: Strategy_Behavior(interval), _setpointName(setpointName), _inputSensorName(inputSensorName) {
_kp = -2.0;
_ki = -0.1;
_kd = 0.0;
_input = 0.0;
_lastError = 0.0;
_integral = 0.0;
_lastTime = millis();
}
// It's good practice to have methods to set your gains
void PIDStrategy::setGains(float kp, float ki, float kd) {
_kp = kp;
_ki = ki;
_kd = kd;
}
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.
void PIDStrategy::setInput(float input) {
_input = input;
}
float PIDStrategy::execute(float currentValue) {
unsigned long now = millis();
float timeChange = (float)(now - _lastTime);
if (timeChange <= 0) {
Serial.printf("PID strategy delta time 0.\n");
return 0;
}
_input = currentValue;
float error = _setpoint - _input;
_integral += error * timeChange;
if (_integral > 100.0) _integral = 100.0;
if (_integral < -100.0) _integral = -100.0;
float derivative = (error - _lastError) / timeChange;
float output = (_kp * error) + (_ki * _integral) + (_kd * derivative);
_lastError = error;
_lastTime = now;
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;
}

View File

@@ -0,0 +1,43 @@
// In BaseEmulator/Strategies/Strategy_PID.h
#ifndef PID_Strategy_h
#define PID_Strategy_h
#include "Strategy_Behavior.h"
#include <string>
class PIDStrategy : public Strategy_Behavior {
public:
// MODIFIED CONSTRUCTOR: Takes the setpoint, interval, and the name of the input sensor.
PIDStrategy(const std::string& setpointName, unsigned long interval, const std::string& inputSensorName);
float execute(float currentValue) override;
// Add a getter for the sensor name
std::string getInputSensorName() const { return _inputSensorName; }
std::string getSetpointName() const { return _setpointName; }
// Add this virtual function to easily identify this strategy as a PID
bool isPID() const override { return true; }
// ... (other methods like setSetpoint, setGains)
void setSetpoint(float setpoint);
void setGains(float kp, float ki, float kd);
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
};
#endif

View File

@@ -0,0 +1,51 @@
/**
* @file Strategy_Ramp.cpp
* @brief Implementation of the RampStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*/
#include "Strategy_Ramp.h"
#include <Arduino.h>
/**
* @brief Constructs a new RampStrategy object.
*
* Initializes the ramp strategy by passing the update interval to the
* base Strategy_Behavior class and storing the target value and step.
*
* @param targetValue The destination value for the ramp.
* @param step The amount to increment or decrement on each execution.
* @param interval The time in milliseconds between each value change.
*/
RampStrategy::RampStrategy(float targetValue, float step, unsigned long interval)
: Strategy_Behavior(interval), _targetValue(targetValue), _step(step) {}
/**
* @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. If the target is already reached, it returns the current value.
*
* @param currentValue The current value, used to determine the next step.
* @return The next value in the ramp sequence.
*/
float RampStrategy::execute(float currentValue) {
if (currentValue > _targetValue) {
// Prevent overshooting the target when decrementing
Serial.println("Ramp strategy going down.");
return (currentValue - _step < _targetValue) ? _targetValue : currentValue - _step;
} else if (currentValue < _targetValue) {
// Prevent overshooting the target when incrementing
Serial.println("Ramp strategy going up.");
return (currentValue + _step > _targetValue) ? _targetValue : currentValue + _step;
} else { // currentValue is already at the target
Serial.println("Ramp strategy at target.");
return _targetValue;
}
}
void RampStrategy::setTarget(float targetValue) {
_targetValue = targetValue;
}

View File

@@ -0,0 +1,48 @@
/**
* @file Strategy_Ramp.h
* @brief Defines the RampStrategy class for ramping a value towards a target.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for a behavior strategy that incrementally
* changes a value until it reaches a specified target value.
*/
#ifndef Ramp_Strategy_h
#define Ramp_Strategy_h
#include "Strategy_Behavior.h"
/**
* @class RampStrategy
* @brief A strategy that moves a value towards a target by a fixed step.
*
* This class implements the Strategy_Behavior interface to produce a ramping
* effect. On each `execute` call, it increments or decrements the current
* value by a fixed step until the target value is reached.
*/
class RampStrategy : public Strategy_Behavior {
public:
/**
* @brief Constructs a new RampStrategy object.
* @param targetValue The destination value for the ramp.
* @param step The amount to increment or decrement on each execution.
* @param interval The time in milliseconds between each value change.
*/
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.
*/
void setTarget(float targetValue);
/**
* @brief Executes the strategy to get the next value in the ramp sequence.
* @param currentValue The current value, used to determine the next step.
* @return The next value in the ramp sequence.
*/
float execute(float currentValue) override;
private:
float _targetValue; /**< @brief The target value that the strategy will ramp towards. */
float _step; /**< @brief The value to add or subtract on each execution. */
};
#endif

View File

@@ -0,0 +1,36 @@
/**
* @file Strategy_Random.cpp
* @brief Implementation of the RandomStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*/
#include "Strategy_Random.h"
#include <cstdlib>
#include <Arduino.h>
/**
* @brief Constructs a new RandomStrategy object.
*
* Initializes the random strategy by passing the update interval to the
* base Strategy_Behavior class.
*
* @param interval The time in milliseconds between each value generation.
*/
RandomStrategy::RandomStrategy(unsigned long interval)
: Strategy_Behavior(interval) {}
/**
* @brief Generates a new random value between 0.0 and 100.0.
*
* This method calculates a random integer between 0 and 1000 and divides
* it by 10.0 to produce a floating-point number. The `currentValue`
* parameter is ignored.
*
* @param currentValue The current value of the Modbus point (ignored).
* @return A random floating-point number between 0.0 and 100.0.
*/
float RandomStrategy::execute(float currentValue) {
int randomNum = rand() % 1001;
Serial.println("Random strategy.");
return randomNum / 10.0;
}

View File

@@ -0,0 +1,37 @@
/**
* @file Strategy_Random.h
* @brief Defines the RandomStrategy class for generating random values.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for a behavior strategy that generates
* a random floating-point number between 0.0 and 100.0.
*/
#ifndef Random_Strategy_h
#define Random_Strategy_h
#include "Strategy_Behavior.h"
/**
* @class RandomStrategy
* @brief A strategy that generates a random value on each execution.
*
* This class implements the Strategy_Behavior interface to produce a random
* value. Each time `execute` is called, it returns a new random float
* between 0.0 and 100.0.
*/
class RandomStrategy : public Strategy_Behavior {
public:
/**
* @brief Constructs a new RandomStrategy object.
* @param interval The time in milliseconds between each value generation.
*/
RandomStrategy(unsigned long interval);
/**
* @brief Executes the strategy to generate a new random value.
* @param currentValue The current value of the Modbus point (ignored).
* @return A random floating-point number between 0.0 and 100.0.
*/
float execute(float currentValue) override;
};
#endif

View File

@@ -0,0 +1,54 @@
/**
* @file Strategy_Saw.cpp
* @brief Implementation of the SawStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*/
#include "Strategy_Saw.h"
#include <Arduino.h>
/**
* @brief Constructs a new SawStrategy object.
*
* Initializes the sawtooth wave strategy by passing the update interval to the
* base Strategy_Behavior class and storing the wave's parameters.
*
* @param minValue The lower bound of the sawtooth wave.
* @param maxValue The upper bound of the sawtooth wave.
* @param step The amount to increment or decrement on each execution.
* @param interval The time in milliseconds between each value change.
*/
SawStrategy::SawStrategy(float minValue, float maxValue, float step, unsigned long interval)
: Strategy_Behavior(interval), _minValue(minValue), _maxValue(maxValue), _step(step) {}
void SawStrategy::setMinValue(float minValue) {
_minValue = minValue;
}
void SawStrategy::setMaxValue(float maxValue) {
_maxValue = maxValue;
}
/**
* @brief Calculates the next value in the sawtooth wave sequence.
*
* This method checks if the current value has reached the upper or lower
* bounds and reverses the direction if necessary. It then returns the
* current value incremented or decremented by the step amount.
*
* @param currentValue The current value, used to determine the next step.
* @return The next value in the sawtooth sequence.
*/
float SawStrategy::execute(float currentValue) {
if (currentValue >= _maxValue) {
_goingUp = false;
} else if (currentValue <= _minValue) {
_goingUp = true;
}
if (_goingUp) {
Serial.println("Saw Strategy going up.");
return currentValue + _step;
} else {
Serial.println("Saw Strategy going down.");
return currentValue - _step;
}
}

View File

@@ -0,0 +1,54 @@
/**
* @file Strategy_Saw.h
* @brief Defines the SawStrategy class for generating a sawtooth wave pattern.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*
* This file contains the definition for a behavior strategy that creates a
* sawtooth (or triangular) wave. The value ramps up from a minimum to a
* maximum and then ramps back down, repeating the cycle.
*/
#ifndef Saw_Strategy_h
#define Saw_Strategy_h
#include "Strategy_Behavior.h"
/**
* @class SawStrategy
* @brief A strategy that generates a value that moves up and down between two bounds.
*
* This class implements the Strategy_Behavior interface to produce a sawtooth
* wave. On each `execute` call, it increments or decrements the current value
* by a fixed step. The direction reverses when the value hits the minimum or
* maximum bound.
*/
class SawStrategy : public Strategy_Behavior {
public:
/**
* @brief Constructs a new SawStrategy object.
* @param minValue The lower bound of the sawtooth wave.
* @param maxValue The upper bound of the sawtooth wave.
* @param step The amount to increment or decrement on each execution.
* @param interval The time in milliseconds between each value change.
*/
SawStrategy(float minValue, float maxValue, float step, unsigned long interval);
/**
* @brief Executes the strategy to get the next value in the sawtooth wave.
* @param currentValue The current value, used to determine the next step.
* @return The next value in the sawtooth sequence.
*/
float execute(float currentValue) override;
void setMinValue(float minValue);
void setMaxValue(float maxValue);
private:
float _minValue; /**< @brief The lower bound of the sawtooth wave. */
float _maxValue; /**< @brief The upper bound of the sawtooth wave. */
float _step; /**< @brief The value to add or subtract on each execution. */
bool _goingUp = true; /**< @brief Tracks the current direction of the wave (up or down). */
};
#endif

View File

@@ -0,0 +1,45 @@
/**
* @file Strategy_SingleValue.cpp
* @brief Implementation of the SingleValueStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*/
#include "Strategy_SingleValue.h"
#include <cstdlib>
#include <Arduino.h>
/**
* @brief Constructs a new SingleValueStrategy object.
*
* Initializes the strategy by passing the update interval to the base
* Strategy_Behavior class and storing the base setpoint value.
*
* @param setpoint The base value around which noise will be generated.
* @param interval The time in milliseconds between each value generation.
*/
SingleValueStrategy::SingleValueStrategy(float setpoint, float noiseMagnitude, unsigned long interval)
: Strategy_Behavior(interval), _setpoint(setpoint), _noiseMagnitude(noiseMagnitude) {}
void SingleValueStrategy::setSetpoint(float setpoint) {
_setpoint = setpoint;
}
/**
* @brief Generates a new value by adding random noise to the setpoint.
*
* This method calculates a random noise value between -10.0 and +10.0 and
* adds it to the stored setpoint. The `currentValue` parameter is ignored.
*
* @param currentValue The current value of the Modbus point (ignored).
* @return The setpoint with added random noise.
*/
float SingleValueStrategy::execute(float currentValue) {
if(_noiseMagnitude <= 0){
Serial.println("Single value strategy static.");
return _setpoint;
}
int noiseInt = rand() % 201;
noiseInt -= 100;
float noise = (noiseInt / 100) * _noiseMagnitude;
Serial.println("Single value strategy with noise.");
return _setpoint + noise;
}

View File

@@ -0,0 +1,44 @@
/**
* @file Strategy_SingleValue.h
* @brief Defines the SingleValueStrategy class for setup a value with 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.
*/
#ifndef SingleValue_strategy_h
#define SingleValue_strategy_h
#include "Strategy_Behavior.h"
/**
* @class SingleValueStrategy
* @brief A strategy that sets a value to a setpoint and generates noise around it.
*
* 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
*/
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.
*/
SingleValueStrategy(float setpoint, float noiseMagnitude, unsigned long interval);
/**
* @brief Executes the strategy to get the next random value around 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.
*/
float execute(float currentValue) override;
void setSetpoint(float setpoint);
private:
float _setpoint;
float _noiseMagnitude;
};
#endif

View File

@@ -0,0 +1,44 @@
/**
* @file Strategy_Square.cpp
* @brief Implementation of the SquareStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*/
#include "Strategy_Square.h"
#include <Arduino.h>
/**
* @brief Constructs a new SquareStrategy object.
*
* Initializes the square wave strategy by passing the update interval to the
* base Strategy_Behavior class and storing the lower and upper bounds.
*
* @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.
*/
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.
*/
void SquareStrategy::setLowerValue(float lowerValue) {
_lowerValue = lowerValue;
}
void SquareStrategy::setUpperValue(float upperValue) {
_upperValue = upperValue;
}
float SquareStrategy::execute(float currentValue) {
_upState = !_upState;
if(_upState){
Serial.println("Square Strategy high state.");
return _upperValue;
} else {
Serial.println("Square Strategy low state.");
return _lowerValue;
}
}

View File

@@ -0,0 +1,45 @@
/**
* @file Strategy_Square.h
* @brief Defines the SquareStrategy class for generating a square wave pattern.
* @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.
*/
#ifndef square_strategy_h
#define square_strategy_h
#include "Strategy_Behavior.h"
/**
* @class SquareStrategy
* @brief A strategy that alternates between a lower and an upper 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`.
*/
class SquareStrategy : 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.
*/
SquareStrategy(float lowerValue, float upperValue, unsigned long interval);
/**
* @brief Executes the strategy to get the next value in the square wave.
* @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.
*/
float execute(float currentValue) override;
void setLowerValue(float lowerValue);
void setUpperValue(float upperValue);
private:
float _lowerValue; /**< @brief The lower bound of the square wave. */
float _upperValue; /**< @brief The upper bound of the square wave. */
bool _upState = true; /**< @brief The internal state to track whether to return the upper or lower value. */
};
#endif

View File

@@ -0,0 +1,38 @@
/**
* @file Strategy_Totalizer.cpp
* @brief Implementation of the TotalizerStrategy class.
* @author Emmanuel Hernandez Cruz
* @date 2025-09-05
*/
#include "Strategy_Totalizer.h"
#include <cstdlib>
#include <Arduino.h>
/**
* @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.
*
* @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.
*/
TotalizerStrategy::TotalizerStrategy(unsigned long interval)
: Strategy_Behavior(interval) {
int randomNum = rand() % 1001;
_currentValue = randomNum;
}
/**
* @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 TotalizerStrategy::execute(float currentValue) {
_currentValue += 1;
if (_currentValue >60000) {
_currentValue = 0;
}
Serial.println("Totalizer strategy adding up.");
return _currentValue;
}

View File

@@ -0,0 +1,42 @@
/**
* @file Strategy_Square.h
* @brief Defines the SquareStrategy class for generating a square wave pattern.
* @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.
*/
#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.
*
* 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`.
*/
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.
*/
TotalizerStrategy(unsigned long interval);
/**
* @brief Executes the strategy to get the next value in the square wave.
* @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.
*/
float execute(float currentValue) override;
private:
float _currentValue; /**< @brief The lower bound of the square wave. */
};
#endif