easy_modbus/frame/
request.rs

1use std::fmt;
2use std::fmt::Formatter;
3
4use bytes::{BufMut, BytesMut};
5
6use crate::frame::Version::Rtu;
7use crate::util::crc;
8
9use super::{Head, Length};
10
11/// Modbus Request
12#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub enum Request {
14    ReadCoils(Head, ReadCoilsRequest),
15    ReadDiscreteInputs(Head, ReadDiscreteInputsRequest),
16    ReadMultipleHoldingRegisters(Head, ReadMultipleHoldingRegistersRequest),
17    ReadInputRegisters(Head, ReadInputRegistersRequest),
18    WriteSingleCoil(Head, WriteSingleCoilRequest),
19    WriteSingleHoldingRegister(Head, WriteSingleHoldingRegisterRequest),
20    WriteMultipleCoils(Head, WriteMultipleCoilsRequest),
21    WriteMultipleHoldingRegisters(Head, WriteMultipleHoldingRegistersRequest),
22}
23
24impl fmt::Display for Request {
25    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
26        let mut buf = BytesMut::with_capacity(64);
27        request_to_bytesmut(self.clone(), &mut buf);
28        let mut first = true;
29        for byte in buf {
30            if !first {
31                write!(f, " ")?;
32            }
33            write!(f, "{:02X}", byte)?;
34            first = false;
35        }
36        Ok(())
37    }
38}
39
40/// Function Code `0x01`
41#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct ReadCoilsRequest {
43    /// Address of first coil to read
44    pub(crate) first_address: u16,
45
46    /// Number of coils to read
47    ///
48    /// Because of the byte count returned in the reply message is only 8 bits wide and the protocol
49    /// overhead is 5 bytes, a maximum of 2008(251 * 8) discrete coils can be read at once.
50    pub(crate) coils_number: u16,
51}
52
53impl Length for ReadCoilsRequest {
54    fn len(&self) -> u16 {
55        4
56    }
57}
58
59impl ReadCoilsRequest {
60    pub(crate) fn new(first_address: u16, coils_number: u16) -> ReadCoilsRequest {
61        ReadCoilsRequest {
62            first_address,
63            coils_number,
64        }
65    }
66}
67
68/// Function Code `0x02`
69#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
70pub struct ReadDiscreteInputsRequest {
71    /// Address of first discrete input to read
72    pub(crate) first_address: u16,
73
74    /// Number of discrete input to read
75    ///
76    /// Because of the byte count returned in the reply message is only 8 bits wide and the protocol
77    /// overhead is 5 bytes, a maximum of 2008(251 * 8) discrete inputs can be read at once.
78    pub(crate) discrete_inputs_number: u16,
79}
80
81impl Length for ReadDiscreteInputsRequest {
82    fn len(&self) -> u16 {
83        4
84    }
85}
86
87impl ReadDiscreteInputsRequest {
88    pub(crate) fn new(
89        first_address: u16,
90        discrete_inputs_number: u16,
91    ) -> ReadDiscreteInputsRequest {
92        ReadDiscreteInputsRequest {
93            first_address,
94            discrete_inputs_number,
95        }
96    }
97
98    pub fn get_first_address(&self) -> &u16 {
99        &self.first_address
100    }
101
102    pub fn get_discrete_input_number(&self) -> &u16 {
103        &self.discrete_inputs_number
104    }
105}
106
107/// Function Code `0x03`
108#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
109pub struct ReadMultipleHoldingRegistersRequest {
110    /// Address of first register to read
111    pub(crate) first_address: u16,
112
113    /// Number of registers to read
114    ///
115    /// Because the maximum length of a Modbus PDU is 253, so up to 125 registers can be requested
116    /// at once when using RTU format, and up to 123 over TCP
117    pub(crate) registers_number: u16,
118}
119
120impl Length for ReadMultipleHoldingRegistersRequest {
121    fn len(&self) -> u16 {
122        4
123    }
124}
125
126impl ReadMultipleHoldingRegistersRequest {
127    pub(crate) fn new(
128        first_address: u16,
129        registers_number: u16,
130    ) -> ReadMultipleHoldingRegistersRequest {
131        ReadMultipleHoldingRegistersRequest {
132            first_address,
133            registers_number,
134        }
135    }
136
137    pub fn get_first_address(&self) -> &u16 {
138        &self.first_address
139    }
140
141    pub fn get_registers_number(&self) -> &u16 {
142        &self.registers_number
143    }
144}
145
146/// Function code `0x04`
147#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
148pub struct ReadInputRegistersRequest {
149    /// Address of first register to read
150    pub(crate) first_address: u16,
151
152    /// Number of registers to read
153    ///
154    /// Because the maximum length of a Modbus PDU is 253, so up to 125 registers can be requested
155    /// at once when using RTU format, and up to 123 over TCP
156    pub(crate) registers_number: u16,
157}
158
159impl Length for ReadInputRegistersRequest {
160    fn len(&self) -> u16 {
161        4
162    }
163}
164
165impl ReadInputRegistersRequest {
166    pub(crate) fn new(first_address: u16, registers_number: u16) -> ReadInputRegistersRequest {
167        ReadInputRegistersRequest {
168            first_address,
169            registers_number,
170        }
171    }
172
173    pub fn get_first_address(&self) -> &u16 {
174        &self.first_address
175    }
176
177    pub fn get_registers_number(&self) -> &u16 {
178        &self.registers_number
179    }
180}
181
182/// Function Code `0x05`
183#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
184pub struct WriteSingleCoilRequest {
185    /// Address of coil to write
186    pub(crate) coil_address: u16,
187
188    /// Value to write
189    ///
190    /// 0 (0x0000) for off, 65,280 (0xFF00) for on
191    pub(crate) value: u16,
192}
193
194impl Length for WriteSingleCoilRequest {
195    fn len(&self) -> u16 {
196        4
197    }
198}
199
200impl WriteSingleCoilRequest {
201    pub(crate) fn new(coil_address: u16, value: u16) -> WriteSingleCoilRequest {
202        WriteSingleCoilRequest {
203            coil_address,
204            value,
205        }
206    }
207
208    pub fn get_coil_address(&self) -> &u16 {
209        &self.coil_address
210    }
211
212    pub fn get_value(&self) -> &u16 {
213        &self.value
214    }
215}
216
217/// Function Code `0x06`
218#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
219pub struct WriteSingleHoldingRegisterRequest {
220    /// Address of Holding Register to write
221    pub(crate) register_address: u16,
222
223    /// Value to write
224    pub(crate) value: u16,
225}
226
227impl Length for WriteSingleHoldingRegisterRequest {
228    fn len(&self) -> u16 {
229        4
230    }
231}
232
233impl WriteSingleHoldingRegisterRequest {
234    pub(crate) fn new(register_address: u16, value: u16) -> WriteSingleHoldingRegisterRequest {
235        WriteSingleHoldingRegisterRequest {
236            register_address,
237            value,
238        }
239    }
240
241    pub fn get_register_address(&self) -> &u16 {
242        &self.register_address
243    }
244
245    pub fn get_value(&self) -> &u16 {
246        &self.value
247    }
248}
249
250/// Function Code `0x0F`
251#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
252pub struct WriteMultipleCoilsRequest {
253    /// Address of first coil to write
254    ///
255    /// First requested coil is stored as least significant bit of first byte in request.
256    pub(crate) first_address: u16,
257
258    /// Number of coils to write
259    pub(crate) coils_number: u16,
260
261    /// Number of bytes of coil values to follow
262    ///
263    /// If number of coils is not a multiple of 8, most significant bits of last byte should be
264    /// stuffed with zeros.
265    pub(crate) bytes_number: u8,
266
267    /// Coil values
268    ///
269    /// Value of each coil is binary (0 for off, 1 for on).
270    pub(crate) values: Vec<u8>,
271}
272
273impl Length for WriteMultipleCoilsRequest {
274    fn len(&self) -> u16 {
275        5 + self.values.len() as u16
276    }
277}
278
279impl WriteMultipleCoilsRequest {
280    pub(crate) fn new(
281        first_address: u16,
282        coils_number: u16,
283        values: Vec<u8>,
284    ) -> WriteMultipleCoilsRequest {
285        WriteMultipleCoilsRequest {
286            first_address,
287            coils_number,
288            bytes_number: values.len() as u8,
289            values,
290        }
291    }
292
293    pub fn first_address(&self) -> &u16 {
294        &self.first_address
295    }
296
297    pub fn coils_number(&self) -> &u16 {
298        &self.coils_number
299    }
300}
301
302/// Function Code `0x10`
303#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
304pub struct WriteMultipleHoldingRegistersRequest {
305    /// Address of first holding registers to write
306    pub(crate) first_address: u16,
307
308    /// Number of holding registers to write
309    ///
310    /// Because the maximum length of a Modbus PDU is 253 (inferred from the maximum Modbus APU
311    /// length of 256 on RS485), up to 123 registers can be written at once.
312    pub(crate) registers_number: u16,
313
314    /// Number of bytes of register value to follow
315    pub(crate) bytes_number: u8,
316
317    /// New values of holding registers
318    pub(crate) values: Vec<u8>,
319}
320
321impl Length for WriteMultipleHoldingRegistersRequest {
322    fn len(&self) -> u16 {
323        5 + self.values.len() as u16
324    }
325}
326
327impl WriteMultipleHoldingRegistersRequest {
328    pub(crate) fn new(first_address: u16, values: Vec<u8>) -> WriteMultipleHoldingRegistersRequest {
329        WriteMultipleHoldingRegistersRequest {
330            first_address,
331            registers_number: values.len() as u16 / 2,
332            bytes_number: values.len() as u8,
333            values,
334        }
335    }
336
337    pub fn get_first_address(&self) -> &u16 {
338        &self.first_address
339    }
340
341    pub fn get_registers_number(&self) -> &u16 {
342        &self.registers_number
343    }
344
345    pub fn get_bytes_number(&self) -> &u8 {
346        &self.bytes_number
347    }
348
349    pub fn get_values(&self) -> &Vec<u8> {
350        &self.values
351    }
352}
353
354impl From<ReadCoilsRequest> for BytesMut {
355    fn from(request: ReadCoilsRequest) -> Self {
356        let mut buf = BytesMut::new();
357        buf.put_u16(request.first_address);
358        buf.put_u16(request.coils_number);
359        buf
360    }
361}
362
363impl From<ReadDiscreteInputsRequest> for BytesMut {
364    fn from(request: ReadDiscreteInputsRequest) -> Self {
365        let mut buf = BytesMut::new();
366        buf.put_u16(request.first_address);
367        buf.put_u16(request.discrete_inputs_number);
368        buf
369    }
370}
371
372impl From<ReadMultipleHoldingRegistersRequest> for BytesMut {
373    fn from(request: ReadMultipleHoldingRegistersRequest) -> Self {
374        let mut buf = BytesMut::new();
375        buf.put_u16(request.first_address);
376        buf.put_u16(request.registers_number);
377        buf
378    }
379}
380
381impl From<ReadInputRegistersRequest> for BytesMut {
382    fn from(request: ReadInputRegistersRequest) -> Self {
383        let mut buf = BytesMut::new();
384        buf.put_u16(request.first_address);
385        buf.put_u16(request.registers_number);
386        buf
387    }
388}
389
390impl From<WriteSingleCoilRequest> for BytesMut {
391    fn from(request: WriteSingleCoilRequest) -> Self {
392        let mut buf = BytesMut::new();
393        buf.put_u16(request.coil_address);
394        buf.put_u16(request.value);
395        buf
396    }
397}
398
399impl From<WriteSingleHoldingRegisterRequest> for BytesMut {
400    fn from(request: WriteSingleHoldingRegisterRequest) -> Self {
401        let mut buf = BytesMut::new();
402        buf.put_u16(request.register_address);
403        buf.put_u16(request.value);
404        buf
405    }
406}
407
408impl From<WriteMultipleCoilsRequest> for BytesMut {
409    fn from(request: WriteMultipleCoilsRequest) -> Self {
410        let mut buf = BytesMut::new();
411        buf.put_u16(request.first_address);
412        buf.put_u16(request.coils_number);
413        buf.put_u8(request.bytes_number);
414        buf.put_slice(request.values.as_slice());
415        buf
416    }
417}
418
419impl From<WriteMultipleHoldingRegistersRequest> for BytesMut {
420    fn from(request: WriteMultipleHoldingRegistersRequest) -> Self {
421        let mut buf = BytesMut::new();
422        buf.put_u16(request.first_address);
423        buf.put_u16(request.registers_number);
424        buf.put_u8(request.bytes_number);
425        buf.put_slice(request.values.as_slice());
426        buf
427    }
428}
429
430pub(crate) fn request_to_bytesmut(item: Request, dst: &mut BytesMut) {
431    let version;
432    match item {
433        Request::ReadCoils(head, body) => {
434            version = head.version.clone();
435            dst.put(BytesMut::from(head));
436            dst.put(BytesMut::from(body));
437        }
438        Request::ReadDiscreteInputs(head, body) => {
439            version = head.version.clone();
440            dst.put(BytesMut::from(head));
441            dst.put(BytesMut::from(body));
442        }
443        Request::ReadMultipleHoldingRegisters(head, body) => {
444            version = head.version.clone();
445            dst.put(BytesMut::from(head));
446            dst.put(BytesMut::from(body));
447        }
448        Request::ReadInputRegisters(head, body) => {
449            version = head.version.clone();
450            dst.put(BytesMut::from(head));
451            dst.put(BytesMut::from(body));
452        }
453        Request::WriteSingleCoil(head, body) => {
454            version = head.version.clone();
455            dst.put(BytesMut::from(head));
456            dst.put(BytesMut::from(body));
457        }
458        Request::WriteSingleHoldingRegister(head, body) => {
459            version = head.version.clone();
460            dst.put(BytesMut::from(head));
461            dst.put(BytesMut::from(body));
462        }
463        Request::WriteMultipleCoils(head, body) => {
464            version = head.version.clone();
465            dst.put(BytesMut::from(head));
466            dst.put(BytesMut::from(body));
467        }
468        Request::WriteMultipleHoldingRegisters(head, body) => {
469            version = head.version.clone();
470            dst.put(BytesMut::from(head));
471            dst.put(BytesMut::from(body));
472        }
473    };
474    if Rtu == version {
475        dst.put_u16(crc::compute(&dst.to_vec()));
476    }
477}
478
479#[cfg(test)]
480mod request_test {
481    use crate::frame::Length;
482    use crate::frame::request::*;
483
484    #[test]
485    fn test_read_coils_request() {
486        let request_l = ReadCoilsRequest::new(0x01, 0x02);
487        let request_r = ReadCoilsRequest {
488            first_address: 0x01,
489            coils_number: 0x02,
490        };
491        assert_eq!(request_l, request_r);
492        assert_eq!(request_l.len(), 4);
493    }
494
495    #[test]
496    fn test_read_discrete_inputs_request() {
497        let request_l = ReadDiscreteInputsRequest::new(0x01, 0x02);
498        let request_r = ReadDiscreteInputsRequest {
499            first_address: 0x01,
500            discrete_inputs_number: 0x02,
501        };
502        assert_eq!(request_l, request_r);
503        assert_eq!(request_l.len(), 4);
504    }
505
506    #[test]
507    fn test_read_multiple_holding_register_request() {
508        let request_l = ReadMultipleHoldingRegistersRequest::new(0x01, 0x02);
509        let request_r = ReadMultipleHoldingRegistersRequest {
510            first_address: 0x01,
511            registers_number: 0x02,
512        };
513        assert_eq!(request_l, request_r);
514        assert_eq!(request_l.len(), 4);
515    }
516
517    #[test]
518    fn test_read_input_register_request() {
519        let request_l = ReadInputRegistersRequest::new(0x01, 0x02);
520        let request_r = ReadInputRegistersRequest {
521            first_address: 0x01,
522            registers_number: 0x02,
523        };
524        assert_eq!(request_l, request_r);
525        assert_eq!(request_l.len(), 4);
526    }
527
528    #[test]
529    fn test_write_single_coil_request() {
530        let request_l = WriteSingleCoilRequest::new(0x01, 0xABCD);
531        let request_r = WriteSingleCoilRequest {
532            coil_address: 0x01,
533            value: 0xABCD,
534        };
535        assert_eq!(request_l, request_r);
536        assert_eq!(request_l.len(), 4);
537    }
538
539    #[test]
540    fn test_write_single_holding_register_request() {
541        let request_l = WriteSingleHoldingRegisterRequest::new(0x01, 0x02);
542        let request_r = WriteSingleHoldingRegisterRequest {
543            register_address: 0x01,
544            value: 0x02,
545        };
546        assert_eq!(request_l, request_r);
547        assert_eq!(request_l.len(), 4);
548    }
549
550    #[test]
551    fn test_write_multiple_coils_request() {
552        let request_l = WriteMultipleCoilsRequest::new(0x01, 0x09, vec![0b0100_1101, 0b0000_0001]);
553        let request_r = WriteMultipleCoilsRequest {
554            first_address: 0x01,
555            coils_number: 0x09,
556            bytes_number: 0x02,
557            values: vec![0b0100_1101, 0b0000_0001],
558        };
559        assert_eq!(request_l, request_r);
560        assert_eq!(request_l.len(), 7);
561    }
562
563    #[test]
564    fn test_write_multiple_holding_registers_request() {
565        let request_l = WriteMultipleHoldingRegistersRequest::new(0x01, vec![0x00, 0x0F]);
566        let request_r = WriteMultipleHoldingRegistersRequest {
567            first_address: 0x01,
568            registers_number: 0x01,
569            bytes_number: 0x02,
570            values: vec![0x00, 0x0f],
571        };
572        assert_eq!(request_l, request_r);
573        assert_eq!(request_l.len(), 7);
574    }
575}