modbus_rtu/slave/
mod.rs

1mod data_model;     pub use data_model::{DataModel, DataStructure};
2
3use crate::common::{crc, exception::Exception, PacketError, RequestForm};
4
5
6/// Modbus Slave
7#[derive(Debug)]
8pub struct ModbusSlave<const L1: usize, const L2: usize> {
9    /// The Modbus slave ID.
10    ///
11    /// Valid Modbus IDs range from `1` to `247`. This crate also supports reserved IDs from `248` to `255`.
12    /// If the ID is set to `0`, the device will listen to all Modbus IDs and never respond.
13    ///
14    modbus_id: u8,
15
16    /// Holding registers.
17    ///
18    /// Read-write registers that can be accessed and modified by the Modbus master.
19    /// 
20    holding_registers: DataModel<L1, u16>,
21
22    /// Input registers.
23    ///
24    /// Read-only registers that can be accessed by the Modbus master.
25    /// 
26    input_registers: DataModel<L2, u16>,
27}
28
29
30impl<'a, const L1: usize, const L2: usize> ModbusSlave<L1, L2> {
31    pub fn new(modbus_id: u8, holding_registers: DataModel<L1, u16>, input_registers: DataModel<L2, u16>) -> ModbusSlave<L1, L2> {
32        ModbusSlave { modbus_id, holding_registers, input_registers }
33    }
34
35    pub fn get_modbus_id(&self) -> u8 {
36        self.modbus_id
37    }
38
39    pub fn set_modbus_id(&mut self, modbus_id: u8) {
40        self.modbus_id = modbus_id;
41    }
42
43    pub fn get_holding_registers(&self) -> &DataModel<L1, u16> {
44        &self.holding_registers
45    }
46
47    pub fn get_holding_registers_mut(&mut self) -> &mut DataModel<L1, u16> {
48        &mut self.holding_registers
49    }
50
51    pub fn get_input_registers(&self) -> &DataModel<L2, u16> {
52        &self.input_registers
53    }
54
55    pub fn get_input_registers_mut(&mut self) -> &mut DataModel<L2, u16> {
56        &mut self.input_registers
57    }
58
59    pub fn analyze_packet(&self, packet: &[u8]) -> Result<RequestForm<'a>, PacketError> {
60        let len = packet.len();
61
62        // Packet too short
63        if len < 4 {
64            return Err(PacketError::TooShort(len));
65        }
66
67        // Validate CRC bytes
68        crc::validate(packet)?;
69
70        // Check modbus ID
71        if (self.modbus_id != 0x00) && (self.modbus_id != packet[0]) {
72            return Err(PacketError::NotMyId(packet[0]));
73        }
74
75        match packet[1] {
76            0x03 => {
77                if self.holding_registers.is_empty() {
78                    return Err(PacketError::Exeption(packet[1], Exception::IllegalFunction));
79                }
80                todo!()
81            },
82            0x04 => {
83                if self.input_registers.is_empty() {
84                    return Err(PacketError::Exeption(packet[1], Exception::IllegalFunction));
85                }
86                todo!()
87            },
88            0x06 => {
89                if self.holding_registers.is_empty() {
90                    return Err(PacketError::Exeption(packet[1], Exception::IllegalFunction));
91                }
92                todo!()
93            },
94            0x10 => {
95                if self.holding_registers.is_empty() {
96                    return Err(PacketError::Exeption(packet[1], Exception::IllegalFunction));
97                }
98                todo!()
99            },
100            #[cfg(feature="bypass")]
101            0x45 => {
102                todo!()
103            },
104            _ => return Err(PacketError::Exeption(packet[1], Exception::IllegalFunction)),
105        }
106    }
107
108    pub fn build_exception_response_packet(&self, fc: u8, exception: Exception) -> [u8; 5] {
109        let mut result: [u8; 5] = [
110            self.modbus_id,
111            fc | 0x80,
112            exception.into(),
113            0x00,
114            0x00,
115        ];
116
117        let crc_bytes = crc::gen_bytes(&result[..3]);
118        result[3..5].copy_from_slice(&crc_bytes);
119
120        result
121    }
122}