Getting started
Start here
Use this page when you want the shortest path from a Rust program to a MELSEC PLC. The examples use TCP at 192.168.250.100:1025.
Prerequisites
| Requirement | Value |
|---|---|
| Rust | 1.85 or newer (1.85 is the declared minimum supported compiler) |
| Async runtime | tokio with macros and a runtime feature |
| PLC endpoint | 192.168.250.100:1025 |
| Profile used below | SlmpPlcProfile::IqR |
Add dependency
cargo add plc-comm-slmp
cargo add tokio --features macros,rt-multi-thread
Choose your PLC profile
The endpoint port, transport, target route, and exact SlmpPlcProfile are required.
The library derives the SLMP frame and compatibility mode from the profile.
use plc_comm_slmp::{SlmpConnectionOptions, SlmpPlcProfile};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let options = SlmpConnectionOptions::new("192.168.250.100", 1025, plc_comm_slmp::SlmpTransportMode::Tcp, plc_comm_slmp::SlmpTargetAddress::default(), SlmpPlcProfile::IqR)?;
println!("{:?}", options.plc_profile());
Ok(())
}
First read
This reads D100 as an unsigned 16-bit word.
use plc_comm_slmp::{
read_typed, SlmpAddress, SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let options = SlmpConnectionOptions::new("192.168.250.100", 1025, plc_comm_slmp::SlmpTransportMode::Tcp, plc_comm_slmp::SlmpTargetAddress::default(), SlmpPlcProfile::IqR)?;
let client = SlmpClient::connect(options).await?;
let value = read_typed(&client, SlmpAddress::parse("D100", SlmpPlcProfile::IqR)?, "U").await?;
println!("{:?}", value);
client.close().await?;
Ok(())
}
Expected output shape:
U16(123)
First write
Only write to a test address that your PLC program allows you to change.
use plc_comm_slmp::{
read_typed, write_typed, SlmpAddress, SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
SlmpValue,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let options = SlmpConnectionOptions::new("192.168.250.100", 1025, plc_comm_slmp::SlmpTransportMode::Tcp, plc_comm_slmp::SlmpTargetAddress::default(), SlmpPlcProfile::IqR)?;
let client = SlmpClient::connect(options).await?;
let address = SlmpAddress::parse("D600", SlmpPlcProfile::IqR)?;
let original = read_typed(&client, address, "U").await?;
write_typed(&client, address, "U", &SlmpValue::U16(42)).await?;
let readback_result = read_typed(&client, address, "U").await;
let restore_result = write_typed(&client, address, "U", &original).await;
restore_result?;
let value = readback_result?;
println!("{:?}", value);
client.close().await?;
Ok(())
}
The readback result is not propagated until after restoration is attempted, so a readback failure cannot skip the confirmed-write cleanup. If the test write itself returns an outcome-unknown error, do not send an automatic restore or retry; reopen, inspect the test register, and reconcile it explicitly. If the restoration attempt fails, also inspect the test register and reconcile its value manually before continuing.
Confirm success
- The PLC IP address is reachable from your computer.
- TCP port
1025is open on your PLC Ethernet module or built-in Ethernet port. - The PLC-side communication data code is Binary and the port/open setting matches your transport; see the MELSEC SLMP PLC Setup Guide.
- PLC-side RUN-time write permission is enabled before you run a write example where the PLC exposes that setting.
SlmpPlcProfile::IqRmatches your real hardware, or you selected the correct variant from profiles.- A read from
D100returns aSlmpValuewithout an SLMP end code error. - Any write test uses a register reserved for testing and restores the original value.
If it does not work
| Symptom | Check |
|---|---|
| You get SLMP end code errors | SlmpPlcProfile must match the actual hardware. |
| Connection opens but all requests fail | Confirm Binary communication data code in the PLC setup guide. |
| Reads work but writes fail | Confirm RUN-time write permission in the PLC setup guide and the selected profile write policy. |
| You are tempted to set the frame manually | Do not override frame type manually; it is derived from the profile. |
| A special device family fails | Start with D reads, not G, HG, LTN, or LCN. |
X or Y addresses look different on iQ-F |
SlmpPlcProfile::IqF parses X and Y string addresses as octal. |