10 KiB
Modbus Logic Engine (MB_SCRIPT) Functional Testing Strategy
1. Objective
To verify the functional correctness of the ModbusLogicEngine component (enabled by the ENABLE_MB_SCRIPT define). This includes:
- Correct configuration of logic rules via Modbus.
- Accurate evaluation of rule conditions based on Modbus register/coil values.
- Proper execution of defined actions (writing registers/coils, calling component methods).
- Correct reporting of rule status, trigger timestamps, and trigger counts via Modbus.
- Handling of various error conditions.
2. Scope
This strategy focuses on black-box functional testing from the perspective of a Modbus client interacting with the device. It does not cover unit testing of individual ModbusLogicEngine methods or performance/stress testing (which may have separate test plans).
3. Approach
Testing will primarily utilize the existing npm scripts which wrap Python helper scripts to interact with the device over Modbus TCP.
- Configuration: Rules will be configured by writing to the specific Modbus holding registers allocated to the Logic Engine (
MODBUS_LOGIC_RULES_STARTand subsequent offsets defined insrc/ModbusLogicEngine.h). - Triggering: Rule conditions will be triggered by writing appropriate values to the source Modbus holding registers or coils specified in the rule's condition.
- Verification:
- Action outcomes will be verified by reading the target Modbus holding registers or coils.
- Rule status, timestamps, and trigger counts will be verified by reading the corresponding status registers for the rule.
- Internal behavior and potential errors can be monitored using device logs (
npm run build:monitorornpm run debug:serial).
- No New Scripts: This strategy aims to use only the pre-existing
npmscripts for Modbus interaction.
4. Tools
- Modbus Read/Write:
npm run modbus:read:holding -- --address <addr>npm run modbus:write:holding -- --address <addr> --value <val>npm run modbus:read:coil -- --address <addr>npm run modbus:write:coil -- --address <addr> --value <0|1>
- Logging:
npm run build:monitor(Live serial monitoring)npm run debug:serial(Fetch buffered logs via REST API)
- Reference:
src/ModbusLogicEngine.h(for register offsets, enums)src/config-modbus.h(forMODBUS_LOGIC_RULES_STARTaddress)
5. Prerequisites
- Firmware compiled with
#define ENABLE_MB_SCRIPTinconfig.hand flashed to the ESP32. - Device connected to the network and accessible via its IP address or mDNS name (
modbus-esp32.localby default). - Python environment configured correctly to run the scripts in the
scripts/directory. - Knowledge of the Modbus register mapping for the Logic Engine (starting address + offsets).
6. Test Cases
Let RULE_START = MODBUS_LOGIC_RULES_START.
Let RULE_0_BASE = RULE_START.
Let RULE_1_BASE = RULE_START + LOGIC_ENGINE_REGISTERS_PER_RULE.
Offsets are defined in ModbusLogicEngineOffsets.
(Note: Choose suitable, otherwise unused Modbus addresses for source/target registers/coils for testing)
TC 1: Basic Rule - Write Holding Register
- Configure:
- Write
1toRULE_0_BASE + ENABLED. - Write
3(REG_HOLDING) toRULE_0_BASE + COND_SRC_TYPE. - Write
2000toRULE_0_BASE + COND_SRC_ADDR. - Write
0(EQUAL) toRULE_0_BASE + COND_OPERATOR. - Write
123toRULE_0_BASE + COND_VALUE. - Write
3(WRITE_HOLDING_REGISTER) toRULE_0_BASE + COMMAND_TYPE. - Write
2001toRULE_0_BASE + COMMAND_TARGET. - Write
456toRULE_0_BASE + COMMAND_PARAM1(Value to write). - Write
0toRULE_0_BASE + COMMAND_PARAM2(Unused). - Write
0toRULE_0_BASE + FLAGS.
- Write
- Trigger: Write
123to Modbus address2000. - Verify:
- Read address
2001. Expected:456. - Read
RULE_0_BASE + LAST_STATUS. Expected:0(MB_Error::Success). - Read
RULE_0_BASE + TRIGGER_COUNT. Expected:1.
- Read address
TC 2: Condition Operator - Not Equal
- Configure: Similar to TC 1, but:
- Write
1(NOT_EQUAL) toRULE_0_BASE + COND_OPERATOR. - Write
123toRULE_0_BASE + COND_VALUE.
- Write
- Trigger 1: Write
123to address2000. - Verify 1: Read address
2001. Expected: Unchanged from previous state (action should not run). - Trigger 2: Write
124to address2000. - Verify 2:
- Read address
2001. Expected:456. - Read
RULE_0_BASE + LAST_STATUS. Expected:0(MB_Error::Success). - Read
RULE_0_BASE + TRIGGER_COUNT. Expected: Incremented. - (Repeat for other operators:
<,<=,>,>=)
- Read address
TC 3: Source Type - Coil
- Configure: Similar to TC 1, but:
- Write
2(REG_COIL) toRULE_0_BASE + COND_SRC_TYPE. - Write
100(Test Coil Addr) toRULE_0_BASE + COND_SRC_ADDR. - Write
1toRULE_0_BASE + COND_VALUE(Condition is Coil ON).
- Write
- Trigger: Write
1to Coil address100. - Verify:
- Read address
2001. Expected:456. - Read
RULE_0_BASE + LAST_STATUS. Expected:0(MB_Error::Success).
- Read address
TC 4: Action Type - Write Coil
- Configure: Similar to TC 1, but:
- Write
2(WRITE_COIL) toRULE_0_BASE + COMMAND_TYPE. - Write
101toRULE_0_BASE + COMMAND_TARGET. - Write
1toRULE_0_BASE + COMMAND_PARAM1(Value: ON). - Write
0toRULE_0_BASE + COMMAND_PARAM2(Unused).
- Write
- Trigger: Write
123to address2000. - Verify:
- Read Coil address
101. Expected:1. - Read
RULE_0_BASE + LAST_STATUS. Expected:0(MB_Error::Success).
- Read Coil address
TC 5: Action Type - Call Component Method (Requires Setup)
- Prerequisite: A method must be registered with the
ModbusLogicEnginethat has a verifiable side-effect readable via Modbus. Example: A simple method inPHAppthat increments a counter stored in a Modbus register (e.g., address 3000).// In PHApp.h (or a test component) short testMethod(short p1, short p2) { testMethodCounter += p1; // Use p1 (arg1 from rule) Log.infoln("Test Method Called! Arg1=%d, Counter: %d", p1, testMethodCounter); return E_OK; } uint16_t testMethodCounter = 0; // In PHApp::setup() or where ModbusLogicEngine is initialized logicEngine->registerMethod(this->id, 1, // Use app ID and method ID 1 std::bind(&PHApp::testMethod, this, std::placeholders::_1, std::placeholders::_2)); // In PHApp::readNetworkValue() if (address == 3000) return testMethodCounter;
- Configure: Similar to TC 1, but:
- Write
100(CALL_COMPONENT_METHOD) toRULE_0_BASE + COMMAND_TYPE. - Write
app->idtoRULE_0_BASE + COMMAND_TARGET(Component ID). - Write
1toRULE_0_BASE + COMMAND_PARAM1(Method ID). - Write
5toRULE_0_BASE + COMMAND_PARAM2(Argument 1).
- Write
- Initial Read: Read address
3000. Note the value (e.g.,X). - Trigger: Write
123to address2000. - Verify:
- Read address
3000. Expected:X + 5. - Read
RULE_0_BASE + LAST_STATUS. Expected:0(MB_Error::Success). - Check logs (
build:monitor) for "Test Method Called! Arg1=5".
- Read address
TC 6: Rule Enable/Disable
- Configure: Configure rule as in TC 1.
- Disable: Write
0toRULE_0_BASE + ENABLED. - Trigger: Write
123to address2000. - Verify (Disabled): Read address
2001. Expected: Unchanged. Trigger count should not increment. - Enable: Write
1toRULE_0_BASE + ENABLED. - Trigger: Write
123to address2000. - Verify (Enabled): Read address
2001. Expected:456. Trigger count should increment.
TC 7: Error - Invalid Condition Source Address
- Configure: Similar to TC 1, but:
- Write
9999(Invalid/Unregistered address) toRULE_0_BASE + COND_SRC_ADDR.
- Write
- Trigger: Let the engine loop run.
- Verify: Read
RULE_0_BASE + LAST_STATUS. Expected:2(MB_Error::IllegalDataAddress).
TC 8: Error - Invalid Action Target Address (Write)
- Configure: Similar to TC 1, but:
- Write
9998(Invalid/Unregistered address) toRULE_0_BASE + COMMAND_TARGET.
- Write
- Trigger: Write
123to address2000. - Verify: Read
RULE_0_BASE + LAST_STATUS. Expected:4(MB_Error::ServerDeviceFailure).
TC 9: Error - Invalid Action Target Method (Call)
- Configure: Similar to TC 5, but:
- Write
99(Non-existent Method ID) toRULE_0_BASE + COMMAND_PARAM1.
- Write
- Trigger: Write
123to address2000. - Verify: Read
RULE_0_BASE + LAST_STATUS. Expected:2(MB_Error::IllegalDataAddress).
TC 10: Status/Counter Reset
- Configure & Trigger: Perform TC 1.
- Verify Count: Read
RULE_0_BASE + TRIGGER_COUNT. Expected:1(or current count). - Reset Counter: Write
0toRULE_0_BASE + TRIGGER_COUNT. - Verify Reset: Read
RULE_0_BASE + TRIGGER_COUNT. Expected:0. - Trigger Again: Write
123to address2000. - Verify Increment: Read
RULE_0_BASE + TRIGGER_COUNT. Expected:1.
TC 11: Debug Flag
- Configure: Configure as in TC 1, but:
- Write
RULE_FLAG_DEBUG(value 1) toRULE_0_BASE + FLAGS.
- Write
- Trigger: Write
123to address2000. - Verify:
- Check logs (
build:monitor). Expected: Verbose logs like "MLE Eval [0]: ...", "MLE Action [0]: ...". - Read address
2001. Expected:456.
- Check logs (
TC 12: Receipt Flag
- Configure: Configure as in TC 1, but:
- Write
RULE_FLAG_RECEIPT(value 2) toRULE_0_BASE + FLAGS.
- Write
- Trigger: Write
123to address2000. - Verify:
- Check logs (
build:monitor). Expected: Info log "MLE: Rule 0 action successful.". - Read address
2001. Expected:456.
- Check logs (
TC 13: Debug + Receipt Flags
- Configure: Configure as in TC 1, but:
- Write
RULE_FLAG_DEBUG | RULE_FLAG_RECEIPT(value 3) toRULE_0_BASE + FLAGS.
- Write
- Trigger: Write
123to address2000. - Verify:
- Check logs (
build:monitor). Expected: Both verbose debug logs and the receipt log. - Read address
2001. Expected:456.
- Check logs (