use bacnet_types::constructed::BACnetLightingCommand;
use bacnet_types::enums::LightingOperation;
use bacnet_types::error::Error;
use bytes::BytesMut;
use super::members::unsigned_field;
use super::tagged::{decode_ctx_real, decode_optional_ctx, expect_end};
use crate::primitives;
const WHAT: &str = "lighting command";
pub fn encode_lighting_command(buf: &mut BytesMut, value: &BACnetLightingCommand) {
primitives::encode_ctx_enumerated(buf, 0, value.operation.to_raw());
let levels = [value.target_level, value.ramp_rate, value.step_increment];
for (tag, level) in (1..).zip(levels) {
if let Some(level) = level {
primitives::encode_ctx_real(buf, tag, level);
}
}
if let Some(fade_time) = value.fade_time {
primitives::encode_ctx_unsigned(buf, 4, fade_time.into());
}
if let Some(priority) = value.priority {
primitives::encode_ctx_unsigned(buf, 5, priority.into());
}
}
pub(super) type Fields = (BACnetLightingCommand, usize, Option<&'static str>);
pub(super) fn decode_fields(data: &[u8], offset: usize) -> Result<Fields, Error> {
let mut oversized = None;
let (operation, offset) = unsigned_field::<u32>(
data,
offset,
0,
WHAT,
"operation [0] exceeds 32 bits",
&mut oversized,
)?;
let (target_level, offset) = decode_optional_ctx(data, offset, 1, WHAT, decode_ctx_real)?;
let (ramp_rate, offset) = decode_optional_ctx(data, offset, 2, WHAT, decode_ctx_real)?;
let (step_increment, offset) = decode_optional_ctx(data, offset, 3, WHAT, decode_ctx_real)?;
let (fade_time, offset) = decode_optional_ctx(data, offset, 4, WHAT, |data, at, tag, _| {
unsigned_field::<u32>(
data,
at,
tag,
WHAT,
"fade-time [4] exceeds 32 bits",
&mut oversized,
)
})?;
let (priority, offset) = decode_optional_ctx(data, offset, 5, WHAT, |data, at, tag, _| {
unsigned_field::<u8>(
data,
at,
tag,
WHAT,
"priority [5] exceeds an Unsigned8",
&mut oversized,
)
})?;
let command = BACnetLightingCommand {
operation: LightingOperation::from_raw(operation),
target_level,
ramp_rate,
step_increment,
fade_time,
priority,
};
Ok((command, offset, oversized))
}
fn too_wide(field: &'static str) -> Error {
Error::OutOfRange(format!("{WHAT} {field}"))
}
pub fn decode_lighting_command(
data: &[u8],
offset: usize,
) -> Result<(BACnetLightingCommand, usize), Error> {
let (command, end, oversized) = decode_fields(data, offset)?;
match oversized {
Some(field) => Err(too_wide(field)),
None => Ok((command, end)),
}
}
pub fn decode_lighting_command_value(data: &[u8]) -> Result<BACnetLightingCommand, Error> {
let (command, end, oversized) = decode_fields(data, 0)?;
expect_end(data, end, end, WHAT)?;
match oversized {
Some(field) => Err(too_wide(field)),
None => Ok(command),
}
}