use super::mutation_list_wire_tests::wire;
use super::mutation_tests::Fixture;
use super::*;
use bacnet_objects::lighting::LightingOutputObject;
use bacnet_services::read_property::ReadPropertyRequest;
use bacnet_services::write_property::WritePropertyRequest;
use std::sync::Mutex as StdMutex;
use std::time::Duration;
const WRITE: ConfirmedServiceChoice = ConfirmedServiceChoice::WRITE_PROPERTY;
const READ: ConfirmedServiceChoice = ConfirmedServiceChoice::READ_PROPERTY;
const SIMPLE_ACK: [u8; 3] = [0x20, 5, 15];
fn lo1() -> ObjectIdentifier {
ObjectIdentifier::new(ObjectType::LIGHTING_OUTPUT, 1).unwrap()
}
async fn fixture() -> (Fixture, Arc<StdMutex<Duration>>) {
let fixture = Fixture::new(None);
let now = Arc::new(StdMutex::new(Duration::ZERO));
let source = Arc::clone(&now);
let mut db = fixture.db.write().await;
db.set_monotonic_clock_internal(Some(Arc::new(move || *source.lock().unwrap())));
db.add(Box::new(LightingOutputObject::new(1, "LO-1").unwrap()))
.unwrap();
drop(db);
(fixture, now)
}
async fn write(
fixture: &Fixture,
property: PropertyIdentifier,
value: &[u8],
priority: Option<u8>,
) -> Vec<u8> {
let mut request = BytesMut::new();
WritePropertyRequest {
object_identifier: lo1(),
property_identifier: property,
property_array_index: None,
property_value: value.to_vec(),
priority,
}
.encode(&mut request)
.unwrap();
wire(fixture, WRITE, request.freeze()).await
}
async fn read(fixture: &Fixture, property: PropertyIdentifier) -> Vec<u8> {
let mut request = BytesMut::new();
ReadPropertyRequest {
object_identifier: lo1(),
property_identifier: property,
property_array_index: None,
}
.encode(&mut request);
wire(fixture, READ, request.freeze()).await
}
fn read_ack(property_octets: &[u8], value: &[u8]) -> Vec<u8> {
[
&[0x30, 5, 12, 0x0C, 0x0D, 0x80, 0x00, 0x01][..],
property_octets,
&[0x3E],
value,
&[0x3F],
]
.concat()
}
const PRESENT_VALUE: [u8; 2] = [0x19, 0x55];
const TRACKING_VALUE: [u8; 2] = [0x19, 0xA4];
const IN_PROGRESS: [u8; 3] = [0x1A, 0x01, 0x7A];
#[tokio::test]
async fn a_fade_written_over_the_wire_is_carried_out() {
let (fixture, now) = fixture().await;
let level = [0x44, 0x41, 0xA0, 0x00, 0x00];
assert_eq!(
write(&fixture, PropertyIdentifier::PRESENT_VALUE, &level, Some(8)).await,
SIMPLE_ACK
);
let fade = [
0x09, 0x01, 0x1C, 0x42, 0xC8, 0x00, 0x00, 0x4A, 0x07, 0xD0, 0x59, 0x08,
];
assert_eq!(
write(&fixture, PropertyIdentifier::LIGHTING_COMMAND, &fade, None).await,
SIMPLE_ACK
);
*now.lock().unwrap() = Duration::from_millis(1_000);
assert_eq!(
read(&fixture, PropertyIdentifier::PRESENT_VALUE).await,
read_ack(&PRESENT_VALUE, &[0x44, 0x42, 0xC8, 0x00, 0x00])
);
assert_eq!(
read(&fixture, PropertyIdentifier::TRACKING_VALUE).await,
read_ack(&TRACKING_VALUE, &[0x44, 0x42, 0x70, 0x00, 0x00])
);
assert_eq!(
read(&fixture, PropertyIdentifier::IN_PROGRESS).await,
read_ack(&IN_PROGRESS, &[0x91, 0x01])
);
*now.lock().unwrap() = Duration::from_millis(2_000);
assert_eq!(
read(&fixture, PropertyIdentifier::IN_PROGRESS).await,
read_ack(&IN_PROGRESS, &[0x91, 0x00])
);
}
#[tokio::test]
async fn present_value_warn_values_are_taken_and_their_neighbours_refused() {
let (fixture, _) = fixture().await;
let level = [0x44, 0x42, 0xA0, 0x00, 0x00];
let warn_off = [0x44, 0xC0, 0x40, 0x00, 0x00];
for value in [level, warn_off] {
assert_eq!(
write(&fixture, PropertyIdentifier::PRESENT_VALUE, &value, Some(8)).await,
SIMPLE_ACK
);
}
assert_eq!(
read(&fixture, PropertyIdentifier::PRESENT_VALUE).await,
read_ack(&PRESENT_VALUE, &[0x44, 0x00, 0x00, 0x00, 0x00])
);
assert_eq!(
write(
&fixture,
PropertyIdentifier::PRESENT_VALUE,
&[0x44, 0xBF, 0xC0, 0x00, 0x00],
Some(8)
)
.await,
[0x50, 5, 15, 0x91, 0x02, 0x91, 0x25]
);
}
#[tokio::test]
async fn lighting_command_default_priority_refuses_six_over_the_wire() {
let (fixture, _) = fixture().await;
let lcdp = PropertyIdentifier::LIGHTING_COMMAND_DEFAULT_PRIORITY;
assert_eq!(write(&fixture, lcdp, &[0x21, 0x07], None).await, SIMPLE_ACK);
assert_eq!(
write(&fixture, lcdp, &[0x21, 0x06], None).await,
[0x50, 5, 15, 0x91, 0x02, 0x91, 0x25]
);
assert_eq!(
read(&fixture, lcdp).await,
read_ack(&[0x1A, 0x01, 0x7D], &[0x21, 0x07])
);
}
#[path = "lighting_link_wire_tests.rs"]
mod link;