Getting started
Requirements
Use Rust 1.85 or newer. Rust 1.85 is the crate's declared minimum supported compiler version.
Choose these values for the actual PLC before connecting:
- host name resolving to IPv4, or an IPv4 address;
- destination port in
1..=65535; HostLinkTransportMode::TcporHostLinkTransportMode::Udp;- the exact canonical PLC profile from PROFILES.md.
The library does not infer any of those endpoint conditions. Communication timeout may be omitted and is then 3 seconds.
The endpoint contract is IPv4-only because the target PLC configuration is
IPv4. IPv6 literals fail before socket creation; a hostname with no IPv4
result fails without sending a Host Link command. IPv4 literals must not use
URI-style brackets: use 127.0.0.1, not [127.0.0.1].
Add the crate
cargo add plc-comm-kv-hostlink
Connect and read
use plc_comm_kv_hostlink::{
HostLinkClient, HostLinkConnectionOptions, HostLinkTransportMode,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let options = HostLinkConnectionOptions::new(
"192.168.250.100",
8501,
HostLinkTransportMode::Tcp,
"keyence:kv-8000",
)?;
// Construction performs no network I/O. `connect` explicitly opens the
// transport before the first command.
let client = HostLinkClient::connect(options).await?;
let value = client.read_typed("DM0", "U").await?;
println!("{value:?}");
client.close().await?;
Ok(())
}
HostLinkClient::new creates a disconnected client. Call open before any
command. An unconnected command returns HostLinkError::NotConnected without
creating a socket. After a TCP timeout, EOF, transport failure, or dropped
in-flight future, call open explicitly again. UDP keeps the resolved logical
endpoint and replaces only the affected socket on the next command. Commands
never retry the failed operation. Dropping a future produces no library
Result, and a caller that drops a possibly transmitted write must treat its
PLC outcome as unknown.
First controlled write
Use only an address reserved by your PLC program for testing.
let original = client.read_typed("DM120", "U").await?;
client.write_typed("DM120", "U", 1234_u16).await?;
let readback_result = client.read_typed("DM120", "U").await;
let restore_result = client.write_typed("DM120", "U", original).await;
restore_result?;
let readback = readback_result?;
println!("{readback:?}");
The readback result is not propagated until after restoration is attempted. If
the test write itself has an unknown outcome, do not automatically restore or
retry; reopen the client, inspect DM120, and reconcile it explicitly. If the
restoration attempt fails, also inspect DM120 and reconcile its value manually
before continuing.
Common failures
| Symptom | Check |
|---|---|
| Constructor rejects the profile | Use an exact canonical profile string; aliases and display names are rejected. |
Command returns NotConnected |
Call open or use HostLinkClient::connect/open_and_connect. |
| Numeric read rejects the input | Pass a base device and an explicit format; do not pass DM100.D to low-level APIs. |
| A large read is rejected before transport | Reduce it to the one-request limit. The library does not split requests. |
| IPv6 endpoint is rejected | Configure the PLC's IPv4 address or a hostname with an IPv4 result. |
Shared setup and troubleshooting material is published on the PLC communication documentation site.