rs_melsec/
db.rs

1use std::error::Error;
2
3pub mod consts {
4    // PLC definition
5    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    // communication type
12    pub const COMMTYPE_BINARY: &str = "binary";
13    pub const COMMTYPE_ASCII: &str = "ascii";
14
15    // endian types
16    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
22// Commands
23pub 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
42// SubCommands
43pub 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    // Define constants
109    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    // Static methods
153    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}