refactor(modbus): switch to native Modbus TCP protocol

Switch from Modbus RTU over TCP to native Modbus TCP based on hardware
testing. Uses standard MBAP header (no CRC16), port 502, and TCP-only
tokio-modbus feature for simpler implementation.

Updated: Cargo.toml, plan.md, research.md, tasks.md
This commit is contained in:
2026-01-01 14:54:35 +01:00
parent ff0c0c39c0
commit 9bae638bd2
5 changed files with 31 additions and 24 deletions

View File

@@ -67,10 +67,11 @@
**Version**: tokio-modbus 0.17.0 (latest stable, released 2025-10-22)
**Protocol**: Modbus RTU over TCP (NOT Modbus TCP)
- Hardware uses RTU protocol tunneled over TCP
- Includes CRC16 validation
- Different from native Modbus TCP (no CRC, different framing)
**Protocol**: Modbus TCP (native TCP protocol)
- Hardware configured to use native Modbus TCP protocol
- Uses MBAP (Modbus Application Protocol) header
- No CRC16 validation (TCP/IP handles error detection)
- Standard Modbus TCP protocol on port 502
**Connection Strategy**:
- Shared `Arc<Mutex<Context>>` for simplicity
@@ -92,11 +93,13 @@
### Critical Gotchas
1. **Device Gateway Configuration**: Hardware MUST be set to "Multi-host non-storage type" - default storage type sends spurious queries causing failures
1. **Device Protocol Configuration**: Hardware MUST be configured to use Modbus TCP protocol (not RTU over TCP) via VirCom software
- Set "Transfer Protocol" to "Modbus TCP protocol" in Advanced Settings
- Device automatically switches to port 502 when TCP protocol is selected
2. **No Built-in Timeouts**: tokio-modbus has NO automatic timeouts - must wrap every operation with `tokio::time::timeout`
2. **Device Gateway Configuration**: Hardware MUST be set to "Multi-host non-storage type" - default storage type sends spurious queries causing failures
3. **RTU vs TCP Confusion**: Device uses Modbus RTU protocol over TCP (with CRC), not native Modbus TCP protocol
3. **No Built-in Timeouts**: tokio-modbus has NO automatic timeouts - must wrap every operation with `tokio::time::timeout`
4. **Address Indexing**: Relays labeled 1-8, but Modbus addresses are 0-7 (use newtype pattern with conversion methods)
@@ -111,8 +114,8 @@
use tokio_modbus::prelude::*;
use tokio::time::{timeout, Duration};
// Connect to device
let socket_addr = "192.168.1.200:8234".parse()?;
// Connect to device using Modbus TCP on standard port 502
let socket_addr = "192.168.1.200:502".parse()?;
let mut ctx = tcp::connect(socket_addr).await?;
// Set slave ID (unit identifier)
@@ -125,6 +128,8 @@ let states = timeout(
).await???; // Triple-? handles timeout + transport + exception errors
```
**Note**: Modbus TCP uses the standard MBAP header and does not require CRC16 validation. The protocol is cleaner and more standardized than RTU over TCP.
**Toggle Relay with Retry**:
```rust
async fn toggle_relay(