SLMP Protocol for Rust
Async Rust implementation of the SLMP library, based on the plc-comm-slmp-dotnet
implementation and aligned with the shared plc-comm-slmp-cross-verify harness.
The crate focuses on Binary 3E / 4E SLMP over TCP and UDP and keeps the same operation meaning as the existing Python, .NET, C++, Node-RED, and Rust verification clients.
What This Repo Contains
- async Rust library crate:
src/ cross-verifywrapper binary:src/bin/slmp_verify_client.rs- runnable examples:
examples/ - address and usage guides:
docs/ - minimal
napi-rsworkspace member for future Node packaging:crates/slmp-node
Current Scope
- raw device access: word, bit, dword, float32
- random read/write
- block read/write
- extended-device read/write
- memory read/write
- extend-unit read/write
- remote operations and self-test
- high-level typed helpers
- high-level named read/write and polling helpers
- live device-range catalog via user-selected PLC family plus family
SDregisters slmp_verify_clientwrapper forplc-comm-slmp-cross-verify- minimal
napi-rsNode binding scaffold incrates/slmp-node
Installation
Install from crates.io:
The public package name is plc-comm-slmp-rust, and the library import path is
plc_comm_slmp.
Requires Rust 1.85 or newer.
Cargo.toml:
[]
= "0.1.9"
= { = "1", = ["rt-multi-thread", "macros"] }
Quick Start
Raw Client Usage
use ;
async
Recommended High-Level Usage
use ;
async
Typed Access
use ;
# async
Runnable Examples
The repository includes examples that compile as part of the crate and can be run directly against a PLC or mock server.
raw_read_write
Low-level word read plus optional write/read-back.
SLMP_HOST=192.168.250.100 \
SLMP_PORT=1025 \
SLMP_PLC_FAMILY=iq-r \
Enable writes explicitly:
SLMP_ENABLE_WRITES=1 \
SLMP_WRITE_ADDRESS=D600 \
SLMP_WRITE_VALUES=111,222 \
named_helpers
Named snapshot, typed decoding, optional write_named, and one poll_named
tick.
SLMP_HOST=192.168.250.100 \
SLMP_PLC_FAMILY=iq-f \
SLMP_NAMED_ADDRESSES='D100,D200:F,D50.3,LTN10:D,LTS10' \
advanced_operations
Safe read-heavy sample that covers type-name, random read, block read, extended device read, and self-test loopback.
SLMP_HOST=192.168.250.100 \
SLMP_PLC_FAMILY=iq-r \
SLMP_RANDOM_WORDS='D100,R10' \
SLMP_RANDOM_DWORDS='D200,LTN10' \
SLMP_EXT_DEVICE='J1\W10' \
device_range_catalog
Reads the family-specific SD window for a user-selected PLC family and prints
points plus formatted address ranges such as X0000-X2FFF.
SLMP_HOST=192.168.250.100 \
SLMP_PORT=1025 \
SLMP_PLC_FAMILY=iq-f \
connection_profile_probe
Tries the standard frame and compatibility candidates, reads read_type_name,
then validates the resolved family by reading its full SD block once. The
result is advisory only so the caller can choose which settings to use.
SLMP_HOST=192.168.250.100 \
SLMP_PORT=1025 \
device_matrix_compare
Real-PLC regression sample that writes the same address through multiple command paths and checks that read-back stays aligned.
- bit devices:
write_bits,write_random_bits,write_typed,write_named, rawrequest - word devices:
write_words,write_random_words,write_typed,write_named, rawrequest - 32-bit devices:
write_dwords,write_random_words,write_typed,write_named, rawrequest J1\\...devices: extended helper APIs plus rawrequest
SLMP_HOST=192.168.250.100 \
SLMP_PORT=1025 \
SLMP_PLC_FAMILY=iq-r \
This example exits non-zero when command paths for the same address disagree.
Focus on a subset while debugging:
SLMP_COMPARE_ONLY='LTS10,LTC10,LCS10,LCC10,LTN10,LSTN10' \
The shared environment variables for these examples are documented in
docs/RECIPES.md.
For live PLC-dependent device limits resolved from a user-selected PLC family
plus family SD registers, see docs/DEVICE_RANGES.md.
Public API Surface
Main exports:
SlmpConnectionOptionsSlmpClientSlmpAddressprobe_connection_profilesread_type_name/read_device_range_catalog/read_device_range_catalog_for_familyread_typed/write_typedwrite_bit_in_wordread_named/write_namedpoll_namedread_words_single_request/read_dwords_single_requestread_words_chunked/read_dwords_chunkedwrite_words_single_request/write_dwords_single_requestwrite_words_chunked/write_dwords_chunked
Important model types:
SlmpDeviceAddressSlmpQualifiedDeviceAddressSlmpTargetAddressSlmpExtensionSpecSlmpTypeNameInfoSlmpDeviceRangeCatalog,SlmpDeviceRangeEntry,SlmpDeviceRangeFamilySlmpRandomReadResultSlmpBlockRead,SlmpBlockWrite,SlmpBlockReadResultSlmpLongTimerResultSlmpValue
Supported Address Forms
High-level helpers are intended to cover these forms first.
- plain word devices:
D100,R50,ZR0,TN0,CN0 - plain bit devices:
M1000,X20,Y20,B10 - typed suffixes:
D100:S,D200:D,D300:L,D400:F - bit-in-word form:
D50.3 - long current-value forms:
LTN10:D,LSTN20:D,LCN30:D - extended devices:
J1\\SW0,U3\\G100,U1\\HG0
.bit notation is only valid for word devices. Address bit devices directly.
See also:
Choosing the Right API
- Use raw device methods when you need exact SLMP request control.
- Use
read_typedandwrite_typedwhen one address maps to one scalar value. - Use
read_namedandwrite_namedwhen your application needs a snapshot with mixed dtypes and bit-in-word decoding. - Use
poll_namedfor a lightweight periodic stream. - Use
read_randomandread_blockwhen you want to keep request counts low. - Use the extended-device methods for
J...andU...paths. read_namedandwrite_namedcurrently target plain device addresses, notJ...orU...qualified addresses.
Long-Family Behavior
The Rust implementation follows the same normalized behavior as the other libraries:
LTN,LSTN,LCN, andLZdefault to 32-bit readsLCNhigh-level reads and writes use random dword access (0x0403/0x1402)LTS,LTC,LSTS,LSTC,LCS, andLCCare state readsLCSandLCCreads use direct bit read throughread_typed/read_namedLCSandLCCare rejected forRead Random (0x0403),Read Block (0x0406),Write Block (0x1406), andEntry Monitor Device (0x0801)- direct bit reads/writes (
0x0401/0x1401) and Read Random (0x0403) forLTS,LTC,LSTS, andLSTCare rejected by the Rust client API; use helper APIs, random bit write (0x1402), or 4-word block reads fromLTN/LSTN - direct bit writes (
0x1401) forLCSandLCCare also rejected; usewrite_typed/write_namedso random bit write (0x1402) is selected - direct dword reads for
LTN,LSTN,LCN, andLZare rejected; use helper APIs, random dword high-level access, or explicit 4-word block reads where supported
Route guard note: keep low-level direct bit routes guarded for
LTS/LTC/LSTS/LSTC and direct bit writes guarded for LCS/LCC.
High-level writes must continue to resolve to random bit write (0x1402).
That behavior is intentional and is enforced through
plc-comm-slmp-cross-verify.
Cross-Verify
This repo is designed to participate in:
plc-comm-slmp-cross-verify/specs/sharedpython verify.py --clients rust- full parity runs with Python, .NET, C++, and Node-RED
- live PLC verification through the same saved baseline/profile flow
The wrapper binary used by the harness is:
Development
Format and test:
Run the Rust tests:
Check the Node binding scaffold:
Run Rust-only parity through the canonical harness:
Run full parity:
Run live PLC verification with the validated R120 profile:
Node Binding
crates/slmp-node is currently a thin napi-rs scaffold. It is not yet the
main delivery path. The current purpose is to keep the Rust workspace ready for
future Node package work without redesigning the crate layout later.
License
Distributed under the MIT License.