1use std::error::Error;
2
3pub mod consts {
4 pub const Q_SERIES: &str = "Q";
6 pub const L_SERIES: &str = "L";
7 pub const QNA_SERIES: &str = "QnA";
8 pub const IQL_SERIES: &str = "iQ-L";
9 pub const IQR_SERIES: &str = "iQ-R";
10
11 pub const COMMTYPE_BINARY: &str = "binary";
13 pub const COMMTYPE_ASCII: &str = "ascii";
14
15 pub const ENDIAN_NATIVE: char = '=';
17 pub const ENDIAN_LITTLE: char = '<';
18 pub const ENDIAN_BIG: char = '>';
19 pub const ENDIAN_NETWORK: char = '!';
20}
21
22pub mod commands {
24 pub const BATCH_READ: u16 = 0x0401;
25 pub const BATCH_WRITE: u16 = 0x1401;
26 pub const RANDOM_READ: u16 = 0x0403;
27 pub const RANDOM_WRITE: u16 = 0x1402;
28 pub const MONITOR_REG: u16 = 0x0801;
29 pub const MONITOR: u16 = 0x0802;
30 pub const REMOTE_RUN: u16 = 0x1001;
31 pub const REMOTE_STOP: u16 = 0x1002;
32 pub const REMOTE_PAUSE: u16 = 0x1003;
33 pub const REMOTE_LATCH_CLEAR: u16 = 0x1005;
34 pub const REMOTE_RESET: u16 = 0x1006;
35 pub const REMOTE_UNLOCK: u16 = 0x1630;
36 pub const REMOTE_LOCK: u16 = 0x1631;
37 pub const ERROR_LED_OFF: u16 = 0x1617;
38 pub const READ_CPU_MODEL: u16 = 0x0101;
39 pub const LOOPBACK_TEST: u16 = 0x0619;
40}
41
42pub mod subcommands {
44 pub const ZERO: u16 = 0x0000;
45 pub const ONE: u16 = 0x0001;
46 pub const TWO: u16 = 0x0002;
47 pub const THREE: u16 = 0x0003;
48 pub const FIVE: u16 = 0x0005;
49 pub const A: u16 = 0x000A;
50 pub const F: u16 = 0x000F;
51}
52
53#[derive(Debug, PartialEq, Clone)]
54pub enum DataType {
55 BIT,
56 SWORD,
57 UWORD,
58 SDWORD,
59 UDWORD,
60 FLOAT,
61 DOUBLE,
62 SLWORD,
63 ULWORD,
64}
65
66impl DataType {
67 pub fn size(&self) -> i8 {
68 match self {
69 DataType::BIT | DataType::SWORD | DataType::UWORD => 2,
70 DataType::SDWORD | DataType::UDWORD | DataType::FLOAT => 4,
71 DataType::DOUBLE | DataType::SLWORD | DataType::ULWORD => 8,
72 }
73 }
74
75 pub fn from_str(s: &str) -> Option<Self> {
76 match s {
77 "b" => Some(DataType::BIT),
78 "h" => Some(DataType::SWORD),
79 "H" => Some(DataType::UWORD),
80 "i" => Some(DataType::SDWORD),
81 "I" => Some(DataType::UDWORD),
82 "f" => Some(DataType::FLOAT),
83 "d" => Some(DataType::DOUBLE),
84 "q" => Some(DataType::SLWORD),
85 "Q" => Some(DataType::ULWORD),
86 _ => None,
87 }
88 }
89
90 pub fn to_struct_type(&self) -> &str {
91 match self {
92 DataType::BIT => "b",
93 DataType::SWORD => "h",
94 DataType::UWORD => "H",
95 DataType::SDWORD => "i",
96 DataType::UDWORD => "I",
97 DataType::FLOAT => "f",
98 DataType::DOUBLE => "d",
99 DataType::SLWORD => "q",
100 DataType::ULWORD => "Q",
101 }
102 }
103}
104
105pub struct DeviceConstants;
106
107impl DeviceConstants {
108 pub const SM_DEVICE: u8 = 0x91;
110 pub const SD_DEVICE: u8 = 0xA9;
111 pub const X_DEVICE: u8 = 0x9C;
112 pub const Y_DEVICE: u8 = 0x9D;
113 pub const M_DEVICE: u8 = 0x90;
114 pub const L_DEVICE: u8 = 0x92;
115 pub const F_DEVICE: u8 = 0x93;
116 pub const V_DEVICE: u8 = 0x94;
117 pub const B_DEVICE: u8 = 0xA0;
118 pub const D_DEVICE: u8 = 0xA8;
119 pub const W_DEVICE: u8 = 0xB4;
120 pub const TS_DEVICE: u8 = 0xC1;
121 pub const TC_DEVICE: u8 = 0xC0;
122 pub const TN_DEVICE: u8 = 0xC2;
123 pub const SS_DEVICE: u8 = 0xC7;
124 pub const SC_DEVICE: u8 = 0xC6;
125 pub const SN_DEVICE: u8 = 0xC8;
126 pub const CS_DEVICE: u8 = 0xC4;
127 pub const CC_DEVICE: u8 = 0xC3;
128 pub const CN_DEVICE: u8 = 0xC5;
129 pub const SB_DEVICE: u8 = 0xA1;
130 pub const SW_DEVICE: u8 = 0xB5;
131 pub const DX_DEVICE: u8 = 0xA2;
132 pub const DY_DEVICE: u8 = 0xA3;
133 pub const R_DEVICE: u8 = 0xAF;
134 pub const ZR_DEVICE: u8 = 0xB0;
135
136 pub const LTS_DEVICE: u8 = 0x51;
137 pub const LTC_DEVICE: u8 = 0x50;
138 pub const LTN_DEVICE: u8 = 0x52;
139 pub const LSTS_DEVICE: u8 = 0x59;
140 pub const LSTC_DEVICE: u8 = 0x58;
141 pub const LSTN_DEVICE: u8 = 0x5A;
142 pub const LCS_DEVICE: u8 = 0x55;
143 pub const LCC_DEVICE: u8 = 0x54;
144 pub const LCN_DEVICE: u8 = 0x56;
145 pub const LZ_DEVICE: u8 = 0x62;
146 pub const RD_DEVICE: u8 = 0x2C;
147
148 pub const BIT_DEVICE: &'static str = "bit";
149 pub const WORD_DEVICE: &'static str = "word";
150 pub const DWORD_DEVICE: &'static str = "dword";
151
152 pub fn get_binary_device_code(
154 plc_type: &str,
155 device_name: &str,
156 ) -> Result<(u8, u32), Box<dyn Error>> {
157 match device_name {
158 "SM" => Ok((DeviceConstants::SM_DEVICE, 10)),
159 "SD" => Ok((DeviceConstants::SD_DEVICE, 10)),
160 "X" => Ok((DeviceConstants::X_DEVICE, 16)),
161 "Y" => Ok((DeviceConstants::Y_DEVICE, 16)),
162 "M" => Ok((DeviceConstants::M_DEVICE, 10)),
163 "L" => Ok((DeviceConstants::L_DEVICE, 10)),
164 "F" => Ok((DeviceConstants::F_DEVICE, 10)),
165 "V" => Ok((DeviceConstants::V_DEVICE, 10)),
166 "B" => Ok((DeviceConstants::B_DEVICE, 16)),
167 "D" => Ok((DeviceConstants::D_DEVICE, 10)),
168 "W" => Ok((DeviceConstants::W_DEVICE, 16)),
169 "TS" => Ok((DeviceConstants::TS_DEVICE, 10)),
170 "TC" => Ok((DeviceConstants::TC_DEVICE, 10)),
171 "TN" => Ok((DeviceConstants::TN_DEVICE, 10)),
172 "SS" => Ok((DeviceConstants::SS_DEVICE, 10)),
173 "SC" => Ok((DeviceConstants::SC_DEVICE, 10)),
174 "SN" => Ok((DeviceConstants::SN_DEVICE, 10)),
175 "CS" => Ok((DeviceConstants::CS_DEVICE, 10)),
176 "CC" => Ok((DeviceConstants::CC_DEVICE, 10)),
177 "CN" => Ok((DeviceConstants::CN_DEVICE, 10)),
178 "SB" => Ok((DeviceConstants::SB_DEVICE, 16)),
179 "SW" => Ok((DeviceConstants::SW_DEVICE, 16)),
180 "DX" => Ok((DeviceConstants::DX_DEVICE, 16)),
181 "DY" => Ok((DeviceConstants::DY_DEVICE, 16)),
182 "R" => Ok((DeviceConstants::R_DEVICE, 10)),
183 "ZR" => Ok((DeviceConstants::ZR_DEVICE, 16)),
184 "LTS" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LTS_DEVICE, 10)),
185 "LTC" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LTC_DEVICE, 10)),
186 "LTN" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LTN_DEVICE, 10)),
187 "LSTS" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LSTS_DEVICE, 10)),
188 "LSTC" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LSTC_DEVICE, 10)),
189 "LSTN" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LSTN_DEVICE, 10)),
190 "LCS" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LCS_DEVICE, 10)),
191 "LCC" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LCC_DEVICE, 10)),
192 "LCN" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LCN_DEVICE, 10)),
193 "LZ" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::LZ_DEVICE, 10)),
194 "RD" if plc_type == "iQR_SERIES" => Ok((DeviceConstants::RD_DEVICE, 10)),
195 _ => Err(format!(
196 "failed to get binary device code for device: {}",
197 device_name,
198 )
199 .into()),
200 }
201 }
202
203 pub fn get_ascii_device_code(
204 plc_type: &str,
205 device_name: &str,
206 ) -> Result<(String, u32), Box<dyn Error>> {
207 let padding = if plc_type == consts::IQR_SERIES { 4 } else { 2 };
208 let padded_name = format!("{:*<width$}", device_name, width = padding);
209
210 match device_name {
211 "SM" | "SD" | "X" | "Y" | "M" | "L" | "F" | "V" | "B" | "D" | "W" | "TS" | "TC"
212 | "TN" | "CS" | "CC" | "CN" | "SB" | "SW" | "DX" | "DY" | "R" | "ZR" => {
213 Ok((padded_name, 16))
214 }
215 "STS" if plc_type == consts::IQR_SERIES => {
216 Ok((format!("{:*<width$}", "STS", width = padding), 10))
217 }
218 "STS" => Ok((format!("{:*<width$}", "SS", width = padding), 10)),
219 "STC" if plc_type == consts::IQR_SERIES => {
220 Ok((format!("{:*<width$}", "STC", width = padding), 10))
221 }
222 "STC" => Ok((format!("{:*<width$}", "SC", width = padding), 10)),
223 "STN" if plc_type == consts::IQR_SERIES => {
224 Ok((format!("{:*<width$}", "STN", width = padding), 10))
225 }
226 "STN" => Ok((format!("{:*<width$}", "SN", width = padding), 10)),
227 "LTS" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
228 "LTC" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
229 "LTN" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
230 "LSTS" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
231 "LSTN" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
232 "LCS" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
233 "LCC" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
234 "LCN" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
235 "LZ" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
236 "RD" if plc_type == "iQR_SERIES" => Ok((padded_name, 10)),
237 _ => Err(format!(
238 "failed to get ascii device code for device: {}",
239 device_name,
240 )
241 .into()),
242 }
243 }
244
245 pub fn get_device_type(
246 plc_type: &str,
247 device_name: &str,
248 ) -> Result<&'static str, Box<dyn Error>> {
249 match device_name {
250 "SM" | "X" | "Y" | "M" | "L" | "F" | "V" | "B" | "TS" | "TC" | "STS" | "STC" | "CS"
251 | "CC" | "SB" | "DX" | "DY" => Ok(DeviceConstants::BIT_DEVICE),
252 "SD" | "D" | "W" | "TN" | "STN" | "CN" | "SW" | "R" | "ZR" => {
253 Ok(DeviceConstants::WORD_DEVICE)
254 }
255 "LSTN" | "LCN" | "LZ" => match plc_type {
256 consts::IQR_SERIES => Ok(DeviceConstants::DWORD_DEVICE),
257 _ => Err(format!("Unsupported PLC type: {}", plc_type).into()),
258 },
259 "LST" | "LTC" | "LTN" | "LSTS" | "LCS" | "LCC" => match plc_type {
260 consts::IQR_SERIES => Ok(DeviceConstants::BIT_DEVICE),
261 _ => Err(format!("Unsupported PLC type: {}", plc_type).into()),
262 },
263 "RD" => match plc_type {
264 consts::IQR_SERIES => Ok(DeviceConstants::WORD_DEVICE),
265 _ => Err(format!("Unsupported PLC type: {}", plc_type).into()),
266 },
267 _ => Err(format!(
268 "failed to get ascii device code for device: {}",
269 device_name,
270 )
271 .into()),
272 }
273 }
274}