use super::*;
use crate::next;
use crate::ok;
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub enum NotificationMessage {
HubProperties(HubProperty),
HubActions(HubActionRequest),
HubAlerts(HubAlert),
HubAttachedIo(AttachedIo),
GenericErrorMessages(ErrorMessageFormat),
HwNetworkCommands(NetworkCommand),
FwUpdateGoIntoBootMode([u8; 9]),
FwUpdateLockMemory([u8; 8]),
FwUpdateLockStatusRequest,
FwLockStatus(LockStatus),
PortInformationRequest(InformationRequest),
PortModeInformationRequest(ModeInformationRequest),
PortInputFormatSetupSingle(InputSetupSingle),
PortInputFormatSetupCombinedmode(InputSetupCombined),
PortInformation(PortInformationValue),
PortModeInformation(PortModeInformationValue),
PortValueSingle(PortValueSingleFormat),
PortValueCombined(PortValueCombinedFormat),
PortInputFormatSingle(PortInputFormatSingleFormat),
PortInputFormatCombinedmode(PortInputFormatCombinedFormat),
VirtualPortSetup(VirtualPortSetupFormat),
PortOutputCommand(PortOutputCommandFormat),
PortOutputCommandFeedback(PortOutputCommandFeedbackFormat),
}
impl NotificationMessage {
pub fn parse(msg: &[u8]) -> Result<Self> {
use NotificationMessage::*;
debug!("NOTIFICATION: {:?}", msg);
let mut msg_iter = msg.iter();
Self::validate_length(&mut msg_iter, msg.len())?;
trace!("Length: {}", msg.len());
let _hub_id = next!(msg_iter);
trace!("Hub ID: {}", _hub_id);
let message_type = ok!(MessageType::from_u8(next!(msg_iter)));
trace!(
"Identified message type: {:?} = {:x}",
message_type,
message_type as u8
);
Ok(match message_type {
MessageType::HubProperties => {
let props = HubProperty::parse(&mut msg_iter)?;
HubProperties(props)
}
MessageType::HubActions => {
let action = HubActionRequest::parse(&mut msg_iter)?;
HubActions(action)
}
MessageType::HubAlerts => {
let alert = HubAlert::parse(&mut msg_iter)?;
HubAlerts(alert)
}
MessageType::HubAttachedIo => {
let attach = AttachedIo::parse(&mut msg_iter)?;
HubAttachedIo(attach)
}
MessageType::GenericErrorMessages => {
let error = ErrorMessageFormat::parse(&mut msg_iter)?;
GenericErrorMessages(error)
}
MessageType::HwNetworkCommands => {
let command = NetworkCommand::parse(&mut msg_iter)?;
HwNetworkCommands(command)
}
MessageType::FwUpdateGoIntoBootMode => {
let mut safety = [0_u8; 9];
for ele in safety.iter_mut() {
*ele = next!(msg_iter);
}
FwUpdateGoIntoBootMode(safety)
}
MessageType::FwUpdateLockMemory => {
let mut safety = [0_u8; 8];
for ele in safety.iter_mut() {
*ele = next!(msg_iter);
}
FwUpdateLockMemory(safety)
}
MessageType::FwUpdateLockStatusRequest => FwUpdateLockStatusRequest,
MessageType::FwLockStatus => {
let status = LockStatus::parse(&mut msg_iter)?;
FwLockStatus(status)
}
MessageType::PortInformationRequest => {
let req = InformationRequest::parse(&mut msg_iter)?;
PortInformationRequest(req)
}
MessageType::PortModeInformationRequest => {
let req = ModeInformationRequest::parse(&mut msg_iter)?;
PortModeInformationRequest(req)
}
MessageType::PortInputFormatSetupSingle => {
let setup = InputSetupSingle::parse(&mut msg_iter)?;
PortInputFormatSetupSingle(setup)
}
MessageType::PortInputFormatSetupCombined => {
let setup = InputSetupCombined::parse(&mut msg_iter)?;
PortInputFormatSetupCombinedmode(setup)
}
MessageType::PortInformation => {
let info = PortInformationValue::parse(&mut msg_iter)?;
PortInformation(info)
}
MessageType::PortModeInformation => {
let info = PortModeInformationValue::parse(&mut msg_iter)?;
PortModeInformation(info)
}
MessageType::PortValueSingle => {
let value = PortValueSingleFormat::parse(&mut msg_iter)?;
PortValueSingle(value)
}
MessageType::PortValueCombined => {
let value = PortValueCombinedFormat::parse(&mut msg_iter)?;
PortValueCombined(value)
}
MessageType::PortInputFormatSingle => {
let fmt = PortInputFormatSingleFormat::parse(&mut msg_iter)?;
PortInputFormatSingle(fmt)
}
MessageType::PortInputFormatCombined => {
let fmt = PortInputFormatCombinedFormat::parse(&mut msg_iter)?;
PortInputFormatCombinedmode(fmt)
}
MessageType::VirtualPortSetup => {
let setup = VirtualPortSetupFormat::parse(&mut msg_iter)?;
VirtualPortSetup(setup)
}
MessageType::PortOutputCommand => {
let cmd = PortOutputCommandFormat::parse(&mut msg_iter)?;
PortOutputCommand(cmd)
}
MessageType::PortOutputCommandFeedback => {
let feedback =
PortOutputCommandFeedbackFormat::parse(&mut msg_iter)?;
PortOutputCommandFeedback(feedback)
}
})
}
pub fn message_type(&self) -> u8 {
use NotificationMessage::*;
(match self {
HubProperties(_) => MessageType::HubProperties,
HubActions(_) => MessageType::HubActions,
HubAlerts(_) => MessageType::HubAlerts,
HubAttachedIo(_) => MessageType::HubAttachedIo,
GenericErrorMessages(_) => MessageType::GenericErrorMessages,
HwNetworkCommands(_) => MessageType::HwNetworkCommands,
FwUpdateGoIntoBootMode(_) => MessageType::FwUpdateGoIntoBootMode,
FwUpdateLockMemory(_) => MessageType::FwUpdateLockMemory,
FwUpdateLockStatusRequest => MessageType::FwUpdateLockStatusRequest,
FwLockStatus(_) => MessageType::FwLockStatus,
PortInformationRequest(_) => MessageType::PortInformationRequest,
PortModeInformationRequest(_) => {
MessageType::PortModeInformationRequest
}
PortInputFormatSetupSingle(_) => {
MessageType::PortInputFormatSetupSingle
}
PortInputFormatSetupCombinedmode(_) => {
MessageType::PortInputFormatSetupCombined
}
PortInformation(_) => MessageType::PortInformation,
PortModeInformation(_) => MessageType::PortModeInformation,
PortValueSingle(_) => MessageType::PortValueSingle,
PortValueCombined(_) => MessageType::PortValueCombined,
PortInputFormatSingle(_) => MessageType::PortInputFormatSingle,
PortInputFormatCombinedmode(_) => {
MessageType::PortInputFormatCombined
}
VirtualPortSetup(_) => MessageType::VirtualPortSetup,
PortOutputCommand(_) => MessageType::PortOutputCommand,
PortOutputCommandFeedback(_) => {
MessageType::PortOutputCommandFeedback
}
}) as u8
}
fn validate_length<'a>(
mut msg: impl Iterator<Item = &'a u8>,
supplied: usize,
) -> Result<()> {
let calculated = Self::length(&mut msg)?;
if calculated != supplied {
Err(Error::ParseError(format!(
"Length mismatch {} != {}",
calculated, supplied
)))
} else {
Ok(())
}
}
pub fn length<'a>(mut msg: impl Iterator<Item = &'a u8>) -> Result<usize> {
let first = next!(msg);
let length = if first & 0x80 == 0x00 {
(first & 0x7f) as usize
} else {
let second = next!(msg); eprintln!("second: {:x}", second);
((second as usize) << 7) | ((first & 0x7f) as usize)
};
Ok(length)
}
pub fn checksum(buf: &[u8]) -> u8 {
buf.iter().fold(0xff, |acc, x| acc ^ x)
}
pub fn serialise(&self) -> Vec<u8> {
use NotificationMessage::*;
let mut ser = match self {
HubProperties(msg) => msg.serialise(),
HubActions(msg) => msg.serialise(),
HubAlerts(msg) => msg.serialise(),
HwNetworkCommands(_) => todo!(),
FwUpdateGoIntoBootMode(_) => todo!(),
FwUpdateLockMemory(_) => todo!(),
FwUpdateLockStatusRequest => todo!(),
PortInformationRequest(msg) => msg.serialise(),
PortModeInformationRequest(msg) => msg.serialise(),
PortInputFormatSetupSingle(msg) => msg.serialise(),
PortInputFormatSetupCombinedmode(msg) => msg.serialise(),
VirtualPortSetup(_) => todo!(),
PortOutputCommand(cmd) => cmd.serialise(),
HubAttachedIo(_) => todo!(),
GenericErrorMessages(_) => todo!(),
FwLockStatus(_) => todo!(),
PortInformation(_) => todo!(),
PortModeInformation(_) => todo!(),
PortValueSingle(_) => todo!(),
PortValueCombined(_) => todo!(),
PortInputFormatSingle(_) => todo!(),
PortInputFormatCombinedmode(_) => todo!(),
PortOutputCommandFeedback(_) => todo!(),
};
ser[0] = ser.len() as u8;
debug!("Serialised to: {:02x?}", ser);
ser
}
}