Phase 3 PR 42 — ModbusPal simulator profiles for Standard + DL205/DL260 #41
@@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE modbuspal_project SYSTEM "modbuspal.dtd">
|
||||
|
||||
<!--
|
||||
DL205.xmpp — AutomationDirect DirectLOGIC DL205 / DL260 quirk simulator.
|
||||
|
||||
Slave id 1 on TCP 502. Models the real-PLC behaviors documented in
|
||||
docs/v2/dl205.md as concrete register values, so integration tests can
|
||||
assert each quirk WITHOUT a live PLC. The driver is correct when reads
|
||||
against this profile produce the same logical values that an
|
||||
AutomationDirect-aware client would see.
|
||||
|
||||
BIG WARNING: every "interesting" register here is encoded as a raw 16-bit
|
||||
integer. ModbusPal 1.6b serves whatever you put in `value="..."` straight
|
||||
onto the wire as a 16-bit big-endian register; it has no String / BCD /
|
||||
Float / WordSwap binding (only SINT16 / SINT32 / FLOAT32 + word-order, none
|
||||
of which capture the byte-level packing the DL series uses). So strings,
|
||||
BCD, and CDAB floats live here as opaque integers with the math worked out
|
||||
in the comment above each register. That math is reproduced in
|
||||
docs/v2/dl205.md so the two stay in sync.
|
||||
|
||||
If this profile grows beyond ~50 quirky registers, switch to pymodbus
|
||||
(see ModbusPal/README.md §"alternatives") — the magic-number table will
|
||||
become unreadable. For the planned 12 DL205_<behavior> tests, raw values
|
||||
are fine.
|
||||
|
||||
Loaded via the ModbusPal GUI: File > Load > pick this file > Run.
|
||||
Run only ONE simulator at a time (they share TCP 502); to switch between
|
||||
Standard and DL205, stop one before loading the other.
|
||||
-->
|
||||
|
||||
<modbuspal_project>
|
||||
|
||||
<idgen value="200"/>
|
||||
|
||||
<links selected="TCP/IP">
|
||||
<tcpip port="502"/>
|
||||
<serial com="COM 1" baudrate="9600" parity="even" stops="1">
|
||||
<flowcontrol xonxoff="false" rtscts="false"/>
|
||||
</serial>
|
||||
</links>
|
||||
|
||||
<slave id="1" enabled="true" name="DL205Sim" implementation="modbus">
|
||||
|
||||
<holding_registers>
|
||||
|
||||
<!-- ============================================================
|
||||
V-MEMORY ADDRESSING MARKERS
|
||||
============================================================
|
||||
DirectLOGIC V-memory is octal natively; the CPU translates
|
||||
V<oct> -> Modbus PDU <decimal>. Tests verify our address
|
||||
helper produces the right PDU offset for known V-addresses.
|
||||
Marker values are arbitrary but distinctive so a test that
|
||||
reads the wrong PDU sees Goodread+wrong-value, not zero.
|
||||
-->
|
||||
|
||||
<!-- V0 (octal) = PDU 0x0000. Decisively proves register 0 is valid
|
||||
on DL205/DL260 with H2-ECOM100 in absolute mode (the default).
|
||||
The "rejects register 0" rumour was a DL05/DL06 relative-mode
|
||||
artefact — see dl205.md §Register Zero. -->
|
||||
<!-- 0xCAFE = 51966 (signed 16-bit: -13570) -->
|
||||
<register address="0" value="-13570" name="V0_marker_0xCAFE"/>
|
||||
|
||||
<!-- V2000 octal = decimal 1024 = PDU 0x0400. -->
|
||||
<!-- 0x2000 = 8192 -->
|
||||
<register address="1024" value="8192" name="V2000_marker_0x2000"/>
|
||||
|
||||
<!-- V40400 octal = decimal 8448 = PDU 0x2100. Proves the
|
||||
"V40400 = register 0" myth wrong on absolute-mode firmware. -->
|
||||
<!-- 0x4040 = 16448 -->
|
||||
<register address="8448" value="16448" name="V40400_marker_0x4040"/>
|
||||
|
||||
<!-- ============================================================
|
||||
STRING PACKING (the user's headline quirk)
|
||||
============================================================
|
||||
Two ASCII chars per register, FIRST CHAR in the LOW byte.
|
||||
"Hello" at HR[0x410..0x412]:
|
||||
|
||||
HR[0x410] = 'H' (0x48) lo, 'e' (0x65) hi -> 0x6548 = 25928
|
||||
HR[0x411] = 'l' (0x6C) lo, 'l' (0x6C) hi -> 0x6C6C = 27756
|
||||
HR[0x412] = 'o' (0x6F) lo, '\0' (0x00) hi -> 0x006F = 111
|
||||
|
||||
A textbook (high-byte-first) decoder reads "eH" "ll" "\0o"
|
||||
and prints "eHll \0o" — that's exactly the failure mode the
|
||||
DL205 string test asserts NOT happens once we add the
|
||||
ModbusStringByteOrder=LowFirst option to the driver.
|
||||
Test: DL205_String_low_byte_first_within_register. -->
|
||||
<register address="1040" value="25928" name="HelloStr_lo='H'_hi='e'"/>
|
||||
<register address="1041" value="27756" name="HelloStr_lo='l'_hi='l'"/>
|
||||
<register address="1042" value="111" name="HelloStr_lo='o'_hi=null"/>
|
||||
|
||||
<!-- ============================================================
|
||||
32-BIT FLOAT IN CDAB WORD ORDER
|
||||
============================================================
|
||||
IEEE 754 float 1.5f = 0x3FC00000.
|
||||
Standard ABCD: HR[N]=0x3FC0, HR[N+1]=0x0000
|
||||
DL205 CDAB: HR[N]=0x0000, HR[N+1]=0x3FC0 (LOW word first)
|
||||
|
||||
Test: DL205_Float32_word_order_is_CDAB.
|
||||
Driver must use ModbusByteOrder=WordSwap to decode this as 1.5. -->
|
||||
<register address="1056" value="0" name="FloatCDAB_lo_word"/>
|
||||
<!-- 0x3FC0 = 16320 -->
|
||||
<register address="1057" value="16320" name="FloatCDAB_hi_word"/>
|
||||
|
||||
<!-- ============================================================
|
||||
BCD-ENCODED REGISTER (DirectLOGIC default numeric storage)
|
||||
============================================================
|
||||
Ladder value 1234 stored as 0x1234 = 4660 (BCD nibbles, NOT
|
||||
binary 1234 = 0x04D2). A driver in binary-int mode reads 4660
|
||||
and reports the wrong value; in BCD mode it nibble-decodes
|
||||
0x1234 -> 1234. Test: DL205_BCD_register_decodes_as_decimal. -->
|
||||
<!-- 0x1234 = 4660 -->
|
||||
<register address="1072" value="4660" name="BCD_1234_as_0x1234"/>
|
||||
|
||||
<!-- ============================================================
|
||||
LOAD-LIMIT BOUNDARY MARKERS
|
||||
============================================================
|
||||
The DL series caps FC03 at 128 registers (above spec's 125)
|
||||
and FC16 at 100 (BELOW spec's 123). The cap-tests don't need
|
||||
specific values — they assert exception 03 IllegalDataValue
|
||||
on an over-sized request. We pre-seed a contiguous block at
|
||||
0x500..0x57F (128 regs) so a 128-register read returns Good
|
||||
and a 129-register read can be tried for the failure case.
|
||||
Per-register values: address - 0x500 (so HR[0x500]=0,
|
||||
HR[0x501]=1, ..., HR[0x57F]=127). Easy mental verification.
|
||||
Test: DL205_FC03_128_registers_returns_Good. -->
|
||||
<!-- (Generated programmatically below for brevity — first / last + spot-check) -->
|
||||
<register address="1280" value="0" name="FC03Block_first"/>
|
||||
<register address="1281" value="1"/>
|
||||
<register address="1282" value="2"/>
|
||||
<register address="1343" value="63" name="FC03Block_mid"/>
|
||||
<register address="1407" value="127" name="FC03Block_last"/>
|
||||
<!-- Note: ModbusPal serves unlisted addresses as 0 by default for
|
||||
reads that fall within the configured slave's address space.
|
||||
The block-test relies on that behavior; the hand-listed
|
||||
entries above are sanity markers. If the driver later wants
|
||||
byte-perfect comparison across the whole 128-register range,
|
||||
expand this section to one element per address (or switch to
|
||||
pymodbus). -->
|
||||
</holding_registers>
|
||||
|
||||
<coils>
|
||||
|
||||
<!-- ============================================================
|
||||
COIL / DISCRETE-INPUT MAPPING MARKERS (DL260 layout)
|
||||
============================================================
|
||||
Per dl205.md, on the DL260:
|
||||
X inputs -> discrete inputs 0..511 (FC02)
|
||||
Y outputs -> coils 2048..2559 (FC01/05)
|
||||
C relays -> coils 3072..4095 (FC01/05)
|
||||
|
||||
ModbusPal 1.6b does NOT have a discrete-inputs section in
|
||||
the official build, so the X-input markers can't be
|
||||
encoded faithfully (the driver test for FC02 against this
|
||||
profile will need a fork or pymodbus). The Y and C coil
|
||||
markers ARE encodable here.
|
||||
-->
|
||||
|
||||
<!-- Y0 marker — coil 2048 ON proves "Y0 maps to coil 2048" mapping.
|
||||
Test: DL205_Y0_maps_to_coil_2048. -->
|
||||
<coil address="2048" value="1" name="Y0_marker"/>
|
||||
<coil address="2049" value="0"/>
|
||||
<coil address="2050" value="1"/>
|
||||
|
||||
<!-- C0 marker — coil 3072 ON proves "C0 maps to coil 3072" mapping.
|
||||
Test: DL205_C0_maps_to_coil_3072. -->
|
||||
<coil address="3072" value="1" name="C0_marker"/>
|
||||
<coil address="3073" value="0"/>
|
||||
<coil address="3074" value="1"/>
|
||||
|
||||
<!-- Scratch coils 4000..4007 for write-roundtrip tests against
|
||||
the C-relay range. C ranges are writable on the real DL260. -->
|
||||
<coil address="4000" value="0" name="Cscratch_0"/>
|
||||
<coil address="4001" value="0"/>
|
||||
<coil address="4002" value="0"/>
|
||||
<coil address="4003" value="0"/>
|
||||
<coil address="4004" value="0"/>
|
||||
<coil address="4005" value="0"/>
|
||||
<coil address="4006" value="0"/>
|
||||
<coil address="4007" value="0"/>
|
||||
</coils>
|
||||
|
||||
<tuning>
|
||||
<!-- Zero delay / zero error rate. The DL205 H2-ECOM has a typical
|
||||
2-10ms scan-cycle delay; if a test wants to simulate that,
|
||||
tune via the ModbusPal GUI (Tuning > Reply delay). -->
|
||||
<reply_delay min="0" max="0"/>
|
||||
<error_rates no_reply="0.0"/>
|
||||
</tuning>
|
||||
</slave>
|
||||
|
||||
</modbuspal_project>
|
||||
@@ -1,30 +1,105 @@
|
||||
# ModbusPal simulator profiles
|
||||
|
||||
Drop device-specific `.xmpp` profiles here. The integration tests connect to the
|
||||
endpoint in `MODBUS_SIM_ENDPOINT` (default `localhost:502`) and expect the
|
||||
simulator to already be running — tests do not launch ModbusPal themselves,
|
||||
because its Java GUI + JRE requirement is heavier than the harness is worth.
|
||||
Two hand-authored `.xmpp` profiles you load into ModbusPal to drive the
|
||||
integration-test suite without a real PLC:
|
||||
|
||||
| File | What it simulates | Test category |
|
||||
|---|---|---|
|
||||
| [`Standard.xmpp`](Standard.xmpp) | Generic Modbus TCP server — HR[0..31] = address-as-value, alternating coils, one auto-incrementing register at HR[100] for subscribe tests, scratch ranges for write-roundtrip tests. | `Trait=Standard` |
|
||||
| [`DL205.xmpp`](DL205.xmpp) | AutomationDirect DirectLOGIC DL205 / DL260 quirks per [`docs/v2/dl205.md`](../../../docs/v2/dl205.md): low-byte-first string packing, CDAB Float32, BCD numerics, V-memory address markers, Y/C coil mappings. | `Trait=DL205` |
|
||||
|
||||
Both listen on TCP **port 502** (the standard Modbus port — change in the
|
||||
ModbusPal GUI if a port conflict). Run **only one at a time** since they
|
||||
share the port.
|
||||
|
||||
## Getting started
|
||||
|
||||
1. Download ModbusPal from SourceForge (`modbuspal.jar`).
|
||||
1. Download ModbusPal 1.6b from
|
||||
[SourceForge](https://sourceforge.net/projects/modbuspal/) — `modbuspal.jar`.
|
||||
Requires Java 8+ (Java 17/21 work but emit Swing deprecation warnings).
|
||||
2. `java -jar modbuspal.jar` to launch the GUI.
|
||||
3. Load a profile from this directory (or configure one manually) and start the
|
||||
simulator on TCP port 502.
|
||||
4. `dotnet test tests/ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests` — tests
|
||||
auto-skip with a clear `SkipReason` if the TCP probe at the configured
|
||||
endpoint fails within 2 seconds.
|
||||
3. **File > Load** → pick `Standard.xmpp` (or `DL205.xmpp`).
|
||||
4. Click the **Run** button (top-right of the toolbar) to start serving on TCP 502.
|
||||
5. `dotnet test tests/ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests` —
|
||||
tests auto-skip with a clear `SkipReason` if the TCP probe at the
|
||||
configured endpoint fails within 2 seconds (`ModbusSimulatorFixture`).
|
||||
|
||||
## Profile files
|
||||
## Switching between Standard and DL205
|
||||
|
||||
- `DL205.xmpp` — _to be added_ — register map reflecting the AutomationDirect
|
||||
DL205 quirks tracked in `docs/v2/modbus-test-plan.md`. The scaffolded smoke
|
||||
test in `DL205/DL205SmokeTests.cs` needs holding register 100 writable and
|
||||
present; a minimal ModbusPal profile with a single holding-register bank at
|
||||
address 100 is sufficient.
|
||||
Stop the running simulator (toolbar's **Stop** button), **File > Load**
|
||||
the other profile, **Run**.
|
||||
|
||||
## Environment variables
|
||||
|
||||
- `MODBUS_SIM_ENDPOINT` — override the simulator endpoint. Accepts `host:port`;
|
||||
defaults to `localhost:502`. Useful when pointing the suite at a real PLC on
|
||||
the bench.
|
||||
- `MODBUS_SIM_ENDPOINT` — override the simulator endpoint
|
||||
(`host:port`). Defaults to `localhost:502`. Useful when pointing the suite
|
||||
at a real PLC on the bench, or running ModbusPal on a non-default port.
|
||||
|
||||
## What's encoded in each profile
|
||||
|
||||
### Standard
|
||||
|
||||
- HR[0..31]: each register's value equals its address.
|
||||
- HR[100]: bound to a `LinearGenerator` (0..65535 over 60s, looping) — drives
|
||||
subscribe-and-receive tests.
|
||||
- HR[200..209]: scratch range for write-roundtrip tests.
|
||||
- Coils[0..31]: alternating on/off (even=on).
|
||||
- Coils[100..109]: scratch range.
|
||||
|
||||
### DL205 (per `docs/v2/dl205.md`)
|
||||
|
||||
| HR address | Quirk demonstrated | Raw value | Decoded value |
|
||||
|---|---|---|---|
|
||||
| `0` | Register zero is valid (rejects-register-0 rumour disproved) | `-13570` (0xCAFE) | marker |
|
||||
| `1024` (= V2000 octal) | V-memory octal-to-decimal mapping | `8192` (0x2000) | marker |
|
||||
| `8448` (= V40400 octal) | V40400 → PDU 0x2100 (NOT register 0) | `16448` (0x4040) | marker |
|
||||
| `1040..1042` | String "Hello" packed first-char-low-byte | `25928, 27756, 111` | `"Hello"` |
|
||||
| `1056..1057` | Float32 1.5f in CDAB word order | `0, 16320` | `1.5f` |
|
||||
| `1072` | Decimal 1234 in BCD encoding | `4660` (0x1234) | `1234` |
|
||||
| `1280..1407` | 128-register block (FC03 cap = 128 above spec's 125) | address − 1280 | for FC03 cap test |
|
||||
|
||||
| Coil address | Quirk demonstrated |
|
||||
|---|---|
|
||||
| `2048` | Y0 maps to coil 2048 (DL260 layout) |
|
||||
| `3072` | C0 maps to coil 3072 (DL260 layout) |
|
||||
| `4000..4007` | Scratch C-relay range for write-roundtrip tests |
|
||||
|
||||
## Limitations of ModbusPal 1.6b
|
||||
|
||||
- **Only `holding_registers` + `coils`** sections in the official build —
|
||||
no `input_registers` (FC04) and no `discrete_inputs` (FC02). DL205's
|
||||
X-input markers can't be encoded faithfully here. Tests for FC02 / FC04
|
||||
wait for a fork (e.g. `SCADA-LTS/ModbusPal`) or a pymodbus rewrite.
|
||||
- **No semantic bindings** for strings / BCD / arbitrary byte layouts. The
|
||||
DL205 profile encodes everything as pre-computed raw 16-bit integers
|
||||
with the math worked out in inline comments. Anything fancier becomes
|
||||
unreadable above ~50 quirky registers — switch to pymodbus when that
|
||||
threshold approaches.
|
||||
- **Project is abandoned** since 1.6b on the official SourceForge listing.
|
||||
Active forks: `SCADA-LTS/ModbusPal`, `ControlThings-io/modbuspal`,
|
||||
`mrhenrike/ModbusPalEnhanced`.
|
||||
- **No headless mode** in the official 1.6b JAR (`-loadFile` / `-hide`
|
||||
flags exist only in source-built forks). For CI use, plan to switch to
|
||||
pymodbus's `ModbusSimulatorServer` (JSON config, scriptable callbacks,
|
||||
first-class headless).
|
||||
- **CVE-2018-10832** XXE in `.xmpp` import. Don't import `.xmpp` files from
|
||||
untrusted sources. Profiles in this repo are author-controlled; safe.
|
||||
|
||||
## Alternatives if ModbusPal stops working
|
||||
|
||||
| Tool | Pros | Cons |
|
||||
|---|---|---|
|
||||
| **pymodbus `ModbusSimulatorServer`** | Headless-first, JSON config, per-register seeding, custom callbacks for byte-level layouts. Best CI fit. | Python dependency. |
|
||||
| **diagslave** | Simple, headless, fast. | Flat register banks; no per-address seeding from config; no scripting. |
|
||||
| **ModbusMechanic** | Headless config-file mode. | Lightly documented. |
|
||||
| **ModRSsim2** | Windows GUI, CSV import, scripting. | GUI-centric. |
|
||||
|
||||
## File format reference
|
||||
|
||||
ModbusPal `.xmpp` is XML with a DTD reference (`modbuspal.dtd`). Root element
|
||||
`<modbuspal_project>` with three children:
|
||||
- `<idgen value="N"/>` — internal id counter (start at 100+)
|
||||
- `<links selected="TCP/IP">` — `<tcpip port="502"/>` for TCP listen, plus a `<serial>` placeholder
|
||||
- One or more `<slave id="..." enabled="true" name="..." implementation="modbus">` containing `<holding_registers>` (`<register address="N" value="V"/>`), `<coils>` (`<coil address="N" value="0|1"/>`), `<tuning>`
|
||||
|
||||
Per-register `<binding automation="..." class="Binding_SINT16|SINT32|FLOAT32" order="0|1"/>` ties a register to a `LinearGenerator` / `RandomGenerator` / `SineGenerator` automation declared at the project level. `order="0"` = LSW, `order="1"` = MSW for 32-bit types. There is **no string binding** and **no byte-swap-within-word** binding.
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE modbuspal_project SYSTEM "modbuspal.dtd">
|
||||
|
||||
<!--
|
||||
Standard.xmpp — generic Modbus TCP server.
|
||||
|
||||
Slave id 1 on TCP port 502. Holding registers 0..31 seeded with their own
|
||||
address as value (so HR[0]=0, HR[5]=5, easy mental map for diagnostics).
|
||||
Coils 0..31 alternate true/false. One auto-incrementing register at HR[100]
|
||||
bound to the "Tick" automation (1 Hz, wraps 0..65535) so subscribe-and-receive
|
||||
integration tests have something that actually changes without a write.
|
||||
|
||||
Loaded via the ModbusPal GUI: File > Load > pick this file > Run.
|
||||
The integration test fixture (MODBUS_SIM_ENDPOINT, default localhost:502)
|
||||
connects on TCP. Tests filter by Trait=Standard.
|
||||
|
||||
Limitations of ModbusPal 1.6b that shape this profile:
|
||||
- Only holding_registers + coils sections (no input_registers, no
|
||||
discrete_inputs in the official 1.6b build). Tests for FC04 / FC02
|
||||
wait until we switch to a fork or pymodbus.
|
||||
- Per-register elements only — sparse maps fine, range form not
|
||||
supported in the serialized format (the GUI lets you Add range,
|
||||
but the .xmpp file expands them).
|
||||
- Listens on all interfaces (no bind-address attribute).
|
||||
-->
|
||||
|
||||
<modbuspal_project>
|
||||
|
||||
<!-- Monotonic id generator ModbusPal uses to internally name automations / slaves. -->
|
||||
<idgen value="100"/>
|
||||
|
||||
<!-- TCP listen on 502 (standard Modbus port). Override via ModbusPal GUI if conflicting. -->
|
||||
<links selected="TCP/IP">
|
||||
<tcpip port="502"/>
|
||||
<serial com="COM 1" baudrate="9600" parity="even" stops="1">
|
||||
<flowcontrol xonxoff="false" rtscts="false"/>
|
||||
</serial>
|
||||
</links>
|
||||
|
||||
<!--
|
||||
Tick automation: 0..65535 over 60 seconds, looping. Bound to HR[100]
|
||||
below so each second the register climbs by ~1092. Slow enough that
|
||||
a 250ms-poll integration test sees discrete jumps; fast enough that
|
||||
a 5s subscribe test sees several change notifications.
|
||||
-->
|
||||
<automation name="Tick" step="1.0" loop="true" init="0.0">
|
||||
<generator class="LinearGenerator" duration="60.0">
|
||||
<start value="0.0" relative="false"/>
|
||||
<end value="65535.0" relative="false"/>
|
||||
</generator>
|
||||
</automation>
|
||||
|
||||
<slave id="1" enabled="true" name="StandardSim" implementation="modbus">
|
||||
|
||||
<holding_registers>
|
||||
<!-- HR[0..31] = address-as-value. Easy mental map for diagnostics + read tests. -->
|
||||
<register address="0" value="0"/>
|
||||
<register address="1" value="1"/>
|
||||
<register address="2" value="2"/>
|
||||
<register address="3" value="3"/>
|
||||
<register address="4" value="4"/>
|
||||
<register address="5" value="5"/>
|
||||
<register address="6" value="6"/>
|
||||
<register address="7" value="7"/>
|
||||
<register address="8" value="8"/>
|
||||
<register address="9" value="9"/>
|
||||
<register address="10" value="10"/>
|
||||
<register address="11" value="11"/>
|
||||
<register address="12" value="12"/>
|
||||
<register address="13" value="13"/>
|
||||
<register address="14" value="14"/>
|
||||
<register address="15" value="15"/>
|
||||
<register address="16" value="16"/>
|
||||
<register address="17" value="17"/>
|
||||
<register address="18" value="18"/>
|
||||
<register address="19" value="19"/>
|
||||
<register address="20" value="20"/>
|
||||
<register address="21" value="21"/>
|
||||
<register address="22" value="22"/>
|
||||
<register address="23" value="23"/>
|
||||
<register address="24" value="24"/>
|
||||
<register address="25" value="25"/>
|
||||
<register address="26" value="26"/>
|
||||
<register address="27" value="27"/>
|
||||
<register address="28" value="28"/>
|
||||
<register address="29" value="29"/>
|
||||
<register address="30" value="30"/>
|
||||
<register address="31" value="31"/>
|
||||
|
||||
<!-- HR[100] auto-increments via the Tick automation. Subscribe tests
|
||||
read this and expect to see at least 2 change notifications in 5s. -->
|
||||
<register address="100" value="0" name="AutoIncrement">
|
||||
<binding automation="Tick" class="Binding_SINT16" order="0"/>
|
||||
</register>
|
||||
|
||||
<!-- HR[200..209] — scratch range left at 0 for write-roundtrip tests
|
||||
to mutate freely without touching the address-as-value set above. -->
|
||||
<register address="200" value="0" name="Scratch0"/>
|
||||
<register address="201" value="0" name="Scratch1"/>
|
||||
<register address="202" value="0" name="Scratch2"/>
|
||||
<register address="203" value="0" name="Scratch3"/>
|
||||
<register address="204" value="0" name="Scratch4"/>
|
||||
<register address="205" value="0" name="Scratch5"/>
|
||||
<register address="206" value="0" name="Scratch6"/>
|
||||
<register address="207" value="0" name="Scratch7"/>
|
||||
<register address="208" value="0" name="Scratch8"/>
|
||||
<register address="209" value="0" name="Scratch9"/>
|
||||
</holding_registers>
|
||||
|
||||
<coils>
|
||||
<!-- Coils 0..31 alternating. Even = on, odd = off. -->
|
||||
<coil address="0" value="1"/>
|
||||
<coil address="1" value="0"/>
|
||||
<coil address="2" value="1"/>
|
||||
<coil address="3" value="0"/>
|
||||
<coil address="4" value="1"/>
|
||||
<coil address="5" value="0"/>
|
||||
<coil address="6" value="1"/>
|
||||
<coil address="7" value="0"/>
|
||||
<coil address="8" value="1"/>
|
||||
<coil address="9" value="0"/>
|
||||
<coil address="10" value="1"/>
|
||||
<coil address="11" value="0"/>
|
||||
<coil address="12" value="1"/>
|
||||
<coil address="13" value="0"/>
|
||||
<coil address="14" value="1"/>
|
||||
<coil address="15" value="0"/>
|
||||
<coil address="16" value="1"/>
|
||||
<coil address="17" value="0"/>
|
||||
<coil address="18" value="1"/>
|
||||
<coil address="19" value="0"/>
|
||||
<coil address="20" value="1"/>
|
||||
<coil address="21" value="0"/>
|
||||
<coil address="22" value="1"/>
|
||||
<coil address="23" value="0"/>
|
||||
<coil address="24" value="1"/>
|
||||
<coil address="25" value="0"/>
|
||||
<coil address="26" value="1"/>
|
||||
<coil address="27" value="0"/>
|
||||
<coil address="28" value="1"/>
|
||||
<coil address="29" value="0"/>
|
||||
<coil address="30" value="1"/>
|
||||
<coil address="31" value="0"/>
|
||||
|
||||
<!-- Coils 100..109 — scratch range for write-roundtrip tests. -->
|
||||
<coil address="100" value="0"/>
|
||||
<coil address="101" value="0"/>
|
||||
<coil address="102" value="0"/>
|
||||
<coil address="103" value="0"/>
|
||||
<coil address="104" value="0"/>
|
||||
<coil address="105" value="0"/>
|
||||
<coil address="106" value="0"/>
|
||||
<coil address="107" value="0"/>
|
||||
<coil address="108" value="0"/>
|
||||
<coil address="109" value="0"/>
|
||||
</coils>
|
||||
|
||||
<tuning>
|
||||
<!-- Zero artificial reply delay or error rate. Set non-zero in the GUI to
|
||||
simulate a slow / lossy link without re-authoring the file. -->
|
||||
<reply_delay min="0" max="0"/>
|
||||
<error_rates no_reply="0.0"/>
|
||||
</tuning>
|
||||
</slave>
|
||||
|
||||
</modbuspal_project>
|
||||
Reference in New Issue
Block a user