use cmds::{CommandClass, Message};
use error::{Error, ErrorKind};
use enum_primitive::FromPrimitive;
enum_from_primitive! {
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum PowerLevelStatus {
NormalPower = 0x00,
minus1dBm = 0x01,
minus2dBm = 0x02,
minus3dBm = 0x03,
minus4dBm = 0x04,
minus5dBm = 0x05,
minus6dBm = 0x06,
minus7dBm = 0x07,
minus8dBm = 0x08,
minus9dBm = 0x09,
}}
enum_from_primitive! {
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum PowerLevelOperationStatus {
TestFailed = 0x00, TestSuccess = 0x01, TestInProgress = 0x02, }}
#[derive(Debug, Clone)]
pub struct PowerLevel;
impl PowerLevel {
pub fn set<N, L, S>(node_id: N, level: L, seconds: S) -> Message
where N: Into<u8>, L: Into<PowerLevelStatus>, S: Into<u8> {
Message::new(node_id.into(), CommandClass::POWER_LEVEL, 0x01, vec!(level.into() as u8, seconds.into()))
}
pub fn get<N>(node_id: N) -> Message
where N: Into<u8> {
Message::new(node_id.into(), CommandClass::POWER_LEVEL, 0x02, vec!())
}
pub fn report<M>(msg: M) -> Result<(PowerLevelStatus, u8), Error>
where M: Into<Vec<u8>> {
let msg = msg.into();
if msg.len() != 7 {
return Err(Error::new(ErrorKind::UnknownZWave, "Message is to short"));
}
if msg[3] != CommandClass::POWER_LEVEL as u8 || msg[4] != 0x03 {
return Err(Error::new(ErrorKind::UnknownZWave, "Answer contained wrong command class"));
}
let level = PowerLevelStatus::from_u8(msg[5]).ok_or(Error::new(ErrorKind::UnknownZWave, "Answer contained wrong power level state"))?;
Ok((level, msg[6]))
}
pub fn test_node_set<N, T, L, F>(node_id: N, test_node_id: T, level: L, test_frames: F) -> Message
where N: Into<u8>, T: Into<u8>, L: Into<PowerLevelStatus>, F: Into<u16> {
let frames = PowerLevel::transform_u16_to_array_of_u8(test_frames.into());
Message::new(node_id.into(), CommandClass::POWER_LEVEL, 0x04, vec!(test_node_id.into(), level.into() as u8, frames[0], frames[1]))
}
pub fn test_node_get<N>(node_id: N) -> Message
where N: Into<u8> {
Message::new(node_id.into(), CommandClass::POWER_LEVEL, 0x05, vec!())
}
pub fn test_node_report<M>(msg: M) -> Result<(u8, PowerLevelOperationStatus, u16), Error>
where M: Into<Vec<u8>> {
let msg = msg.into();
if msg.len() != 9 {
return Err(Error::new(ErrorKind::UnknownZWave, format!("Message is to short: {:?}", msg)));
}
if msg[3] != CommandClass::POWER_LEVEL as u8 || msg[4] != 0x06 {
return Err(Error::new(ErrorKind::UnknownZWave, "Answer contained wrong command class"));
}
let n_id = msg[5];
let level = PowerLevelOperationStatus::from_u8(msg[6]).ok_or(Error::new(ErrorKind::UnknownZWave, "Answer contained wrong operation status"))?;
let frame = PowerLevel::transform_array_of_u8_to_u16(msg[7], msg[8]);
Ok((n_id, level, frame))
}
fn transform_u16_to_array_of_u8(x:u16) -> [u8;2] {
let b1 : u8 = ((x >> 8) & 0xff) as u8;
let b2 : u8 = (x & 0xff) as u8;
return [b1, b2]
}
fn transform_array_of_u8_to_u16(msb:u8, lsb:u8) -> u16 {
let msb = msb as u16;
let lsb = lsb as u16;
((msb << 8) | lsb)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn transform_u16_to_u8() {
assert_eq!([0x00, 0x00], PowerLevel::transform_u16_to_array_of_u8(0));
assert_eq!([0x00, 0x01], PowerLevel::transform_u16_to_array_of_u8(1));
assert_eq!([0x01, 0x00], PowerLevel::transform_u16_to_array_of_u8(256));
assert_eq!([0x01, 0x01], PowerLevel::transform_u16_to_array_of_u8(257));
}
#[test]
fn transform_u8_to_u16() {
assert_eq!(0, PowerLevel::transform_array_of_u8_to_u16(0x00, 0x00));
assert_eq!(1, PowerLevel::transform_array_of_u8_to_u16(0x00, 0x01));
assert_eq!(256, PowerLevel::transform_array_of_u8_to_u16(0x01, 0x00));
assert_eq!(257, PowerLevel::transform_array_of_u8_to_u16(0x01, 0x01));
}
}