200 lines
8.2 KiB
C++
200 lines
8.2 KiB
C++
#ifndef MODBUS_LOGIC_ENGINE_H
|
|
#define MODBUS_LOGIC_ENGINE_H
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef ENABLE_MB_SCRIPT
|
|
|
|
#include <Component.h>
|
|
#include <ArduinoLog.h>
|
|
#include <vector>
|
|
#include <cstdint> // For uint16_t etc.
|
|
#include <modbus/ModbusTypes.h>
|
|
|
|
// Forward declarations
|
|
class PHApp; // Assuming PHApp provides access to other components/Modbus
|
|
|
|
// --- Configuration Constants (Define these in config-modbus.h or similar) ---
|
|
#ifndef MAX_LOGIC_RULES
|
|
#define MAX_LOGIC_RULES 8 // Default number of rules
|
|
#endif
|
|
|
|
#ifndef LOGIC_ENGINE_REGISTERS_PER_RULE
|
|
#define LOGIC_ENGINE_REGISTERS_PER_RULE 13 // Now 13 (removed Param3)
|
|
#endif
|
|
|
|
#ifndef MODBUS_LOGIC_RULES_START
|
|
#define MODBUS_LOGIC_RULES_START 1000 // Example starting address
|
|
#endif
|
|
// --- End Configuration Constants ---
|
|
|
|
// Define constants for rule structure offsets (matching mb-lang.md)
|
|
namespace ModbusLogicEngineOffsets {
|
|
// --- Configuration (8 registers) ---
|
|
const short ENABLED = 0;
|
|
const short COND_SRC_TYPE = 1;
|
|
const short COND_SRC_ADDR = 2;
|
|
const short COND_OPERATOR = 3;
|
|
const short COND_VALUE = 4;
|
|
const short COMMAND_TYPE = 5;
|
|
const short COMMAND_TARGET = 6;
|
|
// Parameters below depend on COMMAND_TYPE:
|
|
// - WRITE_HOLDING_REGISTER: PARAM1=Value
|
|
// - WRITE_COIL: PARAM1=Value (0 or 1)
|
|
// - CALL_COMPONENT_METHOD: PARAM1=MethodID, PARAM2=Arg1
|
|
const short COMMAND_PARAM1 = 7;
|
|
const short COMMAND_PARAM2 = 8;
|
|
// Removed PARAM3
|
|
|
|
// --- Status & Flags (Moved to end - 4 registers) ---
|
|
const short FLAGS = 9; // Moved
|
|
const short LAST_STATUS = 10; // Moved
|
|
const short LAST_TRIGGER_TS = 11; // Moved
|
|
const short TRIGGER_COUNT = 12; // Moved
|
|
}
|
|
|
|
// --- Rule Flags (Bitmasks for FLAGS register) ---
|
|
#define RULE_FLAG_DEBUG (1 << 0) // Enable verbose debug logging for this rule
|
|
#define RULE_FLAG_RECEIPT (1 << 1) // Enable logging upon successful trigger/action
|
|
|
|
// Define constants for condition operators
|
|
enum class ConditionOperator : uint16_t {
|
|
EQUAL = 0,
|
|
NOT_EQUAL = 1,
|
|
LESS_THAN = 2,
|
|
LESS_EQUAL = 3,
|
|
GREATER_THAN = 4,
|
|
GREATER_EQUAL = 5
|
|
};
|
|
|
|
// Define constants for command types
|
|
// Partially aligned with E_MB_OpType from ModbusTypes.h
|
|
enum class CommandType : uint16_t {
|
|
NONE = 0,
|
|
// Use standard op types where possible (Values from E_MB_OpType)
|
|
WRITE_COIL = 2, // Matches E_MB_OpType::MB_WRITE_COIL
|
|
WRITE_HOLDING_REGISTER = 3, // Matches E_MB_OpType::MB_WRITE_REGISTER
|
|
// Custom command type (value > standard op types)
|
|
CALL_COMPONENT_METHOD = 100
|
|
};
|
|
|
|
// Type alias for rule status using standard Modbus errors
|
|
using RuleStatus = MB_Error;
|
|
|
|
// Structure to hold the configuration and state of a single rule
|
|
struct LogicRule {
|
|
// --- Configuration (Set via Modbus) ---
|
|
// Store config registers directly (Enabled to Param2)
|
|
uint16_t config[LOGIC_ENGINE_REGISTERS_PER_RULE - 4]; // Size now 13-4 = 9
|
|
|
|
// Helper accessors for configuration
|
|
bool isEnabled() const { return config[ModbusLogicEngineOffsets::ENABLED] == 1; }
|
|
RegisterState::E_RegType getCondSourceType() const { return static_cast<RegisterState::E_RegType>(config[ModbusLogicEngineOffsets::COND_SRC_TYPE]); }
|
|
uint16_t getCondSourceAddr() const { return config[ModbusLogicEngineOffsets::COND_SRC_ADDR]; }
|
|
ConditionOperator getCondOperator() const { return static_cast<ConditionOperator>(config[ModbusLogicEngineOffsets::COND_OPERATOR]); }
|
|
uint16_t getCondValue() const { return config[ModbusLogicEngineOffsets::COND_VALUE]; }
|
|
CommandType getCommandType() const { return static_cast<CommandType>(config[ModbusLogicEngineOffsets::COMMAND_TYPE]); }
|
|
uint16_t getCommandTarget() const { return config[ModbusLogicEngineOffsets::COMMAND_TARGET]; }
|
|
uint16_t getCommandParam1() const { return config[ModbusLogicEngineOffsets::COMMAND_PARAM1]; }
|
|
uint16_t getCommandParam2() const { return config[ModbusLogicEngineOffsets::COMMAND_PARAM2]; }
|
|
|
|
// --- Status & Flags (Read/Write via Modbus, updated internally) ---
|
|
// Note: These are conceptually separate but stored contiguously in Modbus address space.
|
|
// The internal representation uses separate members for status/timestamp/count
|
|
// and reads/writes the FLAGS register (config[9]) via Modbus.
|
|
uint16_t getFlags() const { return config[ModbusLogicEngineOffsets::FLAGS]; }
|
|
bool isDebugEnabled() const { return (getFlags() & RULE_FLAG_DEBUG) != 0; }
|
|
bool isReceiptEnabled() const { return (getFlags() & RULE_FLAG_RECEIPT) != 0; }
|
|
|
|
void setConfigValue(short offset, uint16_t value) {
|
|
// Size check updated for new register count (9 config registers)
|
|
if (offset >= 0 && offset < (LOGIC_ENGINE_REGISTERS_PER_RULE - 4)) {
|
|
config[offset] = value;
|
|
} else {
|
|
Log.warningln(F("MLE: Attempt to write invalid config offset %d"), offset);
|
|
}
|
|
}
|
|
|
|
// Internal state members (not directly part of config array)
|
|
RuleStatus lastStatus = RuleStatus::Success;
|
|
uint32_t lastTriggerTimestamp = 0;
|
|
uint16_t triggerCount = 0;
|
|
|
|
LogicRule() {
|
|
// Initialize configuration registers (0-8)
|
|
for(int i = 0; i < (LOGIC_ENGINE_REGISTERS_PER_RULE - 4); ++i) {
|
|
config[i] = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
class ModbusLogicEngine : public Component {
|
|
public:
|
|
// Define the callable method signature: takes two shorts, returns a short (e.g., error code)
|
|
// Using std::function allows storing lambdas, member functions, etc.
|
|
// NOTE: This internal registration is used for CALL_COMPONENT_METHOD.
|
|
// It is separate from the Bridge mechanism used for serial commands.
|
|
using CallableMethod = std::function<short(short, short)>;
|
|
|
|
// Constructor - Requires access to PHApp to interact with other components/Modbus
|
|
ModbusLogicEngine(PHApp* ownerApp); // Pass PHApp reference
|
|
|
|
virtual ~ModbusLogicEngine() = default;
|
|
|
|
short setup() override;
|
|
short loop() override;
|
|
|
|
// Handle Modbus reads/writes for rule configuration and status
|
|
short mb_tcp_read(short address) override;
|
|
short mb_tcp_write(short address, short value) override;
|
|
|
|
/**
|
|
* @brief Registers a method that can be called by the logic engine.
|
|
*
|
|
* @param componentId A unique ID for the component exposing the method.
|
|
* @param methodId A unique ID for the method within that component.
|
|
* @param method The function object (lambda, bound member function) to call.
|
|
* @return True if registration was successful, false otherwise (e.g., duplicate ID).
|
|
*/
|
|
bool registerMethod(uint16_t componentId, uint16_t methodId, CallableMethod method);
|
|
|
|
private:
|
|
PHApp* app; // Pointer to the main application instance
|
|
bool initialized_; // Flag to track initialization state
|
|
|
|
// Storage for all logic rules
|
|
std::vector<LogicRule> rules;
|
|
|
|
// Registry for callable methods: Map<(ComponentID << 16) | MethodID, Function>
|
|
// Combining IDs into a single 32-bit key for the map.
|
|
std::map<uint32_t, CallableMethod> callableMethods;
|
|
|
|
// --- Internal Logic ---
|
|
unsigned long lastLoopTime = 0;
|
|
const unsigned long loopInterval = 100; // Evaluate rules every 100ms (adjust as needed)
|
|
|
|
bool evaluateCondition(LogicRule& rule);
|
|
bool performAction(LogicRule& rule);
|
|
|
|
// --- Helper Methods ---
|
|
// Reads the value required for a rule's condition
|
|
// Updated signature to use RegisterState::E_RegType
|
|
bool readConditionSourceValue(RegisterState::E_RegType type, uint16_t address, uint16_t& value);
|
|
// Performs the write action (Register or Coil)
|
|
// Updated signature to use CommandType
|
|
bool performWriteAction(CommandType type, uint16_t address, uint16_t value);
|
|
// Performs the method call action (now only 2 params)
|
|
bool performCallAction(uint16_t componentId, uint16_t methodId, uint16_t arg1);
|
|
|
|
// Helper to calculate rule index and offset from Modbus address
|
|
bool getRuleInfoFromAddress(short address, int& ruleIndex, short& offset);
|
|
|
|
// Helper to update status fields
|
|
// Updated signature to use RuleStatus (MB_Error)
|
|
void updateRuleStatus(LogicRule& rule, RuleStatus status);
|
|
};
|
|
|
|
#endif // ENABLE_MB_SCRIPT
|
|
|
|
#endif // MODBUS_LOGIC_ENGINE_H
|