use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RegisterType {
Coil,
DiscreteInput,
HoldingRegister,
InputRegister,
}
impl RegisterType {
#[inline]
pub const fn read_function_code(&self) -> u8 {
match self {
Self::Coil => 0x01,
Self::DiscreteInput => 0x02,
Self::HoldingRegister => 0x03,
Self::InputRegister => 0x04,
}
}
#[inline]
pub const fn write_single_function_code(&self) -> Option<u8> {
match self {
Self::Coil => Some(0x05),
Self::HoldingRegister => Some(0x06),
Self::DiscreteInput | Self::InputRegister => None,
}
}
#[inline]
pub const fn write_multiple_function_code(&self) -> Option<u8> {
match self {
Self::Coil => Some(0x0F),
Self::HoldingRegister => Some(0x10),
Self::DiscreteInput | Self::InputRegister => None,
}
}
#[inline]
pub const fn is_writable(&self) -> bool {
matches!(self, Self::Coil | Self::HoldingRegister)
}
#[inline]
pub const fn is_read_only(&self) -> bool {
matches!(self, Self::DiscreteInput | Self::InputRegister)
}
#[inline]
pub const fn is_bit_type(&self) -> bool {
matches!(self, Self::Coil | Self::DiscreteInput)
}
#[inline]
pub const fn is_word_type(&self) -> bool {
matches!(self, Self::HoldingRegister | Self::InputRegister)
}
#[inline]
pub const fn max_read_quantity(&self) -> u16 {
if self.is_bit_type() {
2000 } else {
125 }
}
#[inline]
pub const fn max_write_quantity(&self) -> u16 {
if self.is_bit_type() {
1968 } else {
123 }
}
#[inline]
pub const fn bit_width(&self) -> u8 {
if self.is_bit_type() {
1
} else {
16
}
}
#[inline]
pub const fn byte_size(&self) -> usize {
if self.is_bit_type() {
1 } else {
2 }
}
#[inline]
pub const fn default_address_range(&self) -> (u16, u16) {
(0, 9999)
}
#[inline]
pub const fn name(&self) -> &'static str {
match self {
Self::Coil => "Coil",
Self::DiscreteInput => "Discrete Input",
Self::HoldingRegister => "Holding Register",
Self::InputRegister => "Input Register",
}
}
#[inline]
pub const fn short_name(&self) -> &'static str {
match self {
Self::Coil => "CO",
Self::DiscreteInput => "DI",
Self::HoldingRegister => "HR",
Self::InputRegister => "IR",
}
}
pub fn all() -> impl Iterator<Item = Self> {
[
Self::Coil,
Self::DiscreteInput,
Self::HoldingRegister,
Self::InputRegister,
]
.into_iter()
}
}
impl std::fmt::Display for RegisterType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_register_type_properties() {
assert!(RegisterType::Coil.is_writable());
assert!(RegisterType::Coil.is_bit_type());
assert!(!RegisterType::Coil.is_word_type());
assert_eq!(RegisterType::Coil.read_function_code(), 0x01);
assert_eq!(RegisterType::Coil.write_single_function_code(), Some(0x05));
assert!(!RegisterType::DiscreteInput.is_writable());
assert!(RegisterType::DiscreteInput.is_read_only());
assert!(RegisterType::DiscreteInput.is_bit_type());
assert_eq!(RegisterType::DiscreteInput.read_function_code(), 0x02);
assert_eq!(
RegisterType::DiscreteInput.write_single_function_code(),
None
);
assert!(RegisterType::HoldingRegister.is_writable());
assert!(RegisterType::HoldingRegister.is_word_type());
assert_eq!(RegisterType::HoldingRegister.read_function_code(), 0x03);
assert_eq!(
RegisterType::HoldingRegister.write_single_function_code(),
Some(0x06)
);
assert!(!RegisterType::InputRegister.is_writable());
assert!(RegisterType::InputRegister.is_read_only());
assert!(RegisterType::InputRegister.is_word_type());
assert_eq!(RegisterType::InputRegister.read_function_code(), 0x04);
assert_eq!(
RegisterType::InputRegister.write_single_function_code(),
None
);
}
#[test]
fn test_max_quantities() {
assert_eq!(RegisterType::Coil.max_read_quantity(), 2000);
assert_eq!(RegisterType::Coil.max_write_quantity(), 1968);
assert_eq!(RegisterType::DiscreteInput.max_read_quantity(), 2000);
assert_eq!(RegisterType::HoldingRegister.max_read_quantity(), 125);
assert_eq!(RegisterType::HoldingRegister.max_write_quantity(), 123);
assert_eq!(RegisterType::InputRegister.max_read_quantity(), 125);
}
#[test]
fn test_all_iterator() {
let types: Vec<_> = RegisterType::all().collect();
assert_eq!(types.len(), 4);
assert!(types.contains(&RegisterType::Coil));
assert!(types.contains(&RegisterType::DiscreteInput));
assert!(types.contains(&RegisterType::HoldingRegister));
assert!(types.contains(&RegisterType::InputRegister));
}
}