Skip to main content

fennec_modbus/protocol/function/
read_multiple.rs

1//! Codes for functions that read 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, adapters::DropRemaining},
12        function,
13        function::size_argument,
14    },
15};
16
17/// Address range for reading operations.
18#[must_use]
19pub struct Args<A, V, S>(
20    /// Bare starting address.
21    A,
22    /// Binding to the value type. This is needed to know the number of registers or coils.
23    PhantomData<V>,
24    /// Binding to the size type, normally [`size_argument::Bits`] or [`size_argument::Words`].
25    PhantomData<S>,
26);
27
28impl<A, V: BitSize, S> From<A> for Args<A, V, S> {
29    /// Wrap the address into [`Args`].
30    fn from(address: A) -> Self {
31        Self::new(address)
32    }
33}
34
35impl<A, V: BitSize, S> Args<A, V, S> {
36    /// Create the address range from the starting address.
37    pub const fn new(starting_address: A) -> Self {
38        Self(starting_address, PhantomData, PhantomData)
39    }
40}
41
42impl<A: Address, V: BitSize> Encode for Args<A, V, size_argument::Bits> {
43    /// Encode the address and number of bits to read.
44    fn encode(&self, to: &mut impl BufMut) {
45        V::assert_valid::<246>();
46        self.0.encode(to);
47        to.put_u16(V::N_BITS);
48    }
49}
50
51impl<A: Address, V: BitSize> Encode for Args<A, V, size_argument::Words> {
52    /// Encode the address and number of registers to read.
53    fn encode(&self, to: &mut impl BufMut) {
54        V::assert_valid::<250>();
55        self.0.encode(to);
56        to.put_u16(V::N_WORDS);
57    }
58}
59
60/// Output decoder for the read operations.
61///
62/// # Example
63///
64/// ```rust
65/// use fennec_modbus::protocol::{
66///     codec::Decode,
67///     function::{IntoValue, read_multiple::Output},
68/// };
69///
70/// const BYTES: &[u8] = &[
71///     0x04, // byte count
72///     0x02, 0x2B, // register: high, low
73///     0x00, 0x00, // register: high, low
74/// ];
75///
76/// #[expect(const_item_mutation)]
77/// let value = Output::<u32>::decode(&mut BYTES).unwrap().into_value();
78/// assert_eq!(value, 0x022B0000);
79/// ```
80pub struct Output<V>(V);
81
82impl<V: Decode> Decode for Output<V> {
83    fn decode(from: &mut impl Buf) -> Result<Self, Error> {
84        let n_bytes = from.try_get_u8()?;
85        let mut from = DropRemaining(from).take(usize::from(n_bytes));
86        V::decode(&mut from).map(Self)
87    }
88}
89
90impl<V> function::IntoValue for Output<V> {
91    type Value = V;
92
93    fn into_value(self) -> Self::Value {
94        self.0
95    }
96}