use std::time::Duration;
use bacnet_transport::mstp::{
MasterState, MstpDiagnostics, MstpDiagnosticsSnapshot, MstpNodeState,
};
use super::message::WorkerEvent;
use super::worker::EventSink;
use crate::mstp::MstpArgs;
pub(crate) const SAMPLE_EVERY: Duration = Duration::from_secs(1);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct NodeView {
pub(crate) state: &'static str,
pub(crate) holds_token: bool,
pub(crate) next_station: u8,
pub(crate) poll_station: u8,
pub(crate) sole_master: bool,
}
impl From<MstpNodeState> for NodeView {
fn from(node: MstpNodeState) -> Self {
let (state, holds_token) = match node.state {
MasterState::Idle => ("IDLE", false),
MasterState::NoToken => ("NO_TOKEN", false),
MasterState::UseToken => ("USE_TOKEN", true),
MasterState::DoneWithToken => ("DONE_WITH_TOKEN", true),
MasterState::PassToken => ("PASS_TOKEN", false),
MasterState::WaitForReply => ("WAIT_FOR_REPLY", true),
MasterState::PollForMaster => ("POLL_FOR_MASTER", true),
MasterState::AnswerDataRequest => ("ANSWER_DATA_REQUEST", false),
};
Self {
state,
holds_token,
next_station: node.next_station,
poll_station: node.poll_station,
sole_master: node.sole_master,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Sample {
pub(crate) node: Option<NodeView>,
pub(crate) counters: MstpDiagnosticsSnapshot,
}
impl Sample {
pub(crate) fn of(handle: &MstpDiagnostics) -> Self {
Self {
node: handle.node_state().map(NodeView::from),
counters: handle.snapshot(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum MstpReport {
Joined(MstpArgs, String),
Sample(Box<Sample>),
}
pub(crate) async fn sample(handle: MstpDiagnostics, sink: EventSink) {
let mut every = tokio::time::interval(SAMPLE_EVERY);
every.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
loop {
every.tick().await;
let report = WorkerEvent::Mstp(MstpReport::Sample(Box::new(Sample::of(&handle))));
if let super::worker::Offer::Closed = sink.offer(report) {
return std::future::pending().await;
}
}
}