bacnet_bip_core/node/
actions.rs1use core::net::SocketAddrV4;
5
6use bacnet_bip_codec::Bvll;
7
8use super::exchange::ExchangeId;
9use super::registration::RegistrationEvent;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum Action {
16 Idle,
18 Register {
22 exchange: ExchangeId,
24 to: SocketAddrV4,
26 ttl: u16,
28 },
29 ExchangeEnded {
31 exchange: ExchangeId,
33 },
34 ReleaseHeld,
37 DiscardHeld,
40 Registration(RegistrationEvent),
42}
43
44impl Action {
45 #[must_use]
47 pub const fn message(&self) -> Option<Bvll<'static>> {
48 match *self {
49 Self::Register { ttl, .. } => Some(Bvll::RegisterForeignDevice { ttl }),
50 _ => None,
51 }
52 }
53}
54
55const EVENTS: usize = 3;
58
59#[derive(Debug, Clone)]
64pub(crate) struct Actions<const X: usize> {
65 ended: [Option<u32>; X],
67 events: [Option<RegistrationEvent>; EVENTS],
68 held: Option<bool>,
69 register: Option<(ExchangeId, SocketAddrV4, u16)>,
70}
71
72impl<const X: usize> Actions<X> {
73 pub(crate) const fn new() -> Self {
74 Self {
75 ended: [None; X],
76 events: [None; EVENTS],
77 held: None,
78 register: None,
79 }
80 }
81
82 pub(crate) fn ended(&mut self, exchange: ExchangeId) {
83 self.ended[exchange.slot()] = Some(exchange.generation());
84 }
85
86 pub(crate) fn event(&mut self, event: RegistrationEvent) {
88 match self.events.iter_mut().find(|slot| slot.is_none()) {
89 Some(slot) => *slot = Some(event),
90 None => self.events[EVENTS - 1] = Some(event),
91 }
92 }
93
94 pub(crate) fn held(&mut self, release: bool) {
95 self.held = Some(release);
96 }
97
98 pub(crate) fn register(&mut self, exchange: ExchangeId, to: SocketAddrV4, ttl: u16) {
99 self.register = Some((exchange, to, ttl));
100 }
101
102 pub(crate) fn forget_register(&mut self, exchange: ExchangeId) {
105 if self
106 .register
107 .is_some_and(|(queued, _, _)| queued == exchange)
108 {
109 self.register = None;
110 }
111 }
112
113 pub(crate) fn poll(&mut self) -> Action {
114 for (slot, ended) in self.ended.iter_mut().enumerate() {
115 if let Some(generation) = ended.take() {
116 return Action::ExchangeEnded {
117 exchange: ExchangeId::new(slot, generation),
118 };
119 }
120 }
121 if let Some(event) = self.events[0].take() {
122 for index in 1..EVENTS {
126 self.events.swap(index - 1, index);
127 }
128 return Action::Registration(event);
129 }
130 if let Some(release) = self.held.take() {
131 return if release {
132 Action::ReleaseHeld
133 } else {
134 Action::DiscardHeld
135 };
136 }
137 match self.register.take() {
138 Some((exchange, to, ttl)) => Action::Register { exchange, to, ttl },
139 None => Action::Idle,
140 }
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use bacnet_time::Instant;
147
148 use super::{Action, Actions, EVENTS, RegistrationEvent};
149
150 const fn renewed(secs: u64) -> RegistrationEvent {
151 RegistrationEvent::Renewed {
152 until: Instant::from_secs(secs),
153 }
154 }
155
156 fn polled(actions: &mut Actions<1>) -> [Option<RegistrationEvent>; EVENTS + 1] {
158 let mut out = [None; EVENTS + 1];
159 for slot in &mut out {
160 match actions.poll() {
161 Action::Registration(event) => *slot = Some(event),
162 Action::Idle => break,
163 other => panic!("{other:?}"),
164 }
165 }
166 out
167 }
168
169 #[test]
170 fn events_are_polled_in_order() {
171 let mut actions = Actions::<1>::new();
172 for secs in 1..=3 {
173 actions.event(renewed(secs));
174 }
175 assert_eq!(
176 polled(&mut actions),
177 [Some(renewed(1)), Some(renewed(2)), Some(renewed(3)), None]
178 );
179 actions.event(RegistrationEvent::Lapsed);
181 actions.event(RegistrationEvent::Unanswered);
182 let next = [RegistrationEvent::Lapsed, RegistrationEvent::Unanswered];
183 assert_eq!(
184 polled(&mut actions),
185 [Some(next[0]), Some(next[1]), None, None]
186 );
187 }
188
189 #[test]
190 fn the_newest_event_replaces_the_last_when_the_list_is_full() {
191 let mut actions = Actions::<1>::new();
192 for secs in 1..=4 {
193 actions.event(renewed(secs));
194 }
195 assert_eq!(
196 polled(&mut actions),
197 [Some(renewed(1)), Some(renewed(2)), Some(renewed(4)), None]
198 );
199 }
200}