Skip to main content

fennec_modbus/protocol/function/
write_multiple.rs

1//! Codecs for functions that write multiple coils or registers.
2
3use core::marker::PhantomData;
4
5use bytes::{Buf, BufMut};
6
7use crate::{
8    Error,
9    protocol::{
10        Address,
11        codec::{BitSize, Decode, Encode},
12        function::{IntoValue, size_argument::SizeArgument},
13    },
14};
15
16/// Address range and value for writing operations.
17///
18/// # Example
19///
20/// ```rust
21/// use fennec_modbus::protocol::{
22///     codec::Encode,
23///     function::{size_argument, write_multiple::Args},
24/// };
25///
26/// assert_eq!(
27///     Args::<_, _, size_argument::Words>::new(1_u16, [0x000A_u16, 0x0102]).to_bytes(),
28///     [
29///         0x00, 0x01, // starting address
30///         0x00, 0x02, // register count
31///         0x04, // byte count
32///         0x00, 0x0A, // register 1
33///         0x01, 0x02, // register 2
34///     ]
35/// );
36/// ```
37pub struct Args<A, V, S>(
38    /// Bare starting address.
39    A,
40    /// Value to write.
41    V,
42    /// Binding to the size type, normally [`size_argument::Bits`] or [`size_argument::Words`].
43    PhantomData<S>,
44);
45
46impl<A, V, S> Args<A, V, S> {
47    pub const fn new(address: A, value: V) -> Self {
48        Self(address, value, PhantomData)
49    }
50}
51
52impl<A: Address, V: BitSize + Encode, S: SizeArgument> Encode for Args<A, V, S> {
53    fn encode_to(&self, buf: &mut impl BufMut) {
54        S::assert_valid_size::<V, 246>();
55        self.0.encode_to(buf);
56        buf.put_u16(S::quantity_for::<V>());
57        buf.put_u8(V::N_BYTES);
58        self.1.encode_to(buf);
59    }
60}
61
62/// Writing output.
63///
64/// # Example
65///
66/// ```rust
67/// use fennec_modbus::protocol::{codec::Decode, function::write_multiple::Output};
68///
69/// let mut bytes: &[u8] = &[0x00, 0x01, 0x00, 0x02];
70/// let output = Output::decode_from(&mut bytes).unwrap();
71/// assert_eq!(output.starting_address, 1);
72/// assert_eq!(output.count, 2);
73/// ```
74pub struct Output {
75    /// Starting address.
76    pub starting_address: u16,
77
78    /// Count of registers or coils – according to the operation.
79    pub count: u16,
80}
81
82impl IntoValue for Output {
83    type Value = Self;
84
85    fn into_value(self) -> Self::Value {
86        self
87    }
88}
89
90impl Decode for Output {
91    fn decode_from(buf: &mut impl Buf) -> Result<Self, Error> {
92        Ok(Self { starting_address: u16::decode_from(buf)?, count: u16::decode_from(buf)? })
93    }
94}