1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Async Rust client for Mitsubishi SLMP Binary 3E and 4E.
//!
//! This crate follows the same operation semantics as the sibling
//! `plc-comm-slmp-python`, `.NET`, `C++`, `Node-RED`, and `cross-verify`
//! projects in the same family. The intended flow is:
//!
//! 1. connect with [`SlmpConnectionOptions`] and [`SlmpClient`]
//! 2. use raw device APIs for low-level control
//! 3. use helper APIs such as [`read_named`] and [`write_named`] for
//! application-facing snapshots and typed values
//! 4. validate behavior through `plc-comm-slmp-cross-verify`
//!
//! # Quick Start
//!
//! ```no_run
//! use plc_comm_slmp::{
//! SlmpAddress, SlmpClient, SlmpConnectionOptions, SlmpPlcFamily,
//! };
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let runtime = tokio::runtime::Builder::new_current_thread()
//! .enable_all()
//! .build()?;
//! runtime.block_on(async {
//! let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcFamily::IqR);
//! options.port = 1025;
//!
//! let client = SlmpClient::connect(options).await?;
//! let words = client.read_words_raw(SlmpAddress::parse("D100")?, 2).await?;
//! println!("{words:?}");
//! Ok(())
//! })
//! # }
//! ```
//!
//! # Recommended High-Level Helpers
//!
//! ```no_run
//! use plc_comm_slmp::{
//! NamedAddress, SlmpClient, SlmpConnectionOptions, SlmpPlcFamily, SlmpValue, read_named,
//! write_named,
//! };
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let runtime = tokio::runtime::Builder::new_current_thread()
//! .enable_all()
//! .build()?;
//! runtime.block_on(async {
//! let mut options = SlmpConnectionOptions::new("192.168.250.100", SlmpPlcFamily::IqF);
//! options.port = 1025;
//! let client = SlmpClient::connect(options).await?;
//!
//! let snapshot = read_named(
//! &client,
//! &["D100".into(), "X100".into(), "D50.3".into(), "LTN10:D".into()],
//! )
//! .await?;
//! println!("{snapshot:?}");
//!
//! let mut updates = NamedAddress::new();
//! updates.insert("D300".into(), SlmpValue::U16(42));
//! updates.insert("D400:F".into(), SlmpValue::F32(3.14));
//! write_named(&client, &updates).await?;
//! Ok(())
//! })
//! # }
//! ```
//!
//! # Address Notes
//!
//! - Plain word devices: `D100`, `R50`, `ZR0`
//! - Plain bit devices: `M100`, `X20`, `Y20`, `B10`
//! - Typed suffixes: `D200:F`, `D300:D`, `D400:L`
//! - Bit-in-word form: `D50.3`
//! - Long current values: `LTN10:D`, `LSTN20:D`, `LCN30:D`
//! - Extended devices: `J1\\W10`, `U3\\G100`, `U1\\HG0`
//!
//! `.bit` notation is only valid for word devices. Long timer state reads
//! (`LTS`, `LTC`, `LSTS`, `LSTC`) are decoded through the corresponding
//! current-value blocks. Long counter state reads (`LCS`, `LCC`) use direct bit
//! read. `LCN` current values use random dword access in the high-level helpers,
//! and high-level state writes use random bit write (`0x1402`).
//!
//! # Examples
//!
//! The repository includes runnable examples under `examples/`:
//!
//! - `raw_read_write`
//! - `named_helpers`
//! - `advanced_operations`
//!
//! Run them with `cargo run --features cli --example <name>`.
//!
//! # Verification
//!
//! This crate is meant to participate in `plc-comm-slmp-cross-verify`.
//! The canonical wrapper binary is `slmp_verify_client`.
//!
pub use ;
pub use ;
pub use ;
pub use ;
pub use SlmpError;
pub use ;
pub use ;
pub use ;