Skip to main content

DiscreteInputs

Struct DiscreteInputs 

Source
pub struct DiscreteInputs { /* private fields */ }
Expand description

A collection of discrete input states retrieved from a Modbus server.

This structure maintains the context of the read operation (starting address and quantity) and stores the actual bit-packed values in a memory-efficient heapless::Vec, making it suitable for no_std and embedded environments.

Use the value() method to extract individual boolean states without manually performing bitwise operations.

§Internal Representation

The values array stores these discrete input states. Each byte in values holds 8 input states, where the least significant bit (LSB) of the first byte (values[0]) corresponds to the from_address, the next bit to from_address + 1, and so on. This bit-packing is efficient for memory usage and network transmission.

The MAX_DISCRETE_INPUT_BYTES constant ensures that the values array has enough space to accommodate the maximum possible number of discrete inputs allowed in a single Modbus PDU (MAX_DISCRETE_INPUTS_PER_PDU).

§Examples

use mbus_core::models::discrete_input::{DiscreteInputs, MAX_DISCRETE_INPUT_BYTES};
use mbus_core::errors::MbusError;

// Initialize a block of 8 discrete inputs starting at Modbus address 100.
// Initially all inputs are OFF (0).
let mut inputs = DiscreteInputs::new(100, 8).unwrap();

// Verify initial state: all inputs are false
assert_eq!(inputs.value(100).unwrap(), false);
assert_eq!(inputs.value(107).unwrap(), false);

// Simulate receiving data where inputs at offsets 0 and 2 are ON (0b0000_0101)
let received_data = [0x05, 0x00, 0x00, 0x00]; // Only the first byte is relevant for 8 inputs
inputs = inputs.with_values(&received_data, 8).expect("Valid quantity and data");

// Read individual input values
assert_eq!(inputs.value(100).unwrap(), true);  // Address 100 (offset 0) -> LSB of 0x05 is 1
assert_eq!(inputs.value(101).unwrap(), false); // Address 101 (offset 1) -> next bit is 0
assert_eq!(inputs.value(102).unwrap(), true);  // Address 102 (offset 2) -> next bit is 1
assert_eq!(inputs.value(107).unwrap(), false); // Address 107 (offset 7) -> MSB of 0x05 is 0

// Accessing values out of bounds will return an error
assert_eq!(inputs.value(99), Err(MbusError::InvalidAddress));
assert_eq!(inputs.value(108), Err(MbusError::InvalidAddress));

// Get the raw bit-packed bytes (only the first byte is active for 8 inputs)
assert_eq!(inputs.values(), &[0x05]);

Implementations§

Source§

impl DiscreteInputs

Source

pub fn new(from_address: u16, quantity: u16) -> Result<Self, MbusError>

Creates a new DiscreteInputs instance representing a block of read-only discrete inputs.

The internal values array is initialized to all zeros, meaning all discrete inputs are initially considered OFF (false).

§Arguments
  • from_address - The starting Modbus address for this block of inputs.
  • quantity - The total number of discrete inputs contained in this block.
§What happens:
  1. The quantity is validated to ensure it does not exceed MAX_DISCRETE_INPUTS_PER_PDU.
  2. A new DiscreteInputs instance is created with the specified from_address and quantity.
  3. The internal values array, which stores the bit-packed states, is initialized to all 0u8s.
§Errors

Returns MbusError::InvalidQuantity if the requested quantity exceeds MAX_DISCRETE_INPUTS_PER_PDU.

§Returns

A new initialized DiscreteInputs instance.

Source

pub fn with_values( self, values: &[u8], bits_length: u16, ) -> Result<Self, MbusError>

Sets the bit-packed values for the discrete inputs and validates the length.

This method is typically used to populate a DiscreteInputs instance with actual data received from a Modbus server. It copies the relevant portion of the provided values slice into the internal fixed-size buffer.

§Arguments
  • values - A slice of bytes containing the bit-packed states. This slice should be at least as long as the number of bytes required to store bits_length inputs.
  • bits_length - The number of bits (inputs) actually contained in the provided values. This parameter specifies the actual number of bits (discrete inputs) present in the values slice, which should typically match the quantity of the DiscreteInputs instance.
§What happens:
  1. The bits_length is checked against the quantity of the DiscreteInputs instance.
  2. The necessary number of bytes (byte_length) is calculated from bits_length.
  3. The relevant portion of the input values slice is copied into the internal self.values array.
§Errors

Returns MbusError::InvalidQuantity if bits_length does not match self.quantity.

Source

pub fn from_address(&self) -> u16

Returns the starting Modbus address of the first discrete input in this block.

Source

pub fn quantity(&self) -> u16

Returns the total number of discrete inputs managed by this instance.

Source

pub fn values(&self) -> &[u8]

Returns a reference to the active bytes containing the bit-packed input states.

This method returns a slice &[u8] that contains only the bytes relevant to the quantity of discrete inputs managed by this instance. It does not return the entire MAX_DISCRETE_INPUT_BYTES array if quantity is smaller. The length of the returned slice is calculated as ceil(self.quantity / 8).

Source

pub fn value(&self, address: u16) -> Result<bool, MbusError>

Retrieves the boolean state of a specific input by its address.

This method performs boundary checking to ensure the requested address is within the range [from_address, from_address + quantity).

§Arguments
  • address - The Modbus address of the discrete input to query.
§What happens:
  1. Boundary Check: The address is validated to ensure it falls within the range [self.from_address, self.from_address + self.quantity).
  2. Bit Index Calculation: The bit_index (zero-based offset from from_address) is calculated.
  3. Byte and Bit Position: The byte_index (bit_index / 8) determines which byte in the values array contains the target bit, and bit_in_byte (bit_index % 8) determines its position within that byte.
  4. Masking: A bit_mask (e.g., 0b0000_0001 for bit 0, 0b0000_0010 for bit 1) is created to isolate the specific bit.
  5. Extraction: A bitwise AND operation (&) with the bit_mask is performed on the relevant byte. If the result is non-zero, the bit is ON (true); otherwise, it’s OFF (false).
§Returns
  • Ok(true) if the input is ON (1).
  • Ok(false) if the input is OFF (0).
  • Err(MbusError::InvalidAddress) if the address is out of the block’s range.

Trait Implementations§

Source§

impl Clone for DiscreteInputs

Source§

fn clone(&self) -> DiscreteInputs

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DiscreteInputs

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for DiscreteInputs

Source§

fn eq(&self, other: &DiscreteInputs) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for DiscreteInputs

Source§

impl StructuralPartialEq for DiscreteInputs

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.