Usage guide
Recommended entry points
| Entry point | Use it for |
|---|---|
SlmpConnectionOptions::new(host, plc_profile) |
Creating a connection configuration with profile-derived defaults. |
SlmpClient::connect(options) |
Opening a TCP or UDP SLMP client. |
SlmpAddress::parse("D100") |
Parsing a device address into SlmpDeviceAddress. |
read_latest_self_diagnosis_error_code |
Reading the latest PLC self-diagnosis error code from SD0. |
read_typed and write_typed |
Reading or writing one scalar value. |
read_named and write_named |
Reading or writing a small mixed snapshot by address text. |
read_words_single_request and read_words_chunked |
Reading contiguous word ranges. |
read_dwords_single_request and read_dwords_chunked |
Reading contiguous 32-bit ranges. |
write_bit_in_word |
Updating one bit inside a word register. |
poll_named |
Repeating a named snapshot on an interval. |
Connection
SlmpConnectionOptions exposes user-settable connection fields. The PLC profile, frame type, and compatibility mode are selected together by SlmpConnectionOptions::new.
| Field | Default | Meaning |
|---|---|---|
host |
value passed to new |
PLC host name or IP address. |
port |
1025 |
TCP or UDP port. |
timeout |
3 seconds | Socket read/write timeout. |
tcp_keepalive |
30 seconds | TCP keepalive idle time, or None. |
target |
self CPU target | SLMP target address fields. |
transport_mode |
SlmpTransportMode::Tcp |
TCP or UDP. |
monitoring_timer |
0x0010 |
SLMP monitoring timer. |
use std::time::Duration;
use plc_comm_slmp::{
SlmpClient, SlmpConnectionOptions, SlmpPlcProfile, SlmpTransportMode,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
options.timeout = Duration::from_secs(3);
options.transport_mode = SlmpTransportMode::Tcp;
let client = SlmpClient::connect(options).await?;
println!("{:?}", client.plc_profile().await);
client.close().await?;
Ok(())
}
PLC diagnostics
SlmpClient::read_latest_self_diagnosis_error_code reads SD0, the latest PLC self-diagnosis error code, and returns the raw 16-bit value. Format it as hexadecimal when displaying it.
This value is separate from SlmpError.end_code. SlmpError.end_code is the SLMP response end code for a communication request, while SD0 is the PLC CPU's self-diagnosis error register.
use plc_comm_slmp::{
SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let error_code = client.read_latest_self_diagnosis_error_code().await?;
println!("latest self-diagnosis error code: 0x{error_code:04X}");
client.close().await?;
Ok(())
}
Read a single value
use plc_comm_slmp::{
read_typed, SlmpAddress, SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let value = read_typed(&client, SlmpAddress::parse("D100")?, "U").await?;
println!("{:?}", value);
client.close().await?;
Ok(())
}
| Suffix | Rust value | Meaning |
|---|---|---|
U |
SlmpValue::U16 |
Unsigned 16-bit word. |
S |
SlmpValue::I16 |
Signed 16-bit word. |
D |
SlmpValue::U32 |
Unsigned 32-bit value. |
L |
SlmpValue::I32 |
Signed 32-bit value. |
F |
SlmpValue::F32 |
32-bit float. |
BIT |
SlmpValue::Bool |
Bit device value. |
Write a single value
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 mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let device = SlmpAddress::parse("D600")?;
write_typed(&client, device, "U", &SlmpValue::U16(42)).await?;
let value = read_typed(&client, device, "U").await?;
println!("{:?}", value);
client.close().await?;
Ok(())
}
Named snapshot
use plc_comm_slmp::{
read_named, SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let addresses = vec![
"D100".to_string(),
"D200:F".to_string(),
"D50.3".to_string(),
"M100".to_string(),
"LTN10:D".to_string(),
];
let snapshot = read_named(&client, &addresses).await?;
println!("{:?}", snapshot);
client.close().await?;
Ok(())
}
Block reads
use plc_comm_slmp::{
read_words_chunked, read_words_single_request, SlmpAddress, SlmpClient,
SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let start = SlmpAddress::parse("D100")?;
let single = read_words_single_request(&client, start, 8).await?;
let chunked = read_words_chunked(&client, start, 128, 32).await?;
println!("{:?}", single);
println!("{:?}", chunked);
client.close().await?;
Ok(())
}
Bit in word
Use .n notation when reading through read_named, and use write_bit_in_word when you need to update one bit inside a word.
use plc_comm_slmp::{
read_named, write_bit_in_word, SlmpAddress, SlmpClient, SlmpConnectionOptions,
SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
write_bit_in_word(&client, SlmpAddress::parse("D50")?, 3, true).await?;
let addresses = vec!["D50.3".to_string()];
let snapshot = read_named(&client, &addresses).await?;
println!("{:?}", snapshot);
client.close().await?;
Ok(())
}
Polling
use std::time::Duration;
use futures_util::StreamExt;
use plc_comm_slmp::{
poll_named, SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let addresses = vec!["D100".to_string(), "M100".to_string(), "D50.3".to_string()];
let mut stream = Box::pin(poll_named(&client, &addresses, Duration::from_millis(500)));
if let Some(snapshot) = stream.next().await.transpose()? {
println!("{:?}", snapshot);
}
client.close().await?;
Ok(())
}
Device range catalog
read_device_range_catalog reads live device range bounds after you connect. It requires an explicit profile through SlmpConnectionOptions; it does not auto-discover your intended profile.
use plc_comm_slmp::{SlmpClient, SlmpConnectionOptions, SlmpPlcProfile};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let catalog = client.read_device_range_catalog().await?;
if let Some(entry) = catalog.entries.iter().find(|entry| entry.supported) {
println!("{:?}", entry);
}
client.close().await?;
Ok(())
}
Long device families
LTN, LSTN, LCN, and LZ are 32-bit families. Always use :D or :L suffixes in named addresses.
use plc_comm_slmp::{
read_named, SlmpClient, SlmpConnectionOptions, SlmpPlcProfile,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcProfile::IqR);
options.port = 1025;
let client = SlmpClient::connect(options).await?;
let addresses = vec![
"LTN10:D".to_string(),
"LSTN20:L".to_string(),
"LCN30:D".to_string(),
"LZ0:D".to_string(),
];
let snapshot = read_named(&client, &addresses).await?;
println!("{:?}", snapshot);
client.close().await?;
Ok(())
}
Caution: Plain word access to LTN/LSTN/LCN/LZ is rejected by the guarded low-level routes. Use helper APIs with
:Dor:L.
Address reference table
| Form | Example | Meaning |
|---|---|---|
| Plain word | D100 |
Unsigned 16-bit word. |
| Plain bit | M100 |
Boolean bit. |
:U |
D100:U |
Unsigned 16-bit word. |
:S |
D100:S |
Signed 16-bit word. |
:D |
D100:D |
Unsigned 32-bit value. |
:L |
D100:L |
Signed 32-bit value. |
:F |
D100:F |
32-bit float. |
.n |
D50.3 |
Bit n inside a word, where n is 0 through F. |