Skip to main content

rsiot/components_config/modbus_frame/
rtu_request.rs

1use bytes::{BufMut, Bytes, BytesMut};
2
3use super::CRC_ALG;
4
5/// Функциональный код запроса
6pub enum FunctionCode {
7    /// Чтение значений из регистров флагов
8    ReadCoils,
9
10    /// Чтение значений из регистров дискретных входов
11    ReadDiscreteInputs,
12
13    /// Чтение значений из регистров хранения
14    ReadHoldingRegisters {
15        /// Количество регистров для чтения
16        quantity: u16,
17    },
18
19    /// Чтение значений из регистров ввода
20    ReadInputRegisters,
21
22    /// Запись значения одного флага
23    WriteSingleCoil,
24
25    /// Запись значения в один регистр хранения
26    WriteSingleRegister {
27        /// Значение
28        value: u16,
29    },
30
31    /// Запись значений в несколько регистров флагов
32    WriteMultipleCoils,
33
34    /// Запись значений в несколько регистров хранения
35    WriteMultipleRegisters,
36}
37
38/// Создание запроса Modbus RTU
39pub struct RTURequest {
40    /// Адрес устройства
41    pub address: u8,
42
43    /// Стартовый адрес регистра
44    pub start_address: u16,
45
46    /// Функциональный код запроса
47    pub function_code: FunctionCode,
48}
49
50impl RTURequest {
51    /// Создать запрос
52    pub fn create(self) -> Bytes {
53        let mut buf = BytesMut::new();
54
55        buf.put_u8(self.address);
56
57        match self.function_code {
58            FunctionCode::ReadCoils => todo!(),
59            FunctionCode::ReadDiscreteInputs => todo!(),
60            FunctionCode::ReadHoldingRegisters { quantity } => {
61                buf.put_u8(0x03);
62                buf.put_u16(self.start_address);
63                buf.put_u16(quantity);
64            }
65            FunctionCode::ReadInputRegisters => todo!(),
66            FunctionCode::WriteSingleCoil => todo!(),
67            FunctionCode::WriteSingleRegister { value } => {
68                buf.put_u8(0x06);
69                buf.put_u16(self.start_address);
70                buf.put_u16(value);
71            }
72            FunctionCode::WriteMultipleCoils => todo!(),
73            FunctionCode::WriteMultipleRegisters => todo!(),
74        };
75
76        let checksum = CRC_ALG.checksum(&buf);
77        buf.put_u16_le(checksum);
78
79        buf.into()
80    }
81}
82
83#[cfg(test)]
84mod tests {
85
86    use super::*;
87
88    use pretty_assertions::assert_eq;
89
90    #[test]
91    fn test_read_holding_registers() {
92        let test = RTURequest {
93            address: 0x01,
94            start_address: 2000,
95            function_code: FunctionCode::ReadHoldingRegisters { quantity: 13 },
96        }
97        .create();
98
99        let correct = Bytes::from_static(&[0x01, 0x03, 0x07, 0xD0, 0x00, 0x0D, 0x84, 0x82]);
100
101        assert_eq!(test, correct);
102    }
103}