1use std::io;
2use thiserror::Error;
3
4#[derive(Debug, Error)]
5pub enum Error {
6 #[error(transparent)]
7 IoErr(#[from] io::Error),
8
9 #[error(transparent)]
10 TpktErr(#[from] tpkt::Error),
11
12 #[error("Error: {0}")]
13 Err(String),
14
15 #[error("WriteTimeout")]
16 WriteTimeout,
17
18 #[error("ReadTimeout")]
19 ReadTimeout,
20
21 #[error("Error: {0}")]
22 ConnectErr(String),
23
24 #[error("InvalidBitAddr: {0}")]
25 InvalidBitAddr(u16),
26}
27
28pub type Result<T> =
29 std::result::Result<T, Error>;
30
31use std::{
50 error, fmt,
51 io::{Error as IOError, ErrorKind},
52};
53
54const TCP_SOCKET_CREATION: i32 = 1;
55const TCP_CONNECTION_TIMEOUT: i32 = 2;
56const TCP_CONNECTION_FAILED: i32 = 3;
57const TCP_RECEIVE_TIMEOUT: i32 = 4;
58const TCP_DATA_RECEIVE: i32 = -5;
59const TCP_SEND_TIMEOUT: i32 = 0x00000006;
60const TCP_DATA_SEND: i32 = 0x00000007;
61const TCP_CONNECTION_RESET: i32 = 0x00000008;
62const TCP_NOT_CONNECTED: i32 = 0x00000009;
63const TCP_UNREACHALE_HOST: i32 = 0x00002751;
64
65const ISO_CONNECT: i32 = 0x00010000;
66pub(crate) const ISO_INVALID_PDU: i32 =
67 0x00030000; pub(crate) const ISO_INVALID_DATA_SIZE: i32 =
69 0x00040000;
70
71pub(crate) const CLI_NEGOTIATING_PDU: i32 =
72 0x00100000;
73const CLI_INVALID_PARAMS: i32 = 0x00200000;
74const CLI_JOB_PENDING: i32 = 0x00300000;
75const CLI_TOO_MANY_ITEMS: i32 = 0x00400000;
76const CLI_INVALID_DWORD_LEN: i32 = 0x00500000;
77const CLI_PARTIAL_DATA_WRITTEN: i32 = 0x00600000;
78const CLI_SIZE_OVER_PDU: i32 = 0x00700000;
79pub(crate) const CLI_INVALID_PLC_ANSWER: i32 =
80 0x00800000;
81const CLI_ADDRESS_OUT_OF_RANGE: i32 = 0x00900000;
82const CLI_INVALID_TRANSPORT_SIZE: i32 =
83 0x00A00000;
84const CLI_WRITE_DATA_SIZE_MISMATCH: i32 =
85 0x00B00000;
86const CLI_ITEM_NOT_AVAILABLE: i32 = 0x00C00000;
87const CLI_INVALID_VALUE: i32 = 0x00D00000;
88pub(crate) const CLI_CANNOT_START_PLC: i32 =
89 0x00E00000;
90pub(crate) const CLI_ALREADY_RUN: i32 =
91 0x00F00000;
92pub(crate) const CLI_CANNOT_STOP_PLC: i32 =
93 0x01000000;
94const CLI_CANNOT_COPY_RAM_TO_ROM: i32 =
95 0x01100000;
96const CLI_CANNOT_COMPRESS: i32 = 0x01200000;
97pub(crate) const CLI_ALREADY_STOP: i32 =
98 0x01300000;
99const CLI_FUN_NOT_AVAILABLE: i32 = 0x01400000;
100const CLI_UPLOAD_SEQUENCE_FAILED: i32 =
101 0x01500000;
102const CLI_INVALID_DATA_SIZE_RECVD: i32 =
103 0x01600000;
104const CLI_INVALID_BLOCK_TYPE: i32 = 0x01700000;
105const CLI_INVALID_BLOCK_NUMBER: i32 = 0x01800000;
106const CLI_INVALID_BLOCK_SIZE: i32 = 0x01900000;
107const CLI_NEED_PASSWORD: i32 = 0x01D00000;
108const CLI_INVALID_PASSWORD: i32 = 0x01E00000;
109const CLI_NO_PASSWORD_TO_SET_OR_CLEAR: i32 =
110 0x01F00000;
111const CLI_JOB_TIMEOUT: i32 = 0x02000000;
112const CLI_PARTIAL_DATA_READ: i32 = 0x02100000;
113const CLI_BUFFER_TOO_SMALL: i32 = 0x02200000;
114const CLI_FUNCTION_REFUSED: i32 = 0x02300000;
115const CLI_DESTROYING: i32 = 0x02400000;
116const CLI_INVALID_PARAM_NUMBER: i32 = 0x02500000;
117const CLI_CANNOT_CHANGE_PARAM: i32 = 0x02600000;
118const CLI_FUNCTION_NOT_IMPLEMENTED: i32 =
119 0x02700000;
120
121const CODE_7_ADDRESS_OUT_OF_RANGE: i32 = 5;
122const CODE_7_INVALID_TRANSPORT_SIZE: i32 = 6;
123const CODE_7_WRITE_DATA_SIZE_MISMATCH: i32 = 7;
124const CODE_7_RES_ITEM_NOT_AVAILABLE: i32 = 10;
125const CODE_7_RES_ITEM_NOT_AVAILABLE1: i32 = 53769;
126const CODE_7_INVALID_VALUE: i32 = 56321;
127const CODE_7_NEED_PASSWORD: i32 = 53825;
128const CODE_7_INVALID_PASSWORD: i32 = 54786;
129const CODE_7_NO_PASSWORD_TO_CLEAR: i32 = 54788;
130const CODE_7_NO_PASSWORD_TO_SET: i32 = 54789;
131const CODE_7_FUN_NOT_AVAILABLE: i32 = 33028;
132const CODE_7_DATA_OVER_PDU: i32 = 34048;
133
134#[derive(Debug)]
135pub enum S7ConnectError {
136 ConnectFail(String),
137 Lock,
138 IOError(ErrorKind),
139 Response {
140 code: i32,
141 },
142 CPU {
143 code: i32,
144 },
145 InvalidInput {
146 input: String,
147 },
148 Send,
149 Iso,
150 PduLength(u16),
151 TryFrom(Vec<u8>, String),
152 InvalidCpuStatus(u8),
153 InvalidResponse {
154 reason: String,
155 bytes: Vec<u8>,
156 },
157}
158
159impl fmt::Display for S7ConnectError {
160 fn fmt(
161 &self,
162 f: &mut fmt::Formatter,
163 ) -> fmt::Result {
164 match self {
165 S7ConnectError::ConnectFail(s) => {
166 write!(
167 f,
168 "connection error: {}",
169 s
170 )
171 },
172 S7ConnectError::Lock => {
173 write!(f, "Lock error: panicked")
174 },
175 S7ConnectError::IOError(kind) => {
176 write!(f, "IO error: {:?}", kind)
177 },
178 S7ConnectError::Response { code } => {
179 write!(
180 f,
181 "Error response: {}",
182 error_text(*code)
183 )
184 },
185 S7ConnectError::CPU { code } => {
186 write!(
187 f,
188 "Error response CPU: {}",
189 error_text(cpu_error(*code))
190 )
191 },
192 S7ConnectError::InvalidInput {
193 input,
194 } => write!(
195 f,
196 "Invalid input: {}",
197 input
198 ),
199 S7ConnectError::Send => {
200 write!(f, "Send connection error")
201 },
202 S7ConnectError::Iso => {
203 write!(f, "ISO connection error")
204 },
205 S7ConnectError::PduLength(pdu) => {
206 write!(
207 f,
208 "PDU length connection \
209 error {}",
210 pdu
211 )
212 },
213 S7ConnectError::TryFrom(
214 bytes,
215 reason,
216 ) => {
217 write!(
218 f,
219 "Could not read bytes {:?} \
220 reason {}",
221 bytes, reason
222 )
223 },
224 S7ConnectError::InvalidCpuStatus(
225 status,
226 ) => write!(
227 f,
228 "Invalid cpu status {}",
229 status
230 ),
231 S7ConnectError::InvalidResponse {
232 reason,
233 bytes,
234 } => {
235 write!(
236 f,
237 "Invalid response {:?} err \
238 {}",
239 bytes, reason
240 )
241 },
242 }
252 }
253}
254
255impl From<IOError> for S7ConnectError {
256 fn from(e: IOError) -> Self {
257 S7ConnectError::IOError(e.kind())
258 }
259}
260impl error::Error for S7ConnectError {
263 fn source(
264 &self,
265 ) -> Option<&(dyn error::Error + 'static)>
266 {
267 None
268 }
269}
270
271fn cpu_error(err: i32) -> i32 {
273 match err {
274 CODE_7_ADDRESS_OUT_OF_RANGE => {
275 CLI_ADDRESS_OUT_OF_RANGE
276 },
277 CODE_7_INVALID_TRANSPORT_SIZE => {
278 CLI_INVALID_TRANSPORT_SIZE
279 },
280 CODE_7_WRITE_DATA_SIZE_MISMATCH => {
281 CLI_WRITE_DATA_SIZE_MISMATCH
282 },
283 CODE_7_RES_ITEM_NOT_AVAILABLE
284 | CODE_7_RES_ITEM_NOT_AVAILABLE1 => {
285 CLI_ITEM_NOT_AVAILABLE
286 },
287 CODE_7_DATA_OVER_PDU => CLI_SIZE_OVER_PDU,
288 CODE_7_INVALID_VALUE => CLI_INVALID_VALUE,
289 CODE_7_FUN_NOT_AVAILABLE => {
290 CLI_FUN_NOT_AVAILABLE
291 },
292 CODE_7_NEED_PASSWORD => CLI_NEED_PASSWORD,
293 CODE_7_INVALID_PASSWORD => {
294 CLI_INVALID_PASSWORD
295 },
296 CODE_7_NO_PASSWORD_TO_SET
297 | CODE_7_NO_PASSWORD_TO_CLEAR => {
298 CLI_NO_PASSWORD_TO_SET_OR_CLEAR
299 },
300 _ => CLI_FUNCTION_REFUSED,
301 }
302}
303
304fn error_text(err: i32) -> &'static str {
307 match err {
308 0 => "OK",
309 TCP_SOCKET_CREATION => {
310 "SYS : Error creating the Socket"
311 },
312 TCP_CONNECTION_TIMEOUT => {
313 "TCP : Connection Timeout"
314 },
315 TCP_CONNECTION_FAILED => {
316 "TCP : Connection Error"
317 },
318 TCP_RECEIVE_TIMEOUT => {
319 "TCP : Data receive Timeout"
320 },
321 TCP_DATA_RECEIVE => {
322 "TCP : Error receiving Data"
323 },
324 TCP_SEND_TIMEOUT => {
325 "TCP : Data send Timeout"
326 },
327 TCP_DATA_SEND => {
328 "TCP : Error sending Data"
329 },
330 TCP_CONNECTION_RESET => {
331 "TCP : Connection reset by the Peer"
332 },
333 TCP_NOT_CONNECTED => {
334 "CLI : Client not connected"
335 },
336 TCP_UNREACHALE_HOST => {
337 "TCP : Unreachable host"
338 },
339
340 ISO_CONNECT => "ISO : Connection Error",
341 ISO_INVALID_PDU => {
342 "ISO : Invalid PDU received"
343 },
344 ISO_INVALID_DATA_SIZE => {
345 "ISO : Invalid Buffer passed to \
346 Send/Receive"
347 },
348
349 CLI_NEGOTIATING_PDU => {
350 "CLI : Error in PDU negotiation"
351 },
352 CLI_INVALID_PARAMS => {
353 "CLI : invalid param(s) supplied"
354 },
355 CLI_JOB_PENDING => "CLI : Job pending",
356 CLI_TOO_MANY_ITEMS => {
357 "CLI : too may items (>20) in multi \
358 read/write"
359 },
360 CLI_INVALID_DWORD_LEN => {
361 "CLI : invalid WordLength"
362 },
363 CLI_PARTIAL_DATA_WRITTEN => {
364 "CLI : Partial data written"
365 },
366 CLI_SIZE_OVER_PDU => {
367 "CPU : total data exceeds the PDU \
368 size"
369 },
370 CLI_INVALID_PLC_ANSWER => {
371 "CLI : invalid CPU answer"
372 },
373 CLI_ADDRESS_OUT_OF_RANGE => {
374 "CPU : Address out of range"
375 },
376 CLI_INVALID_TRANSPORT_SIZE => {
377 "CPU : Invalid Transport size"
378 },
379 CLI_WRITE_DATA_SIZE_MISMATCH => {
380 "CPU : Data size mismatch"
381 },
382 CLI_ITEM_NOT_AVAILABLE => {
383 "CPU : Item not available"
384 },
385 CLI_INVALID_VALUE => {
386 "CPU : Invalid value supplied"
387 },
388 CLI_CANNOT_START_PLC => {
389 "CPU : Cannot start PLC"
390 },
391 CLI_ALREADY_RUN => {
392 "CPU : PLC already RUN"
393 },
394 CLI_CANNOT_STOP_PLC => {
395 "CPU : Cannot stop PLC"
396 },
397 CLI_CANNOT_COPY_RAM_TO_ROM => {
398 "CPU : Cannot copy RAM to ROM"
399 },
400 CLI_CANNOT_COMPRESS => {
401 "CPU : Cannot compress"
402 },
403 CLI_ALREADY_STOP => {
404 "CPU : PLC already STOP"
405 },
406 CLI_FUN_NOT_AVAILABLE => {
407 "CPU : Function not available"
408 },
409 CLI_UPLOAD_SEQUENCE_FAILED => {
410 "CPU : Upload sequence failed"
411 },
412 CLI_INVALID_DATA_SIZE_RECVD => {
413 "CLI : Invalid data size received"
414 },
415 CLI_INVALID_BLOCK_TYPE => {
416 "CLI : Invalid block type"
417 },
418 CLI_INVALID_BLOCK_NUMBER => {
419 "CLI : Invalid block number"
420 },
421 CLI_INVALID_BLOCK_SIZE => {
422 "CLI : Invalid block size"
423 },
424 CLI_NEED_PASSWORD => {
425 "CPU : Function not authorized for \
426 current protection level"
427 },
428 CLI_INVALID_PASSWORD => {
429 "CPU : Invalid password"
430 },
431 CLI_NO_PASSWORD_TO_SET_OR_CLEAR => {
432 "CPU : No password to set or clear"
433 },
434 CLI_JOB_TIMEOUT => "CLI : Job Timeout",
435 CLI_FUNCTION_REFUSED => {
436 "CLI : function refused by CPU \
437 (Unknown error)"
438 },
439 CLI_PARTIAL_DATA_READ => {
440 "CLI : Partial data read"
441 },
442 CLI_BUFFER_TOO_SMALL => {
443 "CLI : The buffer supplied is too \
444 small to accomplish the operation"
445 },
446 CLI_DESTROYING => {
447 "CLI : Cannot perform (destroying)"
448 },
449 CLI_INVALID_PARAM_NUMBER => {
450 "CLI : Invalid Param Number"
451 },
452 CLI_CANNOT_CHANGE_PARAM => {
453 "CLI : Cannot change this param now"
454 },
455 CLI_FUNCTION_NOT_IMPLEMENTED => {
456 "CLI : Function not implemented"
457 },
458 _ => "CLI : Unknown error",
459 }
460}