use crate::{
impl_default, impl_message_from_buf, impl_response_ops, impl_var_message_ops, len, std::fmt,
ChannelValue, ChannelValueList, CountryCode, CountryCodeList, Error, FirmwareVersion,
MessageOps, MessageType, ProtocolVersion, ResponseOps, Result, UnitType, ValueMultiplier, Vec,
};
mod index {
pub const UNIT_TYPE: usize = 4;
pub const FIRMWARE_VERSION: usize = 5;
pub const FIRMWARE_VERSION_END: usize = 9;
pub const COUNTRY_CODE: usize = 9;
pub const COUNTRY_CODE_END: usize = 12;
pub const VALUE_MULTIPLIER: usize = 12;
pub const VALUE_MULTIPLIER_END: usize = 15;
pub const NUMBER_OF_CHANNELS: usize = 15;
pub const CHANNEL_VALUES: usize = 16;
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SetupRequestResponse {
buf: [u8; len::SETUP_REQUEST_RESPONSE],
}
impl SetupRequestResponse {
pub fn new() -> Self {
let mut msg = Self {
buf: [0u8; len::SETUP_REQUEST_RESPONSE],
};
msg.init();
msg
}
pub fn unit_type(&self) -> UnitType {
self.buf[index::UNIT_TYPE].into()
}
pub fn firmware_version(&self) -> FirmwareVersion {
self.buf[index::FIRMWARE_VERSION..index::FIRMWARE_VERSION_END]
.as_ref()
.into()
}
pub fn country_code(&self) -> CountryCode {
self.buf[index::COUNTRY_CODE..index::COUNTRY_CODE_END]
.as_ref()
.into()
}
pub fn value_multiplier(&self) -> ValueMultiplier {
self.buf[index::VALUE_MULTIPLIER..index::VALUE_MULTIPLIER_END]
.as_ref()
.into()
}
pub fn num_channels(&self) -> usize {
self.buf[index::NUMBER_OF_CHANNELS] as usize
}
pub fn channel_values(&self) -> Result<ChannelValueList> {
self.is_valid()?;
let channel_values_end = self.channel_values_end();
Ok(self.buf[index::CHANNEL_VALUES..channel_values_end]
.iter()
.map(|&v| ChannelValue::from([v]))
.collect::<Vec<ChannelValue>>()
.into())
}
fn channel_values_start(&self) -> usize {
index::CHANNEL_VALUES
}
fn channel_values_end(&self) -> usize {
self.channel_values_start() + self.num_channels()
}
pub fn channel_security_levels(&self) -> Result<&[u8]> {
self.is_valid()?;
let channel_sec_start = self.channel_security_levels_start();
let channel_sec_end = self.channel_security_levels_end();
Ok(self.buf[channel_sec_start..channel_sec_end].as_ref())
}
fn channel_security_levels_start(&self) -> usize {
self.channel_values_end()
}
fn channel_security_levels_end(&self) -> usize {
self.channel_security_levels_start() + self.num_channels()
}
pub fn real_value_multiplier(&self) -> Result<ValueMultiplier> {
self.is_valid()?;
let real_value_start = self.real_value_multiplier_start();
let real_value_end = self.real_value_multiplier_end();
Ok(self.buf[real_value_start..real_value_end].as_ref().into())
}
fn real_value_multiplier_start(&self) -> usize {
self.channel_security_levels_end()
}
fn real_value_multiplier_end(&self) -> usize {
self.real_value_multiplier_start() + len::U24
}
pub fn protocol_version(&self) -> Result<ProtocolVersion> {
self.is_valid()?;
let protocol_version_idx = self.protocol_version_start();
Ok(self.buf[protocol_version_idx].into())
}
fn protocol_version_start(&self) -> usize {
self.real_value_multiplier_end()
}
fn protocol_version_end(&self) -> usize {
self.protocol_version_start() + 1
}
pub fn channel_country_codes(&self) -> Result<CountryCodeList> {
self.is_valid()?;
let channel_country_code_start = self.channel_country_codes_start();
let channel_country_code_end = self.channel_country_codes_end();
Ok(
self.buf[channel_country_code_start..channel_country_code_end]
.chunks_exact(len::U24)
.map(CountryCode::from)
.collect::<Vec<CountryCode>>()
.into(),
)
}
fn channel_country_codes_start(&self) -> usize {
self.protocol_version_end()
}
fn channel_country_codes_end(&self) -> usize {
self.channel_country_codes_start() + (len::U24 * self.num_channels())
}
pub fn channel_values_long(&self) -> Result<ChannelValueList> {
self.is_valid()?;
let channel_values_start = self.channel_values_long_start();
let channel_values_end = self.channel_values_long_end();
Ok(self.buf[channel_values_start..channel_values_end]
.chunks_exact(4)
.map(ChannelValue::from)
.collect::<Vec<ChannelValue>>()
.into())
}
fn channel_values_long_start(&self) -> usize {
self.channel_country_codes_end()
}
fn channel_values_long_end(&self) -> usize {
self.channel_values_long_start() + (4 * self.num_channels())
}
pub fn is_valid(&self) -> Result<()> {
use crate::message::index as msg_index;
let channel_values_start = self.channel_values_long_start();
let channel_values_end = self.channel_values_long_end();
let protocol_start = self.protocol_version_start();
let protocol_end = self.protocol_version_end();
let buf_end = len::HEADER + self.data_len();
let buf_range = msg_index::DATA..=buf_end;
let protocol = self
.buf
.get(protocol_start)
.ok_or(Error::InvalidDataLength((protocol_start, buf_end)))?;
let (start, end) = if *protocol < 6 {
(protocol_start, protocol_end)
} else {
(channel_values_start, channel_values_end)
};
if buf_range.contains(&start) && buf_range.contains(&end) {
Ok(())
} else {
Err(Error::InvalidDataLength((end, buf_end)))
}
}
}
impl_default!(SetupRequestResponse);
impl_message_from_buf!(SetupRequestResponse);
impl_var_message_ops!(SetupRequestResponse, MessageType::SetupRequest);
impl_response_ops!(SetupRequestResponse);
impl fmt::Display for SetupRequestResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.is_valid() {
Ok(_) => {
let stx = self.stx();
let seqid = self.sequence_id();
let data_len = self.data_len();
let status = self.response_status();
let unit = self.unit_type();
let firmware_version = self.firmware_version();
let country_code = self.country_code();
let value_multi = self.value_multiplier();
let num_channels = self.num_channels();
let channel_values = self.channel_values().unwrap();
let channel_sec = self.channel_security_levels().unwrap();
let real_value_multi = self.real_value_multiplier().unwrap();
let protocol_version = self.protocol_version().unwrap();
let crc = self.checksum();
write!(
f,
"STX: 0x{stx:02x} | SEQID: {seqid} | LEN: 0x{data_len:02x} | Response status: {status} | Unit type: {unit} | Firmware version: {firmware_version} | Country code: {country_code} | Value multiplier: {value_multi} | Number of channels: {num_channels} | Channel values: {channel_values} | Channel security levels: {channel_sec:02x?} | Real value multiplier: {real_value_multi} | Protocol version: {protocol_version}")?;
if (protocol_version as u8) < 6 {
write!(f, "| CRC-16: 0x{crc:04x}")
} else {
let channel_country_codes = self.channel_country_codes().unwrap();
let channel_values_long = self.channel_values_long().unwrap();
write!(f, "| Channel country codes: {channel_country_codes} | Channel values (long): {channel_values_long} | CRC-16: 0x{crc:04x}")
}
}
Err(err) => {
write!(f, "Invalid SetupRequestResponse message: {err}")
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[rustfmt::skip]
fn test_setup_request_response() -> Result<()> {
use crate::{STX, ResponseOps, ResponseStatus};
let setup_request_response_bytes = [
STX,
0x80,
0x35,
0xf0,
0x00,
0x00, 0x33, 0x33, 0x33,
0x45, 0x55, 0x52,
0x00, 0x00, 0x01,
0x04,
0x05, 0x0a, 0x14, 0x32,
0x02, 0x02, 0x02, 0x02,
0x00, 0x00, 0x64,
0x07,
0x45, 0x55, 0x52,
0x45, 0x55, 0x52,
0x45, 0x55, 0x52,
0x45, 0x55, 0x52,
0x05, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00,
0x8b, 0x9b,
];
let exp_response = ResponseStatus::Ok;
let exp_unit_type = UnitType::from(0x00);
let exp_firmware_version = FirmwareVersion::from(b"0333");
let exp_country_code = CountryCode::from(b"EUR");
let exp_value_multiplier = ValueMultiplier::from(1);
let exp_num_channels = 4;
let exp_channel_values = [
ChannelValue::from(5),
ChannelValue::from(10),
ChannelValue::from(20),
ChannelValue::from(50),
];
let exp_channel_security = [2, 2, 2, 2];
let exp_real_value_multiplier = ValueMultiplier::from(100);
let exp_protocol_version = ProtocolVersion::Seven;
let exp_country_codes = [
CountryCode::from(b"EUR"),
CountryCode::from(b"EUR"),
CountryCode::from(b"EUR"),
CountryCode::from(b"EUR"),
];
let exp_channel_values_long = [
ChannelValue::from(5),
ChannelValue::from(10),
ChannelValue::from(20),
ChannelValue::from(50),
];
let response = SetupRequestResponse::try_from(setup_request_response_bytes)?;
assert_eq!(response.len(), setup_request_response_bytes.len());
assert_eq!(response.data_len(), setup_request_response_bytes.len() - len::METADATA);
assert_eq!(response.response_status(), exp_response);
assert_eq!(response.unit_type(), exp_unit_type);
assert_eq!(response.firmware_version(), exp_firmware_version);
assert_eq!(response.country_code(), exp_country_code);
assert_eq!(response.value_multiplier(), exp_value_multiplier);
assert_eq!(response.num_channels(), exp_num_channels);
assert_eq!(response.channel_values()?.as_ref(), exp_channel_values.as_ref());
assert_eq!(response.channel_security_levels()?, exp_channel_security.as_ref());
assert_eq!(response.real_value_multiplier()?, exp_real_value_multiplier);
assert_eq!(response.protocol_version()?, exp_protocol_version);
assert_eq!(response.channel_country_codes()?.as_ref(), exp_country_codes.as_ref());
assert_eq!(response.channel_values_long()?.as_ref(), exp_channel_values_long.as_ref());
Ok(())
}
}