use crate::base::DataValueRaw;
use snafu::ensure;
use std::io::{Read, Write};
use crate::{
error, DataValueReaderExt, DataValueWriterExt, Endian,
HasFixedCommandId, MessageExt, ReadExt, ReadFromPayload, Result,
WithFixedPayloadLength, WriteExt,
};
#[derive(Clone, Debug, PartialEq)]
pub struct Notification {
pub tag: u8,
pub values: Vec<DataValueRaw>,
}
impl Notification {
const ADDITIONAL_FIXED_PAYLOAD_LENGTH: u16 =
u8::FIXED_PAYLOAD_LENGTH + u16::FIXED_PAYLOAD_LENGTH;
fn verify_payload_length(received: u16, required: u16) -> Result<()> {
ensure!(
required == received,
error::InvalidPayloadLength {
message_type: "measurement_data_notification",
received: received as usize,
required: required as usize
}
);
Ok(())
}
}
impl From<Notification> for super::Notification {
fn from(m: Notification) -> Self {
super::Notification::MeasurementData(m)
}
}
impl HasFixedCommandId for Notification {
const COMMAND_ID: u16 = 0x8805;
}
impl MessageExt for Notification {
fn payload_length(&self) -> u16 {
Self::ADDITIONAL_FIXED_PAYLOAD_LENGTH
+ self.values.len() as u16 * DataValueRaw::FIXED_PAYLOAD_LENGTH
}
fn write_payload(&self, w: &mut Write) -> Result<()> {
w.write_u8(self.tag)?;
w.write_u16::<Endian>(self.values.len() as u16)?;
w.write_data_values(&self.values)?;
Ok(())
}
}
impl ReadFromPayload for Notification {
fn read_from_payload<R: Read>(
r: &mut R,
payload_length: u16,
) -> Result<Self> {
let tag = r.read_u8()?;
let count = r.read_u16::<Endian>()?;
let required_payload_length = Self::ADDITIONAL_FIXED_PAYLOAD_LENGTH
+ count * DataValueRaw::FIXED_PAYLOAD_LENGTH;
Self::verify_payload_length(
payload_length,
required_payload_length,
)?;
let values = r.read_data_values(count as usize)?;
Ok(Self { tag, values })
}
}
#[cfg(test)]
mod test_notification {
use super::*;
#[test]
fn write_to_empty() {
let mut buffer = Vec::new();
let options: u8 = 0x45;
let sequence: u8 = 0x93;
let tag = 0x87;
let values = Vec::new();
let message = Notification { tag, values };
message.write_to(&mut buffer, options, sequence).unwrap();
assert_eq!(
buffer,
vec![
0x45,
0x93,
0x05,
0x88,
0x03,
0x00,
0x87,
0x00,
0x00,
]
);
}
#[test]
fn write_to_single_boolean() {
let mut buffer = Vec::new();
let options: u8 = 0x45;
let sequence: u8 = 0x93;
let tag = 0x87;
let values = vec![true.into()];
let length = {
let fixed = 3u16;
let per_value = 9u16;
let value_count = 1u16;
fixed + per_value * value_count
};
assert_eq!(length, 0x000C);
assert_eq!(0x000C, 12);
let message = Notification { tag, values };
message.write_to(&mut buffer, options, sequence).unwrap();
assert_eq!(
buffer,
vec![
0x45,
0x93,
0x05,
0x88,
0x0C,
0x00,
0x87,
0x01,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
]
);
}
#[test]
fn write_to_three_items() {
let mut buffer = Vec::new();
let options: u8 = 0x45;
let sequence: u8 = 0x93;
let tag = 0x87;
let values = vec![
0x1234u16.into(),
true.into(),
0x9988776655443322u64.into(),
];
let length = {
let fixed = 3u16;
let per_value = 9u16;
let value_count = 3u16;
fixed + per_value * value_count
};
assert_eq!(length, 0x001E);
assert_eq!(0x001E, 30);
let message = Notification { tag, values };
message.write_to(&mut buffer, options, sequence).unwrap();
assert_eq!(
buffer,
vec![
0x45,
0x93,
0x05,
0x88,
0x1E,
0x00,
0x87,
0x03,
0x00,
0x06,
0x00,
0x08,
0x34,
0x12,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x22,
0x33,
0x44,
0x55,
0x66,
0x77,
0x88,
0x99,
]
);
}
#[test]
fn from_payload_empty() {
let buffer = vec![
0x86,
0x00,
0x00,
];
let len = buffer.len() as u16;
let message =
Notification::read_from_payload(&mut buffer.as_slice(), len)
.unwrap();
let tag = 0x86;
let values = Vec::new();
assert_eq!(message, Notification { tag, values });
}
#[test]
fn from_payload_single_bool() {
let buffer = vec![
0x86,
0x01,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
];
let len = buffer.len() as u16;
let message =
Notification::read_from_payload(&mut buffer.as_slice(), len)
.unwrap();
let tag = 0x86;
let values = vec![true.into()];
assert_eq!(message, Notification { tag, values });
}
#[test]
fn read_from_three_items() {
let buffer = vec![
0x87,
0x03,
0x00,
0x06,
0x00,
0x08,
0x34,
0x12,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x22,
0x33,
0x44,
0x55,
0x66,
0x77,
0x88,
0x99,
];
let len = buffer.len() as u16;
let message =
Notification::read_from_payload(&mut buffer.as_slice(), len)
.unwrap();
let tag = 0x87;
let values = vec![
0x1234u16.into(),
true.into(),
0x9988776655443322u64.into(),
];
assert_eq!(message, Notification { tag, values });
}
}