1#[cfg(not(feature = "std"))]
11use alloc::{collections::BTreeMap, string::String, string::ToString, vec, vec::Vec};
12#[cfg(feature = "std")]
13use std::collections::BTreeMap;
14
15use crate::NodeId;
16
17pub type Timestamp = u64;
19
20#[derive(Debug, Clone, PartialEq)]
25pub struct LwwRegister<T: Clone> {
26 value: T,
28 timestamp: Timestamp,
30 node_id: NodeId,
32}
33
34impl<T: Clone + Default> Default for LwwRegister<T> {
35 fn default() -> Self {
36 Self {
37 value: T::default(),
38 timestamp: 0,
39 node_id: NodeId::default(),
40 }
41 }
42}
43
44impl<T: Clone> LwwRegister<T> {
45 pub fn new(value: T, timestamp: Timestamp, node_id: NodeId) -> Self {
47 Self {
48 value,
49 timestamp,
50 node_id,
51 }
52 }
53
54 pub fn get(&self) -> &T {
56 &self.value
57 }
58
59 pub fn timestamp(&self) -> Timestamp {
61 self.timestamp
62 }
63
64 pub fn node_id(&self) -> &NodeId {
66 &self.node_id
67 }
68
69 pub fn set(&mut self, value: T, timestamp: Timestamp, node_id: NodeId) -> bool {
73 if self.should_update(timestamp, &node_id) {
74 self.value = value;
75 self.timestamp = timestamp;
76 self.node_id = node_id;
77 true
78 } else {
79 false
80 }
81 }
82
83 pub fn merge(&mut self, other: &LwwRegister<T>) -> bool {
87 if self.should_update(other.timestamp, &other.node_id) {
88 self.value = other.value.clone();
89 self.timestamp = other.timestamp;
90 self.node_id = other.node_id;
91 true
92 } else {
93 false
94 }
95 }
96
97 fn should_update(&self, timestamp: Timestamp, node_id: &NodeId) -> bool {
99 timestamp > self.timestamp
100 || (timestamp == self.timestamp && node_id.as_u32() > self.node_id.as_u32())
101 }
102}
103
104#[derive(Debug, Clone, Default)]
109pub struct GCounter {
110 counts: BTreeMap<u32, u64>,
112}
113
114impl GCounter {
115 pub fn new() -> Self {
117 Self {
118 counts: BTreeMap::new(),
119 }
120 }
121
122 pub fn value(&self) -> u64 {
124 self.counts.values().sum()
125 }
126
127 pub fn increment(&mut self, node_id: &NodeId, amount: u64) {
129 let count = self.counts.entry(node_id.as_u32()).or_insert(0);
130 *count = count.saturating_add(amount);
131 }
132
133 pub fn node_count(&self, node_id: &NodeId) -> u64 {
135 self.counts.get(&node_id.as_u32()).copied().unwrap_or(0)
136 }
137
138 pub fn merge(&mut self, other: &GCounter) {
142 for (&node_id, &count) in &other.counts {
143 let our_count = self.counts.entry(node_id).or_insert(0);
144 *our_count = (*our_count).max(count);
145 }
146 }
147
148 pub fn node_count_total(&self) -> usize {
150 self.counts.len()
151 }
152
153 pub fn encode(&self) -> Vec<u8> {
155 let mut buf = Vec::with_capacity(4 + self.counts.len() * 12);
156 buf.extend_from_slice(&(self.counts.len() as u32).to_le_bytes());
158 for (&node_id, &count) in &self.counts {
160 buf.extend_from_slice(&node_id.to_le_bytes());
161 buf.extend_from_slice(&count.to_le_bytes());
162 }
163 buf
164 }
165
166 pub fn decode(data: &[u8]) -> Option<Self> {
168 if data.len() < 4 {
169 return None;
170 }
171 let num_entries = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
172 if data.len() < 4 + num_entries * 12 {
173 return None;
174 }
175
176 let mut counts = BTreeMap::new();
177 let mut offset = 4;
178 for _ in 0..num_entries {
179 let node_id = u32::from_le_bytes([
180 data[offset],
181 data[offset + 1],
182 data[offset + 2],
183 data[offset + 3],
184 ]);
185 let count = u64::from_le_bytes([
186 data[offset + 4],
187 data[offset + 5],
188 data[offset + 6],
189 data[offset + 7],
190 data[offset + 8],
191 data[offset + 9],
192 data[offset + 10],
193 data[offset + 11],
194 ]);
195 counts.insert(node_id, count);
196 offset += 12;
197 }
198
199 Some(Self { counts })
200 }
201}
202
203#[derive(Debug, Clone, Default, PartialEq)]
205pub struct Position {
206 pub latitude: f32,
208 pub longitude: f32,
210 pub altitude: Option<f32>,
212 pub accuracy: Option<f32>,
214}
215
216impl Position {
217 pub fn new(latitude: f32, longitude: f32) -> Self {
219 Self {
220 latitude,
221 longitude,
222 altitude: None,
223 accuracy: None,
224 }
225 }
226
227 pub fn with_altitude(mut self, altitude: f32) -> Self {
229 self.altitude = Some(altitude);
230 self
231 }
232
233 pub fn with_accuracy(mut self, accuracy: f32) -> Self {
235 self.accuracy = Some(accuracy);
236 self
237 }
238
239 pub fn encode(&self) -> Vec<u8> {
241 let mut buf = Vec::with_capacity(20);
242 buf.extend_from_slice(&self.latitude.to_le_bytes());
243 buf.extend_from_slice(&self.longitude.to_le_bytes());
244
245 let mut flags = 0u8;
247 if self.altitude.is_some() {
248 flags |= 0x01;
249 }
250 if self.accuracy.is_some() {
251 flags |= 0x02;
252 }
253 buf.push(flags);
254
255 if let Some(alt) = self.altitude {
256 buf.extend_from_slice(&alt.to_le_bytes());
257 }
258 if let Some(acc) = self.accuracy {
259 buf.extend_from_slice(&acc.to_le_bytes());
260 }
261 buf
262 }
263
264 pub fn decode(data: &[u8]) -> Option<Self> {
266 if data.len() < 9 {
267 return None;
268 }
269
270 let latitude = f32::from_le_bytes([data[0], data[1], data[2], data[3]]);
271 let longitude = f32::from_le_bytes([data[4], data[5], data[6], data[7]]);
272 let flags = data[8];
273
274 let mut pos = Self::new(latitude, longitude);
275 let mut offset = 9;
276
277 if flags & 0x01 != 0 {
278 if data.len() < offset + 4 {
279 return None;
280 }
281 pos.altitude = Some(f32::from_le_bytes([
282 data[offset],
283 data[offset + 1],
284 data[offset + 2],
285 data[offset + 3],
286 ]));
287 offset += 4;
288 }
289
290 if flags & 0x02 != 0 {
291 if data.len() < offset + 4 {
292 return None;
293 }
294 pos.accuracy = Some(f32::from_le_bytes([
295 data[offset],
296 data[offset + 1],
297 data[offset + 2],
298 data[offset + 3],
299 ]));
300 }
301
302 Some(pos)
303 }
304}
305
306#[derive(Debug, Clone, Default, PartialEq)]
308pub struct HealthStatus {
309 pub battery_percent: u8,
311 pub heart_rate: Option<u8>,
313 pub activity: u8,
315 pub alerts: u8,
317}
318
319impl HealthStatus {
320 pub const ALERT_MAN_DOWN: u8 = 0x01;
322 pub const ALERT_LOW_BATTERY: u8 = 0x02;
324 pub const ALERT_OUT_OF_RANGE: u8 = 0x04;
326 pub const ALERT_CUSTOM_1: u8 = 0x08;
328
329 pub fn new(battery_percent: u8) -> Self {
331 Self {
332 battery_percent,
333 heart_rate: None,
334 activity: 0,
335 alerts: 0,
336 }
337 }
338
339 pub fn with_heart_rate(mut self, hr: u8) -> Self {
341 self.heart_rate = Some(hr);
342 self
343 }
344
345 pub fn with_activity(mut self, activity: u8) -> Self {
347 self.activity = activity;
348 self
349 }
350
351 pub fn set_alert(&mut self, flag: u8) {
353 self.alerts |= flag;
354 }
355
356 pub fn clear_alert(&mut self, flag: u8) {
358 self.alerts &= !flag;
359 }
360
361 pub fn has_alert(&self, flag: u8) -> bool {
363 self.alerts & flag != 0
364 }
365
366 pub fn encode(&self) -> Vec<u8> {
368 vec![
369 self.battery_percent,
370 self.activity,
371 self.alerts,
372 self.heart_rate.unwrap_or(0),
374 ]
375 }
376
377 pub fn decode(data: &[u8]) -> Option<Self> {
379 if data.len() < 4 {
380 return None;
381 }
382 let mut status = Self::new(data[0]);
383 status.activity = data[1];
384 status.alerts = data[2];
385 if data[3] > 0 {
386 status.heart_rate = Some(data[3]);
387 }
388 Some(status)
389 }
390}
391
392#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
398#[repr(u8)]
399pub enum PeripheralType {
400 #[default]
402 Unknown = 0,
403 SoldierSensor = 1,
405 FixedSensor = 2,
407 Relay = 3,
409}
410
411impl PeripheralType {
412 pub fn from_u8(v: u8) -> Self {
414 match v {
415 1 => Self::SoldierSensor,
416 2 => Self::FixedSensor,
417 3 => Self::Relay,
418 _ => Self::Unknown,
419 }
420 }
421}
422
423#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
425#[repr(u8)]
426pub enum EventType {
427 #[default]
429 None = 0,
430 Ping = 1,
432 NeedAssist = 2,
434 Emergency = 3,
436 Moving = 4,
438 InPosition = 5,
440 Ack = 6,
442}
443
444impl EventType {
445 pub fn from_u8(v: u8) -> Self {
447 match v {
448 1 => Self::Ping,
449 2 => Self::NeedAssist,
450 3 => Self::Emergency,
451 4 => Self::Moving,
452 5 => Self::InPosition,
453 6 => Self::Ack,
454 _ => Self::None,
455 }
456 }
457
458 pub fn label(&self) -> &'static str {
460 match self {
461 Self::None => "",
462 Self::Ping => "PING",
463 Self::NeedAssist => "NEED ASSIST",
464 Self::Emergency => "EMERGENCY",
465 Self::Moving => "MOVING",
466 Self::InPosition => "IN POSITION",
467 Self::Ack => "ACK",
468 }
469 }
470}
471
472#[derive(Debug, Clone, Default, PartialEq)]
474pub struct PeripheralEvent {
475 pub event_type: EventType,
477 pub timestamp: u64,
479}
480
481impl PeripheralEvent {
482 pub fn new(event_type: EventType, timestamp: u64) -> Self {
484 Self {
485 event_type,
486 timestamp,
487 }
488 }
489
490 pub fn encode(&self) -> Vec<u8> {
492 let mut buf = Vec::with_capacity(9);
493 buf.push(self.event_type as u8);
494 buf.extend_from_slice(&self.timestamp.to_le_bytes());
495 buf
496 }
497
498 pub fn decode(data: &[u8]) -> Option<Self> {
500 if data.len() < 9 {
501 return None;
502 }
503 Some(Self {
504 event_type: EventType::from_u8(data[0]),
505 timestamp: u64::from_le_bytes([
506 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
507 ]),
508 })
509 }
510}
511
512#[derive(Debug, Clone, PartialEq, Default)]
536pub struct EmergencyEvent {
537 source_node: u32,
539 timestamp: u64,
541 acks: BTreeMap<u32, bool>,
543}
544
545impl EmergencyEvent {
546 pub fn new(source_node: u32, timestamp: u64, known_peers: &[u32]) -> Self {
555 let mut acks = BTreeMap::new();
556
557 acks.insert(source_node, true);
559
560 for &peer_id in known_peers {
562 if peer_id != source_node {
563 acks.entry(peer_id).or_insert(false);
564 }
565 }
566
567 Self {
568 source_node,
569 timestamp,
570 acks,
571 }
572 }
573
574 pub fn source_node(&self) -> u32 {
576 self.source_node
577 }
578
579 pub fn timestamp(&self) -> u64 {
581 self.timestamp
582 }
583
584 pub fn has_acked(&self, node_id: u32) -> bool {
586 self.acks.get(&node_id).copied().unwrap_or(false)
587 }
588
589 pub fn ack(&mut self, node_id: u32) -> bool {
593 let entry = self.acks.entry(node_id).or_insert(false);
594 if !*entry {
595 *entry = true;
596 true
597 } else {
598 false
599 }
600 }
601
602 pub fn add_peer(&mut self, node_id: u32) {
607 self.acks.entry(node_id).or_insert(false);
608 }
609
610 pub fn acked_nodes(&self) -> Vec<u32> {
612 self.acks
613 .iter()
614 .filter(|(_, &acked)| acked)
615 .map(|(&node_id, _)| node_id)
616 .collect()
617 }
618
619 pub fn pending_nodes(&self) -> Vec<u32> {
621 self.acks
622 .iter()
623 .filter(|(_, &acked)| !acked)
624 .map(|(&node_id, _)| node_id)
625 .collect()
626 }
627
628 pub fn all_acked(&self) -> bool {
630 !self.acks.is_empty() && self.acks.values().all(|&acked| acked)
631 }
632
633 pub fn peer_count(&self) -> usize {
635 self.acks.len()
636 }
637
638 pub fn ack_count(&self) -> usize {
640 self.acks.values().filter(|&&acked| acked).count()
641 }
642
643 pub fn merge(&mut self, other: &EmergencyEvent) -> bool {
652 if self.source_node != other.source_node || self.timestamp != other.timestamp {
654 if other.timestamp > self.timestamp {
655 *self = other.clone();
656 return true;
657 }
658 return false;
659 }
660
661 let mut changed = false;
663 for (&node_id, &other_acked) in &other.acks {
664 let entry = self.acks.entry(node_id).or_insert(false);
665 if other_acked && !*entry {
666 *entry = true;
667 changed = true;
668 }
669 }
670 changed
671 }
672
673 pub fn encode(&self) -> Vec<u8> {
677 let mut buf = Vec::with_capacity(16 + self.acks.len() * 5);
678
679 buf.extend_from_slice(&self.source_node.to_le_bytes());
680 buf.extend_from_slice(&self.timestamp.to_le_bytes());
681 buf.extend_from_slice(&(self.acks.len() as u32).to_le_bytes());
682
683 for (&node_id, &acked) in &self.acks {
684 buf.extend_from_slice(&node_id.to_le_bytes());
685 buf.push(if acked { 1 } else { 0 });
686 }
687
688 buf
689 }
690
691 pub fn decode(data: &[u8]) -> Option<Self> {
693 if data.len() < 16 {
694 return None;
695 }
696
697 let source_node = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
698 let timestamp = u64::from_le_bytes([
699 data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11],
700 ]);
701 let num_acks = u32::from_le_bytes([data[12], data[13], data[14], data[15]]) as usize;
702
703 if data.len() < 16 + num_acks * 5 {
704 return None;
705 }
706
707 let mut acks = BTreeMap::new();
708 let mut offset = 16;
709 for _ in 0..num_acks {
710 let node_id = u32::from_le_bytes([
711 data[offset],
712 data[offset + 1],
713 data[offset + 2],
714 data[offset + 3],
715 ]);
716 let acked = data[offset + 4] != 0;
717 acks.insert(node_id, acked);
718 offset += 5;
719 }
720
721 Some(Self {
722 source_node,
723 timestamp,
724 acks,
725 })
726 }
727}
728
729#[derive(Debug, Clone, Default)]
734pub struct Peripheral {
735 pub id: u32,
737 pub parent_node: u32,
739 pub peripheral_type: PeripheralType,
741 pub callsign: [u8; 12],
743 pub health: HealthStatus,
745 pub last_event: Option<PeripheralEvent>,
747 pub timestamp: u64,
749}
750
751impl Peripheral {
752 pub fn new(id: u32, peripheral_type: PeripheralType) -> Self {
754 Self {
755 id,
756 parent_node: 0,
757 peripheral_type,
758 callsign: [0u8; 12],
759 health: HealthStatus::default(),
760 last_event: None,
761 timestamp: 0,
762 }
763 }
764
765 pub fn with_callsign(mut self, callsign: &str) -> Self {
767 let bytes = callsign.as_bytes();
768 let len = bytes.len().min(12);
769 self.callsign[..len].copy_from_slice(&bytes[..len]);
770 self
771 }
772
773 pub fn callsign_str(&self) -> &str {
775 let len = self.callsign.iter().position(|&b| b == 0).unwrap_or(12);
776 core::str::from_utf8(&self.callsign[..len]).unwrap_or("")
777 }
778
779 pub fn with_parent(mut self, parent_node: u32) -> Self {
781 self.parent_node = parent_node;
782 self
783 }
784
785 pub fn set_event(&mut self, event_type: EventType, timestamp: u64) {
787 self.last_event = Some(PeripheralEvent::new(event_type, timestamp));
788 self.timestamp = timestamp;
789 }
790
791 pub fn clear_event(&mut self) {
793 self.last_event = None;
794 }
795
796 pub fn encode(&self) -> Vec<u8> {
800 let mut buf = Vec::with_capacity(43);
801 buf.extend_from_slice(&self.id.to_le_bytes());
802 buf.extend_from_slice(&self.parent_node.to_le_bytes());
803 buf.push(self.peripheral_type as u8);
804 buf.extend_from_slice(&self.callsign);
805 buf.extend_from_slice(&self.health.encode());
806
807 if let Some(ref event) = self.last_event {
808 buf.push(1); buf.extend_from_slice(&event.encode());
810 } else {
811 buf.push(0); }
813
814 buf.extend_from_slice(&self.timestamp.to_le_bytes());
815 buf
816 }
817
818 pub fn decode(data: &[u8]) -> Option<Self> {
820 if data.len() < 34 {
821 return None;
822 }
823
824 let id = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
825 let parent_node = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
826 let peripheral_type = PeripheralType::from_u8(data[8]);
827
828 let mut callsign = [0u8; 12];
829 callsign.copy_from_slice(&data[9..21]);
830
831 let health = HealthStatus::decode(&data[21..25])?;
832
833 let has_event = data[25] != 0;
834 let (last_event, timestamp_offset) = if has_event {
835 if data.len() < 43 {
836 return None;
837 }
838 (PeripheralEvent::decode(&data[26..35]), 35)
839 } else {
840 (None, 26)
841 };
842
843 if data.len() < timestamp_offset + 8 {
844 return None;
845 }
846
847 let timestamp = u64::from_le_bytes([
848 data[timestamp_offset],
849 data[timestamp_offset + 1],
850 data[timestamp_offset + 2],
851 data[timestamp_offset + 3],
852 data[timestamp_offset + 4],
853 data[timestamp_offset + 5],
854 data[timestamp_offset + 6],
855 data[timestamp_offset + 7],
856 ]);
857
858 Some(Self {
859 id,
860 parent_node,
861 peripheral_type,
862 callsign,
863 health,
864 last_event,
865 timestamp,
866 })
867 }
868}
869
870#[derive(Debug, Clone)]
872pub enum CrdtOperation {
873 UpdatePosition {
875 node_id: NodeId,
877 position: Position,
879 timestamp: Timestamp,
881 },
882 UpdateHealth {
884 node_id: NodeId,
886 status: HealthStatus,
888 timestamp: Timestamp,
890 },
891 IncrementCounter {
893 counter_id: u8,
895 node_id: NodeId,
897 amount: u64,
899 },
900 UpdateRegister {
902 key: String,
904 value: Vec<u8>,
906 timestamp: Timestamp,
908 node_id: NodeId,
910 },
911}
912
913impl CrdtOperation {
914 pub fn size(&self) -> usize {
916 match self {
917 CrdtOperation::UpdatePosition { position, .. } => 4 + 8 + position.encode().len(),
918 CrdtOperation::UpdateHealth { status, .. } => 4 + 8 + status.encode().len(),
919 CrdtOperation::IncrementCounter { .. } => 1 + 4 + 8,
920 CrdtOperation::UpdateRegister { key, value, .. } => 4 + 8 + key.len() + value.len(),
921 }
922 }
923
924 pub fn encode(&self) -> Vec<u8> {
926 let mut buf = Vec::new();
927 match self {
928 CrdtOperation::UpdatePosition {
929 node_id,
930 position,
931 timestamp,
932 } => {
933 buf.push(0x01); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
935 buf.extend_from_slice(×tamp.to_le_bytes());
936 buf.extend_from_slice(&position.encode());
937 }
938 CrdtOperation::UpdateHealth {
939 node_id,
940 status,
941 timestamp,
942 } => {
943 buf.push(0x02); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
945 buf.extend_from_slice(×tamp.to_le_bytes());
946 buf.extend_from_slice(&status.encode());
947 }
948 CrdtOperation::IncrementCounter {
949 counter_id,
950 node_id,
951 amount,
952 } => {
953 buf.push(0x03); buf.push(*counter_id);
955 buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
956 buf.extend_from_slice(&amount.to_le_bytes());
957 }
958 CrdtOperation::UpdateRegister {
959 key,
960 value,
961 timestamp,
962 node_id,
963 } => {
964 buf.push(0x04); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
966 buf.extend_from_slice(×tamp.to_le_bytes());
967 buf.push(key.len() as u8);
968 buf.extend_from_slice(key.as_bytes());
969 buf.extend_from_slice(&(value.len() as u16).to_le_bytes());
970 buf.extend_from_slice(value);
971 }
972 }
973 buf
974 }
975
976 pub fn decode(data: &[u8]) -> Option<Self> {
978 if data.is_empty() {
979 return None;
980 }
981
982 match data[0] {
983 0x01 => {
984 if data.len() < 13 {
986 return None;
987 }
988 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
989 let timestamp = u64::from_le_bytes([
990 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
991 ]);
992 let position = Position::decode(&data[13..])?;
993 Some(CrdtOperation::UpdatePosition {
994 node_id,
995 position,
996 timestamp,
997 })
998 }
999 0x02 => {
1000 if data.len() < 13 {
1002 return None;
1003 }
1004 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1005 let timestamp = u64::from_le_bytes([
1006 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1007 ]);
1008 let status = HealthStatus::decode(&data[13..])?;
1009 Some(CrdtOperation::UpdateHealth {
1010 node_id,
1011 status,
1012 timestamp,
1013 })
1014 }
1015 0x03 => {
1016 if data.len() < 14 {
1018 return None;
1019 }
1020 let counter_id = data[1];
1021 let node_id = NodeId::new(u32::from_le_bytes([data[2], data[3], data[4], data[5]]));
1022 let amount = u64::from_le_bytes([
1023 data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13],
1024 ]);
1025 Some(CrdtOperation::IncrementCounter {
1026 counter_id,
1027 node_id,
1028 amount,
1029 })
1030 }
1031 0x04 => {
1032 if data.len() < 14 {
1034 return None;
1035 }
1036 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1037 let timestamp = u64::from_le_bytes([
1038 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1039 ]);
1040 let key_len = data[13] as usize;
1041 if data.len() < 14 + key_len + 2 {
1042 return None;
1043 }
1044 let key = core::str::from_utf8(&data[14..14 + key_len])
1045 .ok()?
1046 .to_string();
1047 let value_len =
1048 u16::from_le_bytes([data[14 + key_len], data[15 + key_len]]) as usize;
1049 if data.len() < 16 + key_len + value_len {
1050 return None;
1051 }
1052 let value = data[16 + key_len..16 + key_len + value_len].to_vec();
1053 Some(CrdtOperation::UpdateRegister {
1054 key,
1055 value,
1056 timestamp,
1057 node_id,
1058 })
1059 }
1060 _ => None,
1061 }
1062 }
1063}
1064
1065#[cfg(test)]
1066mod tests {
1067 use super::*;
1068
1069 #[test]
1070 fn test_lww_register_basic() {
1071 let mut reg = LwwRegister::new(42u32, 100, NodeId::new(1));
1072 assert_eq!(*reg.get(), 42);
1073 assert_eq!(reg.timestamp(), 100);
1074
1075 assert!(reg.set(99, 200, NodeId::new(2)));
1077 assert_eq!(*reg.get(), 99);
1078
1079 assert!(!reg.set(50, 150, NodeId::new(3)));
1081 assert_eq!(*reg.get(), 99);
1082 }
1083
1084 #[test]
1085 fn test_lww_register_tiebreak() {
1086 let mut reg = LwwRegister::new(1u32, 100, NodeId::new(1));
1087
1088 assert!(reg.set(2, 100, NodeId::new(2)));
1090 assert_eq!(*reg.get(), 2);
1091
1092 assert!(!reg.set(3, 100, NodeId::new(1)));
1094 assert_eq!(*reg.get(), 2);
1095 }
1096
1097 #[test]
1098 fn test_lww_register_merge() {
1099 let mut reg1 = LwwRegister::new(1u32, 100, NodeId::new(1));
1100 let reg2 = LwwRegister::new(2u32, 200, NodeId::new(2));
1101
1102 assert!(reg1.merge(®2));
1103 assert_eq!(*reg1.get(), 2);
1104 }
1105
1106 #[test]
1107 fn test_gcounter_basic() {
1108 let mut counter = GCounter::new();
1109 let node1 = NodeId::new(1);
1110 let node2 = NodeId::new(2);
1111
1112 counter.increment(&node1, 5);
1113 counter.increment(&node2, 3);
1114 counter.increment(&node1, 2);
1115
1116 assert_eq!(counter.value(), 10);
1117 assert_eq!(counter.node_count(&node1), 7);
1118 assert_eq!(counter.node_count(&node2), 3);
1119 }
1120
1121 #[test]
1122 fn test_gcounter_merge() {
1123 let mut counter1 = GCounter::new();
1124 let mut counter2 = GCounter::new();
1125 let node1 = NodeId::new(1);
1126 let node2 = NodeId::new(2);
1127
1128 counter1.increment(&node1, 5);
1129 counter2.increment(&node1, 3);
1130 counter2.increment(&node2, 4);
1131
1132 counter1.merge(&counter2);
1133
1134 assert_eq!(counter1.value(), 9); assert_eq!(counter1.node_count(&node1), 5);
1136 assert_eq!(counter1.node_count(&node2), 4);
1137 }
1138
1139 #[test]
1140 fn test_gcounter_encode_decode() {
1141 let mut counter = GCounter::new();
1142 counter.increment(&NodeId::new(1), 5);
1143 counter.increment(&NodeId::new(2), 10);
1144
1145 let encoded = counter.encode();
1146 let decoded = GCounter::decode(&encoded).unwrap();
1147
1148 assert_eq!(decoded.value(), counter.value());
1149 assert_eq!(decoded.node_count(&NodeId::new(1)), 5);
1150 assert_eq!(decoded.node_count(&NodeId::new(2)), 10);
1151 }
1152
1153 #[test]
1154 fn test_position_encode_decode() {
1155 let pos = Position::new(37.7749, -122.4194)
1156 .with_altitude(100.0)
1157 .with_accuracy(5.0);
1158
1159 let encoded = pos.encode();
1160 let decoded = Position::decode(&encoded).unwrap();
1161
1162 assert_eq!(decoded.latitude, pos.latitude);
1163 assert_eq!(decoded.longitude, pos.longitude);
1164 assert_eq!(decoded.altitude, pos.altitude);
1165 assert_eq!(decoded.accuracy, pos.accuracy);
1166 }
1167
1168 #[test]
1169 fn test_position_minimal_encode() {
1170 let pos = Position::new(0.0, 0.0);
1171 let encoded = pos.encode();
1172 assert_eq!(encoded.len(), 9); let pos_with_alt = Position::new(0.0, 0.0).with_altitude(0.0);
1175 let encoded_alt = pos_with_alt.encode();
1176 assert_eq!(encoded_alt.len(), 13);
1177 }
1178
1179 #[test]
1180 fn test_health_status() {
1181 let mut status = HealthStatus::new(85).with_heart_rate(72).with_activity(1);
1182
1183 assert_eq!(status.battery_percent, 85);
1184 assert_eq!(status.heart_rate, Some(72));
1185 assert!(!status.has_alert(HealthStatus::ALERT_MAN_DOWN));
1186
1187 status.set_alert(HealthStatus::ALERT_MAN_DOWN);
1188 assert!(status.has_alert(HealthStatus::ALERT_MAN_DOWN));
1189
1190 let encoded = status.encode();
1191 let decoded = HealthStatus::decode(&encoded).unwrap();
1192 assert_eq!(decoded.battery_percent, 85);
1193 assert_eq!(decoded.heart_rate, Some(72));
1194 assert!(decoded.has_alert(HealthStatus::ALERT_MAN_DOWN));
1195 }
1196
1197 #[test]
1198 fn test_crdt_operation_position() {
1199 let op = CrdtOperation::UpdatePosition {
1200 node_id: NodeId::new(0x1234),
1201 position: Position::new(37.0, -122.0),
1202 timestamp: 1000,
1203 };
1204
1205 let encoded = op.encode();
1206 let decoded = CrdtOperation::decode(&encoded).unwrap();
1207
1208 if let CrdtOperation::UpdatePosition {
1209 node_id,
1210 position,
1211 timestamp,
1212 } = decoded
1213 {
1214 assert_eq!(node_id.as_u32(), 0x1234);
1215 assert_eq!(timestamp, 1000);
1216 assert_eq!(position.latitude, 37.0);
1217 } else {
1218 panic!("Wrong operation type");
1219 }
1220 }
1221
1222 #[test]
1223 fn test_crdt_operation_counter() {
1224 let op = CrdtOperation::IncrementCounter {
1225 counter_id: 1,
1226 node_id: NodeId::new(0x5678),
1227 amount: 42,
1228 };
1229
1230 let encoded = op.encode();
1231 let decoded = CrdtOperation::decode(&encoded).unwrap();
1232
1233 if let CrdtOperation::IncrementCounter {
1234 counter_id,
1235 node_id,
1236 amount,
1237 } = decoded
1238 {
1239 assert_eq!(counter_id, 1);
1240 assert_eq!(node_id.as_u32(), 0x5678);
1241 assert_eq!(amount, 42);
1242 } else {
1243 panic!("Wrong operation type");
1244 }
1245 }
1246
1247 #[test]
1248 fn test_crdt_operation_size() {
1249 let pos_op = CrdtOperation::UpdatePosition {
1250 node_id: NodeId::new(1),
1251 position: Position::new(0.0, 0.0),
1252 timestamp: 0,
1253 };
1254 assert!(pos_op.size() > 0);
1255
1256 let counter_op = CrdtOperation::IncrementCounter {
1257 counter_id: 0,
1258 node_id: NodeId::new(1),
1259 amount: 1,
1260 };
1261 assert_eq!(counter_op.size(), 13);
1262 }
1263
1264 #[test]
1269 fn test_peripheral_type_from_u8() {
1270 assert_eq!(PeripheralType::from_u8(0), PeripheralType::Unknown);
1271 assert_eq!(PeripheralType::from_u8(1), PeripheralType::SoldierSensor);
1272 assert_eq!(PeripheralType::from_u8(2), PeripheralType::FixedSensor);
1273 assert_eq!(PeripheralType::from_u8(3), PeripheralType::Relay);
1274 assert_eq!(PeripheralType::from_u8(99), PeripheralType::Unknown);
1275 }
1276
1277 #[test]
1278 fn test_event_type_from_u8() {
1279 assert_eq!(EventType::from_u8(0), EventType::None);
1280 assert_eq!(EventType::from_u8(1), EventType::Ping);
1281 assert_eq!(EventType::from_u8(2), EventType::NeedAssist);
1282 assert_eq!(EventType::from_u8(3), EventType::Emergency);
1283 assert_eq!(EventType::from_u8(4), EventType::Moving);
1284 assert_eq!(EventType::from_u8(5), EventType::InPosition);
1285 assert_eq!(EventType::from_u8(6), EventType::Ack);
1286 assert_eq!(EventType::from_u8(99), EventType::None);
1287 }
1288
1289 #[test]
1290 fn test_event_type_labels() {
1291 assert_eq!(EventType::None.label(), "");
1292 assert_eq!(EventType::Emergency.label(), "EMERGENCY");
1293 assert_eq!(EventType::Ping.label(), "PING");
1294 }
1295
1296 #[test]
1297 fn test_peripheral_event_encode_decode() {
1298 let event = PeripheralEvent::new(EventType::Emergency, 1234567890);
1299 let encoded = event.encode();
1300 assert_eq!(encoded.len(), 9);
1301
1302 let decoded = PeripheralEvent::decode(&encoded).unwrap();
1303 assert_eq!(decoded.event_type, EventType::Emergency);
1304 assert_eq!(decoded.timestamp, 1234567890);
1305 }
1306
1307 #[test]
1308 fn test_peripheral_new() {
1309 let peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor);
1310 assert_eq!(peripheral.id, 0x12345678);
1311 assert_eq!(peripheral.peripheral_type, PeripheralType::SoldierSensor);
1312 assert_eq!(peripheral.parent_node, 0);
1313 assert!(peripheral.last_event.is_none());
1314 }
1315
1316 #[test]
1317 fn test_peripheral_with_callsign() {
1318 let peripheral = Peripheral::new(1, PeripheralType::SoldierSensor).with_callsign("ALPHA-1");
1319 assert_eq!(peripheral.callsign_str(), "ALPHA-1");
1320
1321 let peripheral2 = Peripheral::new(2, PeripheralType::SoldierSensor)
1323 .with_callsign("THIS_IS_A_VERY_LONG_CALLSIGN");
1324 assert_eq!(peripheral2.callsign_str(), "THIS_IS_A_VE");
1325 }
1326
1327 #[test]
1328 fn test_peripheral_set_event() {
1329 let mut peripheral = Peripheral::new(1, PeripheralType::SoldierSensor);
1330 peripheral.set_event(EventType::Emergency, 1000);
1331
1332 assert!(peripheral.last_event.is_some());
1333 let event = peripheral.last_event.as_ref().unwrap();
1334 assert_eq!(event.event_type, EventType::Emergency);
1335 assert_eq!(event.timestamp, 1000);
1336 assert_eq!(peripheral.timestamp, 1000);
1337
1338 peripheral.clear_event();
1339 assert!(peripheral.last_event.is_none());
1340 }
1341
1342 #[test]
1343 fn test_peripheral_encode_decode_without_event() {
1344 let peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor)
1345 .with_callsign("BRAVO-2")
1346 .with_parent(0x11223344);
1347
1348 let encoded = peripheral.encode();
1349 assert_eq!(encoded.len(), 34); let decoded = Peripheral::decode(&encoded).unwrap();
1352 assert_eq!(decoded.id, 0xAABBCCDD);
1353 assert_eq!(decoded.parent_node, 0x11223344);
1354 assert_eq!(decoded.peripheral_type, PeripheralType::SoldierSensor);
1355 assert_eq!(decoded.callsign_str(), "BRAVO-2");
1356 assert!(decoded.last_event.is_none());
1357 }
1358
1359 #[test]
1360 fn test_peripheral_encode_decode_with_event() {
1361 let mut peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor)
1362 .with_callsign("CHARLIE")
1363 .with_parent(0x87654321);
1364 peripheral.health = HealthStatus::new(85);
1365 peripheral.set_event(EventType::NeedAssist, 9999);
1366
1367 let encoded = peripheral.encode();
1368 assert_eq!(encoded.len(), 43); let decoded = Peripheral::decode(&encoded).unwrap();
1371 assert_eq!(decoded.id, 0x12345678);
1372 assert_eq!(decoded.parent_node, 0x87654321);
1373 assert_eq!(decoded.callsign_str(), "CHARLIE");
1374 assert_eq!(decoded.health.battery_percent, 85);
1375 assert!(decoded.last_event.is_some());
1376 let event = decoded.last_event.as_ref().unwrap();
1377 assert_eq!(event.event_type, EventType::NeedAssist);
1378 assert_eq!(event.timestamp, 9999);
1379 }
1380
1381 #[test]
1382 fn test_peripheral_decode_invalid_data() {
1383 assert!(Peripheral::decode(&[0u8; 10]).is_none());
1385
1386 let mut data = vec![0u8; 34];
1388 data[25] = 0; assert!(Peripheral::decode(&data).is_some());
1390
1391 data[25] = 1; assert!(Peripheral::decode(&data).is_none());
1394 }
1395
1396 #[test]
1401 fn test_emergency_event_new() {
1402 let peers = vec![0x22222222, 0x33333333];
1403 let event = EmergencyEvent::new(0x11111111, 1000, &peers);
1404
1405 assert_eq!(event.source_node(), 0x11111111);
1406 assert_eq!(event.timestamp(), 1000);
1407 assert_eq!(event.peer_count(), 3); assert!(event.has_acked(0x11111111));
1411 assert!(!event.has_acked(0x22222222));
1413 assert!(!event.has_acked(0x33333333));
1414 }
1415
1416 #[test]
1417 fn test_emergency_event_ack() {
1418 let peers = vec![0x22222222, 0x33333333];
1419 let mut event = EmergencyEvent::new(0x11111111, 1000, &peers);
1420
1421 assert_eq!(event.ack_count(), 1); assert!(!event.all_acked());
1423
1424 assert!(event.ack(0x22222222)); assert_eq!(event.ack_count(), 2);
1427 assert!(!event.all_acked());
1428
1429 assert!(!event.ack(0x22222222)); assert!(event.ack(0x33333333));
1434 assert_eq!(event.ack_count(), 3);
1435 assert!(event.all_acked());
1436 }
1437
1438 #[test]
1439 fn test_emergency_event_pending_nodes() {
1440 let peers = vec![0x22222222, 0x33333333];
1441 let mut event = EmergencyEvent::new(0x11111111, 1000, &peers);
1442
1443 let pending = event.pending_nodes();
1444 assert_eq!(pending.len(), 2);
1445 assert!(pending.contains(&0x22222222));
1446 assert!(pending.contains(&0x33333333));
1447
1448 event.ack(0x22222222);
1449 let pending = event.pending_nodes();
1450 assert_eq!(pending.len(), 1);
1451 assert!(pending.contains(&0x33333333));
1452 }
1453
1454 #[test]
1455 fn test_emergency_event_encode_decode() {
1456 let peers = vec![0x22222222, 0x33333333];
1457 let mut event = EmergencyEvent::new(0x11111111, 1234567890, &peers);
1458 event.ack(0x22222222);
1459
1460 let encoded = event.encode();
1461 let decoded = EmergencyEvent::decode(&encoded).unwrap();
1462
1463 assert_eq!(decoded.source_node(), 0x11111111);
1464 assert_eq!(decoded.timestamp(), 1234567890);
1465 assert!(decoded.has_acked(0x11111111));
1466 assert!(decoded.has_acked(0x22222222));
1467 assert!(!decoded.has_acked(0x33333333));
1468 }
1469
1470 #[test]
1471 fn test_emergency_event_merge_same_event() {
1472 let peers = vec![0x22222222, 0x33333333];
1474 let mut event1 = EmergencyEvent::new(0x11111111, 1000, &peers);
1475 let mut event2 = EmergencyEvent::new(0x11111111, 1000, &peers);
1476
1477 event1.ack(0x22222222);
1478 event2.ack(0x33333333);
1479
1480 let changed = event1.merge(&event2);
1482 assert!(changed);
1483 assert!(event1.has_acked(0x22222222));
1484 assert!(event1.has_acked(0x33333333));
1485 assert!(event1.all_acked());
1486 }
1487
1488 #[test]
1489 fn test_emergency_event_merge_different_events() {
1490 let mut old_event = EmergencyEvent::new(0x11111111, 1000, &[0x22222222]);
1492 old_event.ack(0x22222222);
1493
1494 let new_event = EmergencyEvent::new(0x33333333, 2000, &[0x11111111, 0x22222222]);
1496
1497 let changed = old_event.merge(&new_event);
1499 assert!(changed);
1500 assert_eq!(old_event.source_node(), 0x33333333);
1501 assert_eq!(old_event.timestamp(), 2000);
1502 assert!(!old_event.has_acked(0x22222222));
1504 }
1505
1506 #[test]
1507 fn test_emergency_event_merge_older_event_ignored() {
1508 let mut current = EmergencyEvent::new(0x11111111, 2000, &[0x22222222]);
1510
1511 let older = EmergencyEvent::new(0x33333333, 1000, &[0x11111111]);
1513
1514 let changed = current.merge(&older);
1516 assert!(!changed);
1517 assert_eq!(current.source_node(), 0x11111111);
1518 assert_eq!(current.timestamp(), 2000);
1519 }
1520
1521 #[test]
1522 fn test_emergency_event_add_peer() {
1523 let mut event = EmergencyEvent::new(0x11111111, 1000, &[]);
1524
1525 event.add_peer(0x22222222);
1527 assert!(!event.has_acked(0x22222222));
1528 assert_eq!(event.peer_count(), 2);
1529
1530 event.ack(0x22222222);
1532 event.add_peer(0x22222222);
1533 assert!(event.has_acked(0x22222222)); }
1535
1536 #[test]
1537 fn test_emergency_event_decode_invalid() {
1538 assert!(EmergencyEvent::decode(&[0u8; 10]).is_none());
1540
1541 let mut data = vec![0u8; 16];
1543 data[12] = 5; assert!(EmergencyEvent::decode(&data).is_none());
1545 }
1546}