use crate::layer::ReceivedNetworkControl;
use bacnet_npdu::NetworkMessageType;
use bacnet_router_core::message::NetworkNumberIs;
use bacnet_types::network_number::NetworkNumber;
use std::sync::Arc;
use std::sync::atomic::{AtomicU16, Ordering};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberControl {
WhatIs,
NumberIs {
number: u16,
flag: u8,
},
}
impl NumberControl {
pub fn parse(control: &ReceivedNetworkControl) -> Option<Self> {
Self::parse_npdu(&control.npdu, control.link_layer_group)
}
pub fn parse_npdu(npdu: &bacnet_encoding::npdu::Npdu, link_layer_group: bool) -> Option<Self> {
if !npdu.is_network_message() || npdu.source.is_some() || npdu.destination.is_some() {
return None;
}
match npdu.message_type {
Some(t)
if t == NetworkMessageType::WHAT_IS_NETWORK_NUMBER && npdu.payload.is_empty() =>
{
Some(Self::WhatIs)
}
Some(t) if t == NetworkMessageType::NETWORK_NUMBER_IS && link_layer_group => {
let NetworkNumberIs { network, flag } =
NetworkNumberIs::parse(&npdu.payload).ok()?;
(network != 0 && network != u16::MAX && flag <= NetworkNumberIs::CONFIGURED)
.then_some(Self::NumberIs {
number: network,
flag,
})
}
_ => None,
}
}
}
pub fn number_is_reply(state: NetworkNumber) -> Option<[u8; 6]> {
let (number, quality) = state.snapshot();
if number == 0 {
return None;
}
let [high, low, flag] = NetworkNumberIs {
network: number,
flag: u8::from(quality == 3),
}
.to_bytes();
Some([
1,
0x80,
NetworkMessageType::NETWORK_NUMBER_IS.to_raw(),
high,
low,
flag,
])
}
#[derive(Clone, Debug, Default)]
pub struct LocalNetworkNumber(Arc<AtomicU16>);
impl LocalNetworkNumber {
pub fn publish(&self, state: NetworkNumber) {
self.0.store(state.snapshot().0, Ordering::Release);
}
pub fn get(&self) -> Option<u16> {
match self.0.load(Ordering::Acquire) {
0 => None,
number => Some(number),
}
}
}
#[cfg(test)]
mod tests;