1mod bits;
5pub mod memory;
6
7use std::future::Future;
8
9use rusty_modbus_types::{
10 DiagnosticSubFunction, ExceptionCode, MAX_FIFO_VALUES, MAX_PDU_SIZE, MAX_READ_COILS,
11 MAX_READ_DISCRETE_INPUTS, MAX_READ_REGISTERS, MAX_WRITE_COILS, MAX_WRITE_REGISTERS,
12};
13
14pub(crate) const MAX_FILE_RECORD_REGISTERS: usize = 122;
15pub(crate) const MAX_COMM_EVENT_LOG_EVENTS: usize = 64;
16pub(crate) const MAX_DIAGNOSTIC_RESPONSE_DATA_LEN: usize = MAX_PDU_SIZE - 3;
17pub(crate) const MAX_SERVER_ID_BYTES: usize = MAX_PDU_SIZE - 2;
18
19#[derive(Debug, Clone, Copy, Default)]
24pub struct CommEventLogMeta {
25 pub status: u16,
27 pub event_count: u16,
29 pub message_count: u16,
31}
32
33#[derive(Debug, Clone, Default)]
40pub struct CommEventLog {
41 pub status: u16,
43 pub event_count: u16,
45 pub message_count: u16,
47 pub events: Vec<u8>,
49}
50
51pub(crate) fn unpack_packed_coils(
52 quantity: u16,
53 packed_values: &[u8],
54 out: &mut [bool],
55) -> Result<usize, ExceptionCode> {
56 let quantity = validate_packed_coils(quantity, packed_values)?;
57 if out.len() < quantity {
58 return Err(ExceptionCode::IllegalDataValue);
59 }
60 for (byte_index, &byte) in packed_values.iter().enumerate() {
61 let start = byte_index * 8;
62 let bit_count = (quantity - start).min(8);
63 for bit in 0..bit_count {
64 out[start + bit] = (byte >> bit) & 1 == 1;
65 }
66 }
67 Ok(quantity)
68}
69
70pub(crate) fn unpack_register_values_be(
71 quantity: u16,
72 value_bytes: &[u8],
73 out: &mut [u16],
74) -> Result<usize, ExceptionCode> {
75 let quantity = validate_register_values_be(quantity, value_bytes)?;
76 if out.len() < quantity {
77 return Err(ExceptionCode::IllegalDataValue);
78 }
79 for (slot, chunk) in out
80 .iter_mut()
81 .zip(value_bytes.chunks_exact(2))
82 .take(quantity)
83 {
84 *slot = u16::from_be_bytes([chunk[0], chunk[1]]);
85 }
86 Ok(quantity)
87}
88
89pub(crate) fn validate_packed_coils(
90 quantity: u16,
91 packed_values: &[u8],
92) -> Result<usize, ExceptionCode> {
93 if quantity == 0 || quantity > MAX_WRITE_COILS {
94 return Err(ExceptionCode::IllegalDataValue);
95 }
96 let expected = usize::from(quantity).div_ceil(8);
97 if packed_values.len() != expected {
98 return Err(ExceptionCode::IllegalDataValue);
99 }
100 Ok(usize::from(quantity))
101}
102
103pub(crate) fn validate_register_values_be(
104 quantity: u16,
105 value_bytes: &[u8],
106) -> Result<usize, ExceptionCode> {
107 if quantity == 0 || quantity > MAX_WRITE_REGISTERS {
108 return Err(ExceptionCode::IllegalDataValue);
109 }
110 let expected = usize::from(quantity) * 2;
111 if value_bytes.len() != expected {
112 return Err(ExceptionCode::IllegalDataValue);
113 }
114 Ok(usize::from(quantity))
115}
116
117pub(crate) fn pack_coils(bits: &[bool], out: &mut [u8]) -> Result<(), ExceptionCode> {
118 let byte_count = bits.len().div_ceil(8);
119 if out.len() < byte_count {
120 return Err(ExceptionCode::IllegalDataValue);
121 }
122 for (byte_index, out_byte) in out[..byte_count].iter_mut().enumerate() {
123 let start = byte_index * 8;
124 let end = (start + 8).min(bits.len());
125 let mut byte = 0u8;
126 for (bit, &value) in bits[start..end].iter().enumerate() {
127 byte |= u8::from(value) << bit;
128 }
129 *out_byte = byte;
130 }
131 Ok(())
132}
133
134pub(crate) fn pack_registers_be(registers: &[u16], out: &mut [u8]) -> Result<(), ExceptionCode> {
135 let byte_count = registers.len() * 2;
136 if out.len() < byte_count {
137 return Err(ExceptionCode::IllegalDataValue);
138 }
139 for (chunk, &value) in out[..byte_count].chunks_exact_mut(2).zip(registers) {
140 chunk.copy_from_slice(&value.to_be_bytes());
141 }
142 Ok(())
143}
144
145pub trait DataStore: Send + Sync {
160 fn read_coils(
168 &self,
169 address: u16,
170 quantity: u16,
171 buf: &mut [bool],
172 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send;
173
174 fn read_coils_packed(
180 &self,
181 address: u16,
182 quantity: u16,
183 out: &mut [u8],
184 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
185 async move {
186 let mut values = [false; MAX_READ_COILS as usize];
187 let count = self.read_coils(address, quantity, &mut values).await?;
188 if count > values.len() || count > usize::from(quantity) {
189 return Err(ExceptionCode::ServerDeviceFailure);
190 }
191 pack_coils(&values[..count], out)?;
192 Ok(count)
193 }
194 }
195
196 fn write_coil(
198 &self,
199 address: u16,
200 value: bool,
201 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send;
202
203 fn write_coils(
205 &self,
206 address: u16,
207 values: &[bool],
208 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send;
209
210 fn write_coils_packed(
216 &self,
217 address: u16,
218 quantity: u16,
219 packed_values: &[u8],
220 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send {
221 async move {
222 let mut values = [false; MAX_WRITE_COILS as usize];
223 let quantity = unpack_packed_coils(quantity, packed_values, &mut values)?;
224 self.write_coils(address, &values[..quantity]).await
225 }
226 }
227
228 fn read_discrete_inputs(
232 &self,
233 address: u16,
234 quantity: u16,
235 buf: &mut [bool],
236 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send;
237
238 fn read_discrete_inputs_packed(
244 &self,
245 address: u16,
246 quantity: u16,
247 out: &mut [u8],
248 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
249 async move {
250 let mut values = [false; MAX_READ_DISCRETE_INPUTS as usize];
251 let count = self
252 .read_discrete_inputs(address, quantity, &mut values)
253 .await?;
254 if count > values.len() || count > usize::from(quantity) {
255 return Err(ExceptionCode::ServerDeviceFailure);
256 }
257 pack_coils(&values[..count], out)?;
258 Ok(count)
259 }
260 }
261
262 fn read_holding_registers(
266 &self,
267 address: u16,
268 quantity: u16,
269 buf: &mut [u16],
270 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send;
271
272 fn read_holding_registers_be(
279 &self,
280 address: u16,
281 quantity: u16,
282 out: &mut [u8],
283 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
284 async move {
285 let mut values = [0u16; MAX_READ_REGISTERS as usize];
286 let count = self
287 .read_holding_registers(address, quantity, &mut values)
288 .await?;
289 if count > values.len() || count > usize::from(quantity) {
290 return Err(ExceptionCode::ServerDeviceFailure);
291 }
292 pack_registers_be(&values[..count], out)?;
293 Ok(count)
294 }
295 }
296
297 fn write_register(
299 &self,
300 address: u16,
301 value: u16,
302 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send;
303
304 fn write_registers(
306 &self,
307 address: u16,
308 values: &[u16],
309 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send;
310
311 fn write_registers_be(
317 &self,
318 address: u16,
319 quantity: u16,
320 value_bytes: &[u8],
321 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send {
322 async move {
323 let mut values = [0u16; MAX_WRITE_REGISTERS as usize];
324 let quantity = unpack_register_values_be(quantity, value_bytes, &mut values)?;
325 self.write_registers(address, &values[..quantity]).await
326 }
327 }
328
329 fn read_input_registers(
333 &self,
334 address: u16,
335 quantity: u16,
336 buf: &mut [u16],
337 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send;
338
339 fn read_input_registers_be(
345 &self,
346 address: u16,
347 quantity: u16,
348 out: &mut [u8],
349 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
350 async move {
351 let mut values = [0u16; MAX_READ_REGISTERS as usize];
352 let count = self
353 .read_input_registers(address, quantity, &mut values)
354 .await?;
355 if count > values.len() || count > usize::from(quantity) {
356 return Err(ExceptionCode::ServerDeviceFailure);
357 }
358 pack_registers_be(&values[..count], out)?;
359 Ok(count)
360 }
361 }
362
363 fn read_file_record(
372 &self,
373 file_number: u16,
374 record_number: u16,
375 record_length: u16,
376 buf: &mut [u16],
377 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
378 async move {
379 let _ = (file_number, record_number, record_length, buf);
380 Err(ExceptionCode::IllegalFunction)
381 }
382 }
383
384 fn read_file_record_be(
391 &self,
392 file_number: u16,
393 record_number: u16,
394 record_length: u16,
395 out: &mut [u8],
396 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
397 async move {
398 let mut values = [0u16; MAX_FILE_RECORD_REGISTERS];
399 let count = self
400 .read_file_record(file_number, record_number, record_length, &mut values)
401 .await?;
402 if count > values.len() || count > usize::from(record_length) {
403 return Err(ExceptionCode::ServerDeviceFailure);
404 }
405 pack_registers_be(&values[..count], out)?;
406 Ok(count)
407 }
408 }
409
410 fn write_file_record(
414 &self,
415 file_number: u16,
416 record_number: u16,
417 values: &[u16],
418 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send {
419 async move {
420 let _ = (file_number, record_number, values);
421 Err(ExceptionCode::IllegalFunction)
422 }
423 }
424
425 fn write_file_record_be(
431 &self,
432 file_number: u16,
433 record_number: u16,
434 record_length: u16,
435 value_bytes: &[u8],
436 ) -> impl Future<Output = Result<(), ExceptionCode>> + Send {
437 async move {
438 let expected = usize::from(record_length) * 2;
439 if value_bytes.len() != expected {
440 return Err(ExceptionCode::IllegalDataValue);
441 }
442 let values: Vec<u16> = value_bytes
443 .chunks_exact(2)
444 .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]))
445 .collect();
446 self.write_file_record(file_number, record_number, &values)
447 .await
448 }
449 }
450
451 fn read_fifo_queue(
460 &self,
461 address: u16,
462 ) -> impl Future<Output = Result<Vec<u16>, ExceptionCode>> + Send {
463 async move {
464 let _ = address;
465 Err(ExceptionCode::IllegalDataAddress)
466 }
467 }
468
469 fn read_fifo_queue_be(
476 &self,
477 address: u16,
478 out: &mut [u8],
479 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
480 async move {
481 let values = self.read_fifo_queue(address).await?;
482 if values.len() > usize::from(MAX_FIFO_VALUES) {
483 return Err(ExceptionCode::IllegalDataValue);
484 }
485 pack_registers_be(&values, out)?;
486 Ok(values.len())
487 }
488 }
489
490 fn read_exception_status(&self) -> impl Future<Output = Result<u8, ExceptionCode>> + Send {
495 async { Err(ExceptionCode::IllegalFunction) }
496 }
497
498 fn get_comm_event_counter(
501 &self,
502 ) -> impl Future<Output = Result<(u16, u16), ExceptionCode>> + Send {
503 async { Err(ExceptionCode::IllegalFunction) }
504 }
505
506 fn get_comm_event_log(
509 &self,
510 ) -> impl Future<Output = Result<CommEventLog, ExceptionCode>> + Send {
511 async { Err(ExceptionCode::IllegalFunction) }
512 }
513
514 fn append_comm_event_log(
520 &self,
521 out: &mut Vec<u8>,
522 ) -> impl Future<Output = Result<CommEventLogMeta, ExceptionCode>> + Send {
523 async move {
524 let log = self.get_comm_event_log().await?;
525 if log.events.len() > MAX_COMM_EVENT_LOG_EVENTS {
526 return Err(ExceptionCode::ServerDeviceFailure);
527 }
528 out.extend_from_slice(&log.events);
529 Ok(CommEventLogMeta {
530 status: log.status,
531 event_count: log.event_count,
532 message_count: log.message_count,
533 })
534 }
535 }
536
537 fn report_server_id(&self) -> impl Future<Output = Result<Vec<u8>, ExceptionCode>> + Send {
543 async { Err(ExceptionCode::IllegalFunction) }
544 }
545
546 fn append_server_id(
552 &self,
553 out: &mut Vec<u8>,
554 ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send {
555 async move {
556 let data = self.report_server_id().await?;
557 if data.len() > MAX_SERVER_ID_BYTES {
558 return Err(ExceptionCode::ServerDeviceFailure);
559 }
560 out.extend_from_slice(&data);
561 Ok(data.len())
562 }
563 }
564
565 fn diagnostic(
576 &self,
577 sub_function: DiagnosticSubFunction,
578 data: &[u8],
579 ) -> impl Future<Output = Result<Option<Vec<u8>>, ExceptionCode>> + Send {
580 async move {
581 match sub_function {
582 DiagnosticSubFunction::ReturnQueryData => Ok(Some(data.to_vec())),
583 _ => Err(ExceptionCode::IllegalFunction),
584 }
585 }
586 }
587
588 fn append_diagnostic_response(
594 &self,
595 sub_function: DiagnosticSubFunction,
596 data: &[u8],
597 out: &mut Vec<u8>,
598 ) -> impl Future<Output = Result<Option<usize>, ExceptionCode>> + Send {
599 async move {
600 let Some(data) = self.diagnostic(sub_function, data).await? else {
601 return Ok(None);
602 };
603 if data.len() > MAX_DIAGNOSTIC_RESPONSE_DATA_LEN {
604 return Err(ExceptionCode::ServerDeviceFailure);
605 }
606 out.extend_from_slice(&data);
607 Ok(Some(data.len()))
608 }
609 }
610}