use crate::{
CommunicationControlType, CommunicationType, Error, NegativeResponseCode,
SingleValueWireFormat, SuppressablePositiveResponse, WireFormat,
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
const COMMUNICATION_CONTROL_NEGATIVE_RESPONSE_CODES: [NegativeResponseCode; 4] = [
NegativeResponseCode::SubFunctionNotSupported,
NegativeResponseCode::IncorrectMessageLengthOrInvalidFormat,
NegativeResponseCode::ConditionsNotCorrect,
NegativeResponseCode::RequestOutOfRange,
];
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CommunicationControlRequest {
control_type: SuppressablePositiveResponse<CommunicationControlType>,
pub communication_type: CommunicationType,
pub node_id: Option<u16>,
}
impl CommunicationControlRequest {
pub(crate) fn new(
suppress_positive_response: bool,
control_type: CommunicationControlType,
communication_type: CommunicationType,
) -> Self {
debug_assert!(!control_type.is_extended_address_variant());
Self {
control_type: SuppressablePositiveResponse::new(
suppress_positive_response,
control_type,
),
communication_type,
node_id: None,
}
}
pub(crate) fn new_with_node_id(
suppress_positive_response: bool,
control_type: CommunicationControlType,
communication_type: CommunicationType,
node_id: u16,
) -> Self {
assert!(control_type.is_extended_address_variant());
Self {
control_type: SuppressablePositiveResponse::new(
suppress_positive_response,
control_type,
),
communication_type,
node_id: Some(node_id),
}
}
#[must_use]
pub fn suppress_positive_response(&self) -> bool {
self.control_type.suppress_positive_response()
}
#[must_use]
pub fn control_type(&self) -> CommunicationControlType {
self.control_type.value()
}
#[must_use]
pub fn allowed_nack_codes() -> &'static [NegativeResponseCode] {
&COMMUNICATION_CONTROL_NEGATIVE_RESPONSE_CODES
}
}
impl WireFormat for CommunicationControlRequest {
fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let enable_byte = reader.read_u8()?;
let communication_enable = SuppressablePositiveResponse::try_from(enable_byte)?;
let communication_type = CommunicationType::try_from(reader.read_u8()?)?;
match communication_enable.value() {
CommunicationControlType::EnableRxAndDisableTxWithEnhancedAddressInfo
| CommunicationControlType::EnableRxAndTxWithEnhancedAddressInfo => {
let node_id = Some(reader.read_u16::<BigEndian>()?);
Ok(Some(Self {
control_type: communication_enable,
communication_type,
node_id,
}))
}
_ => Ok(Some(Self {
control_type: communication_enable,
communication_type,
node_id: None,
})),
}
}
fn required_size(&self) -> usize {
if self.node_id.is_some() { 4 } else { 2 }
}
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
writer.write_u8(u8::from(self.control_type))?;
writer.write_u8(u8::from(self.communication_type))?;
if let Some(id) = self.node_id {
writer.write_u16::<BigEndian>(id)?;
Ok(4)
} else {
Ok(2)
}
}
}
impl SingleValueWireFormat for CommunicationControlRequest {}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive] pub struct CommunicationControlResponse {
pub control_type: CommunicationControlType,
}
impl CommunicationControlResponse {
pub(crate) fn new(control_type: CommunicationControlType) -> Self {
Self { control_type }
}
}
impl WireFormat for CommunicationControlResponse {
fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let control_type = CommunicationControlType::try_from(reader.read_u8()?)?;
Ok(Some(Self::new(control_type)))
}
fn required_size(&self) -> usize {
1
}
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
writer.write_u8(u8::from(self.control_type))?;
Ok(1)
}
}
impl SingleValueWireFormat for CommunicationControlResponse {}
#[cfg(test)]
mod request {
use super::*;
#[test]
fn simple_request() {
let bytes: [u8; 3] = [0x01, 0x02, 0x03];
let req = CommunicationControlRequest::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(
req.control_type(),
CommunicationControlType::EnableRxAndDisableTx
);
assert_eq!(req.communication_type, CommunicationType::NetworkManagement);
assert_eq!(req.node_id, None);
let mut buffer = Vec::new();
let written = req.encode(&mut buffer).unwrap();
assert_eq!(written, req.required_size());
assert_eq!(buffer.len(), req.required_size());
}
#[test]
fn node_id() {
let bytes: [u8; 4] = [0x05, 0x02, 0x01, 0x02];
let req = CommunicationControlRequest::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(
req.control_type(),
CommunicationControlType::EnableRxAndTxWithEnhancedAddressInfo
);
assert_eq!(req.communication_type, CommunicationType::NetworkManagement);
assert_eq!(req.node_id, Some(258));
let mut buffer = Vec::new();
let written = req.encode(&mut buffer).unwrap();
assert_eq!(written, req.required_size());
assert_eq!(buffer.len(), req.required_size());
}
#[test]
fn new_with_node_id() {
let req = CommunicationControlRequest::new_with_node_id(
true,
CommunicationControlType::EnableRxAndTxWithEnhancedAddressInfo,
CommunicationType::NetworkManagement,
258,
);
assert_eq!(req.node_id, Some(258));
assert!(req.suppress_positive_response());
}
#[test]
fn new_extra() {
let req = CommunicationControlRequest::new(
false,
CommunicationControlType::EnableRxAndDisableTx,
CommunicationType::NetworkManagement,
);
assert!(!req.suppress_positive_response());
assert_eq!(CommunicationControlRequest::allowed_nack_codes().len(), 4);
}
}
#[cfg(test)]
mod response {
use super::*;
#[test]
fn simple_response() {
let bytes: [u8; 1] = [0x01];
let res = CommunicationControlResponse::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(
res.control_type,
CommunicationControlType::EnableRxAndDisableTx
);
let mut buffer = Vec::new();
let written = res.encode(&mut buffer).unwrap();
assert_eq!(written, 1);
assert_eq!(buffer.len(), written);
}
}