1#[cfg(not(feature = "std"))]
26use alloc::{collections::BTreeMap, string::String, string::ToString, vec, vec::Vec};
27#[cfg(feature = "std")]
28use std::collections::BTreeMap;
29
30use crate::NodeId;
31
32pub const MIN_VALID_TIMESTAMP: u64 = 1577836800000;
41
42pub const MAX_BATTERY_PERCENT: u8 = 100;
44
45pub const MIN_HEART_RATE: u8 = 20;
47
48pub const MAX_HEART_RATE: u8 = 250;
50
51pub const MAX_EMERGENCY_ACKS: usize = 256;
53
54pub const MAX_COUNTER_ENTRIES: usize = 256;
56
57pub type Timestamp = u64;
59
60#[derive(Debug, Clone, PartialEq)]
65pub struct LwwRegister<T: Clone> {
66 value: T,
68 timestamp: Timestamp,
70 node_id: NodeId,
72}
73
74impl<T: Clone + Default> Default for LwwRegister<T> {
75 fn default() -> Self {
76 Self {
77 value: T::default(),
78 timestamp: 0,
79 node_id: NodeId::default(),
80 }
81 }
82}
83
84impl<T: Clone> LwwRegister<T> {
85 pub fn new(value: T, timestamp: Timestamp, node_id: NodeId) -> Self {
87 Self {
88 value,
89 timestamp,
90 node_id,
91 }
92 }
93
94 pub fn get(&self) -> &T {
96 &self.value
97 }
98
99 pub fn timestamp(&self) -> Timestamp {
101 self.timestamp
102 }
103
104 pub fn node_id(&self) -> &NodeId {
106 &self.node_id
107 }
108
109 pub fn set(&mut self, value: T, timestamp: Timestamp, node_id: NodeId) -> bool {
113 if self.should_update(timestamp, &node_id) {
114 self.value = value;
115 self.timestamp = timestamp;
116 self.node_id = node_id;
117 true
118 } else {
119 false
120 }
121 }
122
123 pub fn merge(&mut self, other: &LwwRegister<T>) -> bool {
127 if self.should_update(other.timestamp, &other.node_id) {
128 self.value = other.value.clone();
129 self.timestamp = other.timestamp;
130 self.node_id = other.node_id;
131 true
132 } else {
133 false
134 }
135 }
136
137 fn should_update(&self, timestamp: Timestamp, node_id: &NodeId) -> bool {
139 timestamp > self.timestamp
140 || (timestamp == self.timestamp && node_id.as_u32() > self.node_id.as_u32())
141 }
142}
143
144#[derive(Debug, Clone, Default)]
149pub struct GCounter {
150 counts: BTreeMap<u32, u64>,
152}
153
154impl GCounter {
155 pub fn new() -> Self {
157 Self {
158 counts: BTreeMap::new(),
159 }
160 }
161
162 pub fn value(&self) -> u64 {
164 self.counts.values().sum()
165 }
166
167 pub fn increment(&mut self, node_id: &NodeId, amount: u64) {
169 let count = self.counts.entry(node_id.as_u32()).or_insert(0);
170 *count = count.saturating_add(amount);
171 }
172
173 pub fn node_count(&self, node_id: &NodeId) -> u64 {
175 self.counts.get(&node_id.as_u32()).copied().unwrap_or(0)
176 }
177
178 pub fn merge(&mut self, other: &GCounter) {
182 for (&node_id, &count) in &other.counts {
183 let our_count = self.counts.entry(node_id).or_insert(0);
184 *our_count = (*our_count).max(count);
185 }
186 }
187
188 pub fn node_count_total(&self) -> usize {
190 self.counts.len()
191 }
192
193 pub fn entries(&self) -> impl Iterator<Item = (u32, u64)> + '_ {
198 self.counts.iter().map(|(&k, &v)| (k, v))
199 }
200
201 pub fn encode(&self) -> Vec<u8> {
203 let mut buf = Vec::with_capacity(4 + self.counts.len() * 12);
204 buf.extend_from_slice(&(self.counts.len() as u32).to_le_bytes());
206 for (&node_id, &count) in &self.counts {
208 buf.extend_from_slice(&node_id.to_le_bytes());
209 buf.extend_from_slice(&count.to_le_bytes());
210 }
211 buf
212 }
213
214 pub fn decode(data: &[u8]) -> Option<Self> {
220 if data.len() < 4 {
221 return None;
222 }
223 let num_entries = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
224
225 if num_entries > MAX_COUNTER_ENTRIES {
227 return None;
228 }
229
230 if data.len() < 4 + num_entries * 12 {
231 return None;
232 }
233
234 let mut counts = BTreeMap::new();
235 let mut offset = 4;
236 for _ in 0..num_entries {
237 let node_id = u32::from_le_bytes([
238 data[offset],
239 data[offset + 1],
240 data[offset + 2],
241 data[offset + 3],
242 ]);
243 let count = u64::from_le_bytes([
244 data[offset + 4],
245 data[offset + 5],
246 data[offset + 6],
247 data[offset + 7],
248 data[offset + 8],
249 data[offset + 9],
250 data[offset + 10],
251 data[offset + 11],
252 ]);
253 if node_id != 0 {
255 counts.insert(node_id, count);
256 }
257 offset += 12;
258 }
259
260 Some(Self { counts })
261 }
262}
263
264#[derive(Debug, Clone, Default, PartialEq)]
266pub struct Position {
267 pub latitude: f32,
269 pub longitude: f32,
271 pub altitude: Option<f32>,
273 pub accuracy: Option<f32>,
275}
276
277impl Position {
278 pub fn new(latitude: f32, longitude: f32) -> Self {
280 Self {
281 latitude,
282 longitude,
283 altitude: None,
284 accuracy: None,
285 }
286 }
287
288 pub fn with_altitude(mut self, altitude: f32) -> Self {
290 self.altitude = Some(altitude);
291 self
292 }
293
294 pub fn with_accuracy(mut self, accuracy: f32) -> Self {
296 self.accuracy = Some(accuracy);
297 self
298 }
299
300 pub fn encode(&self) -> Vec<u8> {
302 let mut buf = Vec::with_capacity(20);
303 buf.extend_from_slice(&self.latitude.to_le_bytes());
304 buf.extend_from_slice(&self.longitude.to_le_bytes());
305
306 let mut flags = 0u8;
308 if self.altitude.is_some() {
309 flags |= 0x01;
310 }
311 if self.accuracy.is_some() {
312 flags |= 0x02;
313 }
314 buf.push(flags);
315
316 if let Some(alt) = self.altitude {
317 buf.extend_from_slice(&alt.to_le_bytes());
318 }
319 if let Some(acc) = self.accuracy {
320 buf.extend_from_slice(&acc.to_le_bytes());
321 }
322 buf
323 }
324
325 pub fn decode(data: &[u8]) -> Option<Self> {
331 if data.len() < 9 {
332 return None;
333 }
334
335 let latitude = f32::from_le_bytes([data[0], data[1], data[2], data[3]]);
336 let longitude = f32::from_le_bytes([data[4], data[5], data[6], data[7]]);
337 let flags = data[8];
338
339 if !latitude.is_finite() || !longitude.is_finite() {
341 return None;
342 }
343 if !(-90.0..=90.0).contains(&latitude) {
344 return None;
345 }
346 if !(-180.0..=180.0).contains(&longitude) {
347 return None;
348 }
349
350 let mut pos = Self::new(latitude, longitude);
351 let mut offset = 9;
352
353 if flags & 0x01 != 0 {
354 if data.len() < offset + 4 {
355 return None;
356 }
357 let alt = f32::from_le_bytes([
358 data[offset],
359 data[offset + 1],
360 data[offset + 2],
361 data[offset + 3],
362 ]);
363 if !alt.is_finite() || !(-1000.0..=100000.0).contains(&alt) {
365 return None;
366 }
367 pos.altitude = Some(alt);
368 offset += 4;
369 }
370
371 if flags & 0x02 != 0 {
372 if data.len() < offset + 4 {
373 return None;
374 }
375 let acc = f32::from_le_bytes([
376 data[offset],
377 data[offset + 1],
378 data[offset + 2],
379 data[offset + 3],
380 ]);
381 if !acc.is_finite() || acc < 0.0 {
383 return None;
384 }
385 pos.accuracy = Some(acc);
386 }
387
388 Some(pos)
389 }
390}
391
392#[derive(Debug, Clone, Default, PartialEq)]
394pub struct HealthStatus {
395 pub battery_percent: u8,
397 pub heart_rate: Option<u8>,
399 pub activity: u8,
401 pub alerts: u8,
403}
404
405impl HealthStatus {
406 pub const ALERT_MAN_DOWN: u8 = 0x01;
408 pub const ALERT_LOW_BATTERY: u8 = 0x02;
410 pub const ALERT_OUT_OF_RANGE: u8 = 0x04;
412 pub const ALERT_CUSTOM_1: u8 = 0x08;
414
415 pub fn new(battery_percent: u8) -> Self {
417 Self {
418 battery_percent,
419 heart_rate: None,
420 activity: 0,
421 alerts: 0,
422 }
423 }
424
425 pub fn with_heart_rate(mut self, hr: u8) -> Self {
427 self.heart_rate = Some(hr);
428 self
429 }
430
431 pub fn with_activity(mut self, activity: u8) -> Self {
433 self.activity = activity;
434 self
435 }
436
437 pub fn set_alert(&mut self, flag: u8) {
439 self.alerts |= flag;
440 }
441
442 pub fn clear_alert(&mut self, flag: u8) {
444 self.alerts &= !flag;
445 }
446
447 pub fn has_alert(&self, flag: u8) -> bool {
449 self.alerts & flag != 0
450 }
451
452 pub fn encode(&self) -> Vec<u8> {
454 vec![
455 self.battery_percent,
456 self.activity,
457 self.alerts,
458 self.heart_rate.unwrap_or(0),
460 ]
461 }
462
463 pub fn decode(data: &[u8]) -> Option<Self> {
469 if data.len() < 4 {
470 return None;
471 }
472
473 let battery_percent = data[0];
474 let activity = data[1];
475 let alerts = data[2];
476 let heart_rate_raw = data[3];
477
478 if battery_percent > MAX_BATTERY_PERCENT {
480 return None;
481 }
482
483 if activity > 3 {
485 return None;
486 }
487
488 let mut status = Self::new(battery_percent);
489 status.activity = activity;
490 status.alerts = alerts;
491
492 if heart_rate_raw > 0 {
494 if !(MIN_HEART_RATE..=MAX_HEART_RATE).contains(&heart_rate_raw) {
495 return None;
496 }
497 status.heart_rate = Some(heart_rate_raw);
498 }
499
500 Some(status)
501 }
502}
503
504#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
510#[repr(u8)]
511pub enum PeripheralType {
512 #[default]
514 Unknown = 0,
515 SoldierSensor = 1,
517 FixedSensor = 2,
519 Relay = 3,
521}
522
523impl PeripheralType {
524 pub fn from_u8(v: u8) -> Self {
526 match v {
527 1 => Self::SoldierSensor,
528 2 => Self::FixedSensor,
529 3 => Self::Relay,
530 _ => Self::Unknown,
531 }
532 }
533}
534
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
537#[repr(u8)]
538pub enum EventType {
539 #[default]
541 None = 0,
542 Ping = 1,
544 NeedAssist = 2,
546 Emergency = 3,
548 Moving = 4,
550 InPosition = 5,
552 Ack = 6,
554}
555
556impl EventType {
557 pub fn from_u8(v: u8) -> Self {
559 match v {
560 1 => Self::Ping,
561 2 => Self::NeedAssist,
562 3 => Self::Emergency,
563 4 => Self::Moving,
564 5 => Self::InPosition,
565 6 => Self::Ack,
566 _ => Self::None,
567 }
568 }
569
570 pub fn label(&self) -> &'static str {
572 match self {
573 Self::None => "",
574 Self::Ping => "PING",
575 Self::NeedAssist => "NEED ASSIST",
576 Self::Emergency => "EMERGENCY",
577 Self::Moving => "MOVING",
578 Self::InPosition => "IN POSITION",
579 Self::Ack => "ACK",
580 }
581 }
582}
583
584#[derive(Debug, Clone, Default, PartialEq)]
586pub struct PeripheralEvent {
587 pub event_type: EventType,
589 pub timestamp: u64,
591}
592
593impl PeripheralEvent {
594 pub fn new(event_type: EventType, timestamp: u64) -> Self {
596 Self {
597 event_type,
598 timestamp,
599 }
600 }
601
602 pub fn encode(&self) -> Vec<u8> {
604 let mut buf = Vec::with_capacity(9);
605 buf.push(self.event_type as u8);
606 buf.extend_from_slice(&self.timestamp.to_le_bytes());
607 buf
608 }
609
610 pub fn decode(data: &[u8]) -> Option<Self> {
616 if data.len() < 9 {
617 return None;
618 }
619
620 let event_type = EventType::from_u8(data[0]);
621 let timestamp = u64::from_le_bytes([
622 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
623 ]);
624
625 if timestamp != 0 && timestamp < MIN_VALID_TIMESTAMP {
628 return None;
629 }
630
631 Some(Self {
632 event_type,
633 timestamp,
634 })
635 }
636}
637
638#[derive(Debug, Clone, PartialEq, Default)]
662pub struct EmergencyEvent {
663 source_node: u32,
665 timestamp: u64,
667 acks: BTreeMap<u32, bool>,
669}
670
671impl EmergencyEvent {
672 pub fn new(source_node: u32, timestamp: u64, known_peers: &[u32]) -> Self {
681 let mut acks = BTreeMap::new();
682
683 acks.insert(source_node, true);
685
686 for &peer_id in known_peers {
688 if peer_id != source_node {
689 acks.entry(peer_id).or_insert(false);
690 }
691 }
692
693 Self {
694 source_node,
695 timestamp,
696 acks,
697 }
698 }
699
700 pub fn source_node(&self) -> u32 {
702 self.source_node
703 }
704
705 pub fn timestamp(&self) -> u64 {
707 self.timestamp
708 }
709
710 pub fn has_acked(&self, node_id: u32) -> bool {
712 self.acks.get(&node_id).copied().unwrap_or(false)
713 }
714
715 pub fn ack(&mut self, node_id: u32) -> bool {
719 let entry = self.acks.entry(node_id).or_insert(false);
720 if !*entry {
721 *entry = true;
722 true
723 } else {
724 false
725 }
726 }
727
728 pub fn add_peer(&mut self, node_id: u32) {
733 self.acks.entry(node_id).or_insert(false);
734 }
735
736 pub fn acked_nodes(&self) -> Vec<u32> {
738 self.acks
739 .iter()
740 .filter(|(_, &acked)| acked)
741 .map(|(&node_id, _)| node_id)
742 .collect()
743 }
744
745 pub fn pending_nodes(&self) -> Vec<u32> {
747 self.acks
748 .iter()
749 .filter(|(_, &acked)| !acked)
750 .map(|(&node_id, _)| node_id)
751 .collect()
752 }
753
754 pub fn all_nodes(&self) -> Vec<u32> {
756 self.acks.keys().copied().collect()
757 }
758
759 pub fn all_acked(&self) -> bool {
761 !self.acks.is_empty() && self.acks.values().all(|&acked| acked)
762 }
763
764 pub fn peer_count(&self) -> usize {
766 self.acks.len()
767 }
768
769 pub fn ack_count(&self) -> usize {
771 self.acks.values().filter(|&&acked| acked).count()
772 }
773
774 pub fn merge(&mut self, other: &EmergencyEvent) -> bool {
783 if self.source_node != other.source_node || self.timestamp != other.timestamp {
785 if other.timestamp > self.timestamp {
786 *self = other.clone();
787 return true;
788 }
789 return false;
790 }
791
792 let mut changed = false;
794 for (&node_id, &other_acked) in &other.acks {
795 let entry = self.acks.entry(node_id).or_insert(false);
796 if other_acked && !*entry {
797 *entry = true;
798 changed = true;
799 }
800 }
801 changed
802 }
803
804 pub fn encode(&self) -> Vec<u8> {
808 let mut buf = Vec::with_capacity(16 + self.acks.len() * 5);
809
810 buf.extend_from_slice(&self.source_node.to_le_bytes());
811 buf.extend_from_slice(&self.timestamp.to_le_bytes());
812 buf.extend_from_slice(&(self.acks.len() as u32).to_le_bytes());
813
814 for (&node_id, &acked) in &self.acks {
815 buf.extend_from_slice(&node_id.to_le_bytes());
816 buf.push(if acked { 1 } else { 0 });
817 }
818
819 buf
820 }
821
822 pub fn decode(data: &[u8]) -> Option<Self> {
828 if data.len() < 16 {
829 return None;
830 }
831
832 let source_node = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
833 let timestamp = u64::from_le_bytes([
834 data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11],
835 ]);
836 let num_acks = u32::from_le_bytes([data[12], data[13], data[14], data[15]]) as usize;
837
838 if source_node == 0 {
840 return None;
841 }
842
843 if timestamp < MIN_VALID_TIMESTAMP {
845 return None;
846 }
847
848 if num_acks > MAX_EMERGENCY_ACKS {
850 return None;
851 }
852
853 if data.len() < 16 + num_acks * 5 {
854 return None;
855 }
856
857 let mut acks = BTreeMap::new();
858 let mut offset = 16;
859 for _ in 0..num_acks {
860 let node_id = u32::from_le_bytes([
861 data[offset],
862 data[offset + 1],
863 data[offset + 2],
864 data[offset + 3],
865 ]);
866 if node_id != 0 {
868 let acked = data[offset + 4] != 0;
869 acks.insert(node_id, acked);
870 }
871 offset += 5;
872 }
873
874 Some(Self {
875 source_node,
876 timestamp,
877 acks,
878 })
879 }
880}
881
882#[derive(Debug, Clone, Default)]
887pub struct Peripheral {
888 pub id: u32,
890 pub parent_node: u32,
892 pub peripheral_type: PeripheralType,
894 pub callsign: [u8; 12],
896 pub health: HealthStatus,
898 pub last_event: Option<PeripheralEvent>,
900 pub timestamp: u64,
902}
903
904impl Peripheral {
905 pub fn new(id: u32, peripheral_type: PeripheralType) -> Self {
907 Self {
908 id,
909 parent_node: 0,
910 peripheral_type,
911 callsign: [0u8; 12],
912 health: HealthStatus::default(),
913 last_event: None,
914 timestamp: 0,
915 }
916 }
917
918 pub fn with_callsign(mut self, callsign: &str) -> Self {
920 let bytes = callsign.as_bytes();
921 let len = bytes.len().min(12);
922 self.callsign[..len].copy_from_slice(&bytes[..len]);
923 self
924 }
925
926 pub fn callsign_str(&self) -> &str {
928 let len = self.callsign.iter().position(|&b| b == 0).unwrap_or(12);
929 core::str::from_utf8(&self.callsign[..len]).unwrap_or("")
930 }
931
932 pub fn with_parent(mut self, parent_node: u32) -> Self {
934 self.parent_node = parent_node;
935 self
936 }
937
938 pub fn set_event(&mut self, event_type: EventType, timestamp: u64) {
940 self.last_event = Some(PeripheralEvent::new(event_type, timestamp));
941 self.timestamp = timestamp;
942 }
943
944 pub fn clear_event(&mut self) {
946 self.last_event = None;
947 }
948
949 pub fn encode(&self) -> Vec<u8> {
953 let mut buf = Vec::with_capacity(43);
954 buf.extend_from_slice(&self.id.to_le_bytes());
955 buf.extend_from_slice(&self.parent_node.to_le_bytes());
956 buf.push(self.peripheral_type as u8);
957 buf.extend_from_slice(&self.callsign);
958 buf.extend_from_slice(&self.health.encode());
959
960 if let Some(ref event) = self.last_event {
961 buf.push(1); buf.extend_from_slice(&event.encode());
963 } else {
964 buf.push(0); }
966
967 buf.extend_from_slice(&self.timestamp.to_le_bytes());
968 buf
969 }
970
971 pub fn decode(data: &[u8]) -> Option<Self> {
977 if data.len() < 34 {
978 return None;
979 }
980
981 let id = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
982 let parent_node = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
983 let peripheral_type = PeripheralType::from_u8(data[8]);
984
985 if id == 0 {
987 return None;
988 }
989
990 let mut callsign = [0u8; 12];
991 callsign.copy_from_slice(&data[9..21]);
992
993 let callsign_len = callsign.iter().position(|&b| b == 0).unwrap_or(12);
996 if callsign_len > 0 && core::str::from_utf8(&callsign[..callsign_len]).is_err() {
997 return None;
998 }
999
1000 let health = HealthStatus::decode(&data[21..25])?;
1002
1003 let has_event = data[25] != 0;
1004 let (last_event, timestamp_offset) = if has_event {
1005 if data.len() < 43 {
1006 return None;
1007 }
1008 (PeripheralEvent::decode(&data[26..35]), 35)
1010 } else {
1011 (None, 26)
1012 };
1013
1014 if data.len() < timestamp_offset + 8 {
1015 return None;
1016 }
1017
1018 let timestamp = u64::from_le_bytes([
1019 data[timestamp_offset],
1020 data[timestamp_offset + 1],
1021 data[timestamp_offset + 2],
1022 data[timestamp_offset + 3],
1023 data[timestamp_offset + 4],
1024 data[timestamp_offset + 5],
1025 data[timestamp_offset + 6],
1026 data[timestamp_offset + 7],
1027 ]);
1028
1029 if timestamp != 0 && timestamp < MIN_VALID_TIMESTAMP {
1031 return None;
1032 }
1033
1034 Some(Self {
1035 id,
1036 parent_node,
1037 peripheral_type,
1038 callsign,
1039 health,
1040 last_event,
1041 timestamp,
1042 })
1043 }
1044}
1045
1046pub const CHAT_MAX_TEXT_LEN: usize = 128;
1052
1053pub const CHAT_MAX_SENDER_LEN: usize = 12;
1055
1056pub const CHAT_MAX_MESSAGES: usize = 32;
1060
1061pub const CHAT_SYNC_LIMIT: usize = 8;
1067
1068#[derive(Debug, Clone, PartialEq)]
1073pub struct ChatMessage {
1074 pub origin_node: u32,
1076 pub timestamp: u64,
1078 sender: [u8; CHAT_MAX_SENDER_LEN],
1080 sender_len: u8,
1081 text: [u8; CHAT_MAX_TEXT_LEN],
1083 text_len: u8,
1084 pub is_broadcast: bool,
1086 pub requires_ack: bool,
1088 pub reply_to_node: u32,
1090 pub reply_to_timestamp: u64,
1092}
1093
1094impl Default for ChatMessage {
1095 fn default() -> Self {
1096 Self {
1097 origin_node: 0,
1098 timestamp: 0,
1099 sender: [0u8; CHAT_MAX_SENDER_LEN],
1100 sender_len: 0,
1101 text: [0u8; CHAT_MAX_TEXT_LEN],
1102 text_len: 0,
1103 is_broadcast: true,
1104 requires_ack: false,
1105 reply_to_node: 0,
1106 reply_to_timestamp: 0,
1107 }
1108 }
1109}
1110
1111impl ChatMessage {
1112 pub fn new(origin_node: u32, timestamp: u64, sender: &str, text: &str) -> Self {
1114 let mut msg = Self {
1115 origin_node,
1116 timestamp,
1117 ..Default::default()
1118 };
1119 msg.set_sender(sender);
1120 msg.set_text(text);
1121 msg
1122 }
1123
1124 pub fn set_sender(&mut self, sender: &str) {
1126 let bytes = sender.as_bytes();
1127 let len = bytes.len().min(CHAT_MAX_SENDER_LEN);
1128 self.sender[..len].copy_from_slice(&bytes[..len]);
1129 self.sender_len = len as u8;
1130 }
1131
1132 pub fn sender(&self) -> &str {
1134 core::str::from_utf8(&self.sender[..self.sender_len as usize]).unwrap_or("")
1135 }
1136
1137 pub fn set_text(&mut self, text: &str) {
1139 let bytes = text.as_bytes();
1140 let len = bytes.len().min(CHAT_MAX_TEXT_LEN);
1141 self.text[..len].copy_from_slice(&bytes[..len]);
1142 self.text_len = len as u8;
1143 }
1144
1145 pub fn text(&self) -> &str {
1147 core::str::from_utf8(&self.text[..self.text_len as usize]).unwrap_or("")
1148 }
1149
1150 pub fn set_reply_to(&mut self, node: u32, timestamp: u64) {
1152 self.reply_to_node = node;
1153 self.reply_to_timestamp = timestamp;
1154 }
1155
1156 pub fn is_reply(&self) -> bool {
1158 self.reply_to_node != 0 || self.reply_to_timestamp != 0
1159 }
1160
1161 pub fn message_id(&self) -> u64 {
1166 ((self.origin_node as u64) << 32) | (self.timestamp & 0xFFFFFFFF)
1167 }
1168
1169 pub fn encode(&self) -> Vec<u8> {
1184 let size = 4 + 8 + 1 + self.sender_len as usize + 1 + self.text_len as usize + 1 + 4 + 8;
1185 let mut buf = Vec::with_capacity(size);
1186
1187 buf.extend_from_slice(&self.origin_node.to_le_bytes());
1188 buf.extend_from_slice(&self.timestamp.to_le_bytes());
1189 buf.push(self.sender_len);
1190 buf.extend_from_slice(&self.sender[..self.sender_len as usize]);
1191 buf.push(self.text_len);
1192 buf.extend_from_slice(&self.text[..self.text_len as usize]);
1193
1194 let mut flags = 0u8;
1195 if self.is_broadcast {
1196 flags |= 0x01;
1197 }
1198 if self.requires_ack {
1199 flags |= 0x02;
1200 }
1201 buf.push(flags);
1202
1203 buf.extend_from_slice(&self.reply_to_node.to_le_bytes());
1204 buf.extend_from_slice(&self.reply_to_timestamp.to_le_bytes());
1205
1206 buf
1207 }
1208
1209 pub fn decode(data: &[u8]) -> Option<(Self, usize)> {
1222 if data.len() < 14 {
1223 return None;
1225 }
1226
1227 let origin_node = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
1228 let timestamp = u64::from_le_bytes([
1229 data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11],
1230 ]);
1231
1232 if origin_node == 0 {
1234 return None;
1235 }
1236
1237 if timestamp < MIN_VALID_TIMESTAMP {
1239 return None;
1240 }
1241
1242 let sender_len = data[12] as usize;
1243 if sender_len > CHAT_MAX_SENDER_LEN || data.len() < 13 + sender_len + 1 {
1244 return None;
1245 }
1246
1247 if sender_len == 0 {
1249 return None;
1250 }
1251
1252 let mut sender = [0u8; CHAT_MAX_SENDER_LEN];
1253 sender[..sender_len].copy_from_slice(&data[13..13 + sender_len]);
1254
1255 if core::str::from_utf8(&sender[..sender_len]).is_err() {
1257 return None;
1258 }
1259
1260 let text_offset = 13 + sender_len;
1261 let text_len = data[text_offset] as usize;
1262 if text_len > CHAT_MAX_TEXT_LEN || data.len() < text_offset + 1 + text_len + 1 {
1263 return None;
1264 }
1265
1266 let mut text = [0u8; CHAT_MAX_TEXT_LEN];
1267 text[..text_len].copy_from_slice(&data[text_offset + 1..text_offset + 1 + text_len]);
1268
1269 if text_len > 0 && core::str::from_utf8(&text[..text_len]).is_err() {
1272 return None;
1273 }
1274
1275 let flags_offset = text_offset + 1 + text_len;
1276 let flags = data[flags_offset];
1277 let is_broadcast = flags & 0x01 != 0;
1278 let requires_ack = flags & 0x02 != 0;
1279
1280 let mut reply_to_node = 0u32;
1282 let mut reply_to_timestamp = 0u64;
1283 let mut total_len = flags_offset + 1;
1284
1285 if data.len() >= flags_offset + 1 + 12 {
1286 reply_to_node = u32::from_le_bytes([
1287 data[flags_offset + 1],
1288 data[flags_offset + 2],
1289 data[flags_offset + 3],
1290 data[flags_offset + 4],
1291 ]);
1292 reply_to_timestamp = u64::from_le_bytes([
1293 data[flags_offset + 5],
1294 data[flags_offset + 6],
1295 data[flags_offset + 7],
1296 data[flags_offset + 8],
1297 data[flags_offset + 9],
1298 data[flags_offset + 10],
1299 data[flags_offset + 11],
1300 data[flags_offset + 12],
1301 ]);
1302 total_len = flags_offset + 13;
1303 }
1304
1305 Some((
1306 Self {
1307 origin_node,
1308 timestamp,
1309 sender,
1310 sender_len: sender_len as u8,
1311 text,
1312 text_len: text_len as u8,
1313 is_broadcast,
1314 requires_ack,
1315 reply_to_node,
1316 reply_to_timestamp,
1317 },
1318 total_len,
1319 ))
1320 }
1321}
1322
1323#[derive(Debug, Clone, Default)]
1343pub struct ChatCRDT {
1344 messages: BTreeMap<u64, ChatMessage>,
1346}
1347
1348impl ChatCRDT {
1349 pub fn new() -> Self {
1351 Self {
1352 messages: BTreeMap::new(),
1353 }
1354 }
1355
1356 pub fn add_message(&mut self, message: ChatMessage) -> bool {
1360 let id = message.message_id();
1361 if self.messages.contains_key(&id) {
1362 return false;
1363 }
1364
1365 self.messages.insert(id, message);
1366 self.prune_if_needed();
1367 true
1368 }
1369
1370 pub fn send_message(
1372 &mut self,
1373 origin_node: u32,
1374 timestamp: u64,
1375 sender: &str,
1376 text: &str,
1377 ) -> bool {
1378 let msg = ChatMessage::new(origin_node, timestamp, sender, text);
1379 self.add_message(msg)
1380 }
1381
1382 pub fn get_message(&self, origin_node: u32, timestamp: u64) -> Option<&ChatMessage> {
1384 let id = ((origin_node as u64) << 32) | (timestamp & 0xFFFFFFFF);
1385 self.messages.get(&id)
1386 }
1387
1388 pub fn messages(&self) -> impl Iterator<Item = &ChatMessage> {
1390 self.messages.values()
1391 }
1392
1393 pub fn messages_since(&self, since_timestamp: u64) -> impl Iterator<Item = &ChatMessage> {
1395 self.messages
1396 .values()
1397 .filter(move |m| m.timestamp > since_timestamp)
1398 }
1399
1400 pub fn len(&self) -> usize {
1402 self.messages.len()
1403 }
1404
1405 pub fn is_empty(&self) -> bool {
1407 self.messages.is_empty()
1408 }
1409
1410 pub fn newest_timestamp(&self) -> Option<u64> {
1412 self.messages.values().map(|m| m.timestamp).max()
1413 }
1414
1415 pub fn merge(&mut self, other: &ChatCRDT) -> bool {
1419 let mut changed = false;
1420 for (id, msg) in &other.messages {
1421 if !self.messages.contains_key(id) {
1422 self.messages.insert(*id, msg.clone());
1423 changed = true;
1424 }
1425 }
1426 if changed {
1427 self.prune_if_needed();
1428 }
1429 changed
1430 }
1431
1432 fn prune_if_needed(&mut self) {
1434 while self.messages.len() > CHAT_MAX_MESSAGES {
1435 if let Some(&oldest_id) = self.messages.keys().next() {
1437 self.messages.remove(&oldest_id);
1438 }
1439 }
1440 }
1441
1442 pub fn encode(&self) -> Vec<u8> {
1444 let mut buf = Vec::new();
1445
1446 buf.extend_from_slice(&(self.messages.len() as u16).to_le_bytes());
1448
1449 for msg in self.messages.values() {
1451 buf.extend_from_slice(&msg.encode());
1452 }
1453
1454 buf
1455 }
1456
1457 pub fn decode(data: &[u8]) -> Option<Self> {
1459 if data.len() < 2 {
1460 return None;
1461 }
1462
1463 let num_messages = u16::from_le_bytes([data[0], data[1]]) as usize;
1464 let mut messages = BTreeMap::new();
1465 let mut offset = 2;
1466
1467 for _ in 0..num_messages {
1468 if offset >= data.len() {
1469 break;
1470 }
1471 if let Some((msg, len)) = ChatMessage::decode(&data[offset..]) {
1472 let id = msg.message_id();
1473 messages.insert(id, msg);
1474 offset += len;
1475 } else {
1476 break;
1477 }
1478 }
1479
1480 Some(Self { messages })
1481 }
1482
1483 pub fn encoded_size(&self) -> usize {
1485 2 + self
1486 .messages
1487 .values()
1488 .map(|m| m.encode().len())
1489 .sum::<usize>()
1490 }
1491
1492 pub fn for_sync(&self) -> Self {
1500 if self.messages.len() <= CHAT_SYNC_LIMIT {
1501 return self.clone();
1502 }
1503
1504 let messages: BTreeMap<u64, ChatMessage> = self
1507 .messages
1508 .iter()
1509 .rev()
1510 .take(CHAT_SYNC_LIMIT)
1511 .map(|(&k, v)| (k, v.clone()))
1512 .collect();
1513
1514 Self { messages }
1515 }
1516}
1517
1518#[derive(Debug, Clone)]
1520pub enum CrdtOperation {
1521 UpdatePosition {
1523 node_id: NodeId,
1525 position: Position,
1527 timestamp: Timestamp,
1529 },
1530 UpdateHealth {
1532 node_id: NodeId,
1534 status: HealthStatus,
1536 timestamp: Timestamp,
1538 },
1539 IncrementCounter {
1541 counter_id: u8,
1543 node_id: NodeId,
1545 amount: u64,
1547 },
1548 UpdateRegister {
1550 key: String,
1552 value: Vec<u8>,
1554 timestamp: Timestamp,
1556 node_id: NodeId,
1558 },
1559}
1560
1561impl CrdtOperation {
1562 pub fn size(&self) -> usize {
1564 match self {
1565 CrdtOperation::UpdatePosition { position, .. } => 4 + 8 + position.encode().len(),
1566 CrdtOperation::UpdateHealth { status, .. } => 4 + 8 + status.encode().len(),
1567 CrdtOperation::IncrementCounter { .. } => 1 + 4 + 8,
1568 CrdtOperation::UpdateRegister { key, value, .. } => 4 + 8 + key.len() + value.len(),
1569 }
1570 }
1571
1572 pub fn encode(&self) -> Vec<u8> {
1574 let mut buf = Vec::new();
1575 match self {
1576 CrdtOperation::UpdatePosition {
1577 node_id,
1578 position,
1579 timestamp,
1580 } => {
1581 buf.push(0x01); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1583 buf.extend_from_slice(×tamp.to_le_bytes());
1584 buf.extend_from_slice(&position.encode());
1585 }
1586 CrdtOperation::UpdateHealth {
1587 node_id,
1588 status,
1589 timestamp,
1590 } => {
1591 buf.push(0x02); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1593 buf.extend_from_slice(×tamp.to_le_bytes());
1594 buf.extend_from_slice(&status.encode());
1595 }
1596 CrdtOperation::IncrementCounter {
1597 counter_id,
1598 node_id,
1599 amount,
1600 } => {
1601 buf.push(0x03); buf.push(*counter_id);
1603 buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1604 buf.extend_from_slice(&amount.to_le_bytes());
1605 }
1606 CrdtOperation::UpdateRegister {
1607 key,
1608 value,
1609 timestamp,
1610 node_id,
1611 } => {
1612 buf.push(0x04); buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
1614 buf.extend_from_slice(×tamp.to_le_bytes());
1615 buf.push(key.len() as u8);
1616 buf.extend_from_slice(key.as_bytes());
1617 buf.extend_from_slice(&(value.len() as u16).to_le_bytes());
1618 buf.extend_from_slice(value);
1619 }
1620 }
1621 buf
1622 }
1623
1624 pub fn decode(data: &[u8]) -> Option<Self> {
1626 if data.is_empty() {
1627 return None;
1628 }
1629
1630 match data[0] {
1631 0x01 => {
1632 if data.len() < 13 {
1634 return None;
1635 }
1636 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1637 let timestamp = u64::from_le_bytes([
1638 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1639 ]);
1640 let position = Position::decode(&data[13..])?;
1641 Some(CrdtOperation::UpdatePosition {
1642 node_id,
1643 position,
1644 timestamp,
1645 })
1646 }
1647 0x02 => {
1648 if data.len() < 13 {
1650 return None;
1651 }
1652 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1653 let timestamp = u64::from_le_bytes([
1654 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1655 ]);
1656 let status = HealthStatus::decode(&data[13..])?;
1657 Some(CrdtOperation::UpdateHealth {
1658 node_id,
1659 status,
1660 timestamp,
1661 })
1662 }
1663 0x03 => {
1664 if data.len() < 14 {
1666 return None;
1667 }
1668 let counter_id = data[1];
1669 let node_id = NodeId::new(u32::from_le_bytes([data[2], data[3], data[4], data[5]]));
1670 let amount = u64::from_le_bytes([
1671 data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13],
1672 ]);
1673 Some(CrdtOperation::IncrementCounter {
1674 counter_id,
1675 node_id,
1676 amount,
1677 })
1678 }
1679 0x04 => {
1680 if data.len() < 14 {
1682 return None;
1683 }
1684 let node_id = NodeId::new(u32::from_le_bytes([data[1], data[2], data[3], data[4]]));
1685 let timestamp = u64::from_le_bytes([
1686 data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12],
1687 ]);
1688 let key_len = data[13] as usize;
1689 if data.len() < 14 + key_len + 2 {
1690 return None;
1691 }
1692 let key = core::str::from_utf8(&data[14..14 + key_len])
1693 .ok()?
1694 .to_string();
1695 let value_len =
1696 u16::from_le_bytes([data[14 + key_len], data[15 + key_len]]) as usize;
1697 if data.len() < 16 + key_len + value_len {
1698 return None;
1699 }
1700 let value = data[16 + key_len..16 + key_len + value_len].to_vec();
1701 Some(CrdtOperation::UpdateRegister {
1702 key,
1703 value,
1704 timestamp,
1705 node_id,
1706 })
1707 }
1708 _ => None,
1709 }
1710 }
1711}
1712
1713#[cfg(test)]
1714mod tests {
1715 use super::*;
1716
1717 const TEST_TIMESTAMP: u64 = 1705276800000;
1720
1721 #[test]
1722 fn test_lww_register_basic() {
1723 let mut reg = LwwRegister::new(42u32, 100, NodeId::new(1));
1724 assert_eq!(*reg.get(), 42);
1725 assert_eq!(reg.timestamp(), 100);
1726
1727 assert!(reg.set(99, 200, NodeId::new(2)));
1729 assert_eq!(*reg.get(), 99);
1730
1731 assert!(!reg.set(50, 150, NodeId::new(3)));
1733 assert_eq!(*reg.get(), 99);
1734 }
1735
1736 #[test]
1737 fn test_lww_register_tiebreak() {
1738 let mut reg = LwwRegister::new(1u32, 100, NodeId::new(1));
1739
1740 assert!(reg.set(2, 100, NodeId::new(2)));
1742 assert_eq!(*reg.get(), 2);
1743
1744 assert!(!reg.set(3, 100, NodeId::new(1)));
1746 assert_eq!(*reg.get(), 2);
1747 }
1748
1749 #[test]
1750 fn test_lww_register_merge() {
1751 let mut reg1 = LwwRegister::new(1u32, 100, NodeId::new(1));
1752 let reg2 = LwwRegister::new(2u32, 200, NodeId::new(2));
1753
1754 assert!(reg1.merge(®2));
1755 assert_eq!(*reg1.get(), 2);
1756 }
1757
1758 #[test]
1759 fn test_gcounter_basic() {
1760 let mut counter = GCounter::new();
1761 let node1 = NodeId::new(1);
1762 let node2 = NodeId::new(2);
1763
1764 counter.increment(&node1, 5);
1765 counter.increment(&node2, 3);
1766 counter.increment(&node1, 2);
1767
1768 assert_eq!(counter.value(), 10);
1769 assert_eq!(counter.node_count(&node1), 7);
1770 assert_eq!(counter.node_count(&node2), 3);
1771 }
1772
1773 #[test]
1774 fn test_gcounter_merge() {
1775 let mut counter1 = GCounter::new();
1776 let mut counter2 = GCounter::new();
1777 let node1 = NodeId::new(1);
1778 let node2 = NodeId::new(2);
1779
1780 counter1.increment(&node1, 5);
1781 counter2.increment(&node1, 3);
1782 counter2.increment(&node2, 4);
1783
1784 counter1.merge(&counter2);
1785
1786 assert_eq!(counter1.value(), 9); assert_eq!(counter1.node_count(&node1), 5);
1788 assert_eq!(counter1.node_count(&node2), 4);
1789 }
1790
1791 #[test]
1792 fn test_gcounter_encode_decode() {
1793 let mut counter = GCounter::new();
1794 counter.increment(&NodeId::new(1), 5);
1795 counter.increment(&NodeId::new(2), 10);
1796
1797 let encoded = counter.encode();
1798 let decoded = GCounter::decode(&encoded).unwrap();
1799
1800 assert_eq!(decoded.value(), counter.value());
1801 assert_eq!(decoded.node_count(&NodeId::new(1)), 5);
1802 assert_eq!(decoded.node_count(&NodeId::new(2)), 10);
1803 }
1804
1805 #[test]
1806 fn test_position_encode_decode() {
1807 let pos = Position::new(37.7749, -122.4194)
1808 .with_altitude(100.0)
1809 .with_accuracy(5.0);
1810
1811 let encoded = pos.encode();
1812 let decoded = Position::decode(&encoded).unwrap();
1813
1814 assert_eq!(decoded.latitude, pos.latitude);
1815 assert_eq!(decoded.longitude, pos.longitude);
1816 assert_eq!(decoded.altitude, pos.altitude);
1817 assert_eq!(decoded.accuracy, pos.accuracy);
1818 }
1819
1820 #[test]
1821 fn test_position_minimal_encode() {
1822 let pos = Position::new(0.0, 0.0);
1823 let encoded = pos.encode();
1824 assert_eq!(encoded.len(), 9); let pos_with_alt = Position::new(0.0, 0.0).with_altitude(0.0);
1827 let encoded_alt = pos_with_alt.encode();
1828 assert_eq!(encoded_alt.len(), 13);
1829 }
1830
1831 #[test]
1832 fn test_health_status() {
1833 let mut status = HealthStatus::new(85).with_heart_rate(72).with_activity(1);
1834
1835 assert_eq!(status.battery_percent, 85);
1836 assert_eq!(status.heart_rate, Some(72));
1837 assert!(!status.has_alert(HealthStatus::ALERT_MAN_DOWN));
1838
1839 status.set_alert(HealthStatus::ALERT_MAN_DOWN);
1840 assert!(status.has_alert(HealthStatus::ALERT_MAN_DOWN));
1841
1842 let encoded = status.encode();
1843 let decoded = HealthStatus::decode(&encoded).unwrap();
1844 assert_eq!(decoded.battery_percent, 85);
1845 assert_eq!(decoded.heart_rate, Some(72));
1846 assert!(decoded.has_alert(HealthStatus::ALERT_MAN_DOWN));
1847 }
1848
1849 #[test]
1850 fn test_crdt_operation_position() {
1851 let op = CrdtOperation::UpdatePosition {
1852 node_id: NodeId::new(0x1234),
1853 position: Position::new(37.0, -122.0),
1854 timestamp: 1000,
1855 };
1856
1857 let encoded = op.encode();
1858 let decoded = CrdtOperation::decode(&encoded).unwrap();
1859
1860 if let CrdtOperation::UpdatePosition {
1861 node_id,
1862 position,
1863 timestamp,
1864 } = decoded
1865 {
1866 assert_eq!(node_id.as_u32(), 0x1234);
1867 assert_eq!(timestamp, 1000);
1868 assert_eq!(position.latitude, 37.0);
1869 } else {
1870 panic!("Wrong operation type");
1871 }
1872 }
1873
1874 #[test]
1875 fn test_crdt_operation_counter() {
1876 let op = CrdtOperation::IncrementCounter {
1877 counter_id: 1,
1878 node_id: NodeId::new(0x5678),
1879 amount: 42,
1880 };
1881
1882 let encoded = op.encode();
1883 let decoded = CrdtOperation::decode(&encoded).unwrap();
1884
1885 if let CrdtOperation::IncrementCounter {
1886 counter_id,
1887 node_id,
1888 amount,
1889 } = decoded
1890 {
1891 assert_eq!(counter_id, 1);
1892 assert_eq!(node_id.as_u32(), 0x5678);
1893 assert_eq!(amount, 42);
1894 } else {
1895 panic!("Wrong operation type");
1896 }
1897 }
1898
1899 #[test]
1900 fn test_crdt_operation_size() {
1901 let pos_op = CrdtOperation::UpdatePosition {
1902 node_id: NodeId::new(1),
1903 position: Position::new(0.0, 0.0),
1904 timestamp: 0,
1905 };
1906 assert!(pos_op.size() > 0);
1907
1908 let counter_op = CrdtOperation::IncrementCounter {
1909 counter_id: 0,
1910 node_id: NodeId::new(1),
1911 amount: 1,
1912 };
1913 assert_eq!(counter_op.size(), 13);
1914 }
1915
1916 #[test]
1921 fn test_peripheral_type_from_u8() {
1922 assert_eq!(PeripheralType::from_u8(0), PeripheralType::Unknown);
1923 assert_eq!(PeripheralType::from_u8(1), PeripheralType::SoldierSensor);
1924 assert_eq!(PeripheralType::from_u8(2), PeripheralType::FixedSensor);
1925 assert_eq!(PeripheralType::from_u8(3), PeripheralType::Relay);
1926 assert_eq!(PeripheralType::from_u8(99), PeripheralType::Unknown);
1927 }
1928
1929 #[test]
1930 fn test_event_type_from_u8() {
1931 assert_eq!(EventType::from_u8(0), EventType::None);
1932 assert_eq!(EventType::from_u8(1), EventType::Ping);
1933 assert_eq!(EventType::from_u8(2), EventType::NeedAssist);
1934 assert_eq!(EventType::from_u8(3), EventType::Emergency);
1935 assert_eq!(EventType::from_u8(4), EventType::Moving);
1936 assert_eq!(EventType::from_u8(5), EventType::InPosition);
1937 assert_eq!(EventType::from_u8(6), EventType::Ack);
1938 assert_eq!(EventType::from_u8(99), EventType::None);
1939 }
1940
1941 #[test]
1942 fn test_event_type_labels() {
1943 assert_eq!(EventType::None.label(), "");
1944 assert_eq!(EventType::Emergency.label(), "EMERGENCY");
1945 assert_eq!(EventType::Ping.label(), "PING");
1946 }
1947
1948 #[test]
1949 fn test_peripheral_event_encode_decode() {
1950 let event = PeripheralEvent::new(EventType::Emergency, TEST_TIMESTAMP);
1951 let encoded = event.encode();
1952 assert_eq!(encoded.len(), 9);
1953
1954 let decoded = PeripheralEvent::decode(&encoded).unwrap();
1955 assert_eq!(decoded.event_type, EventType::Emergency);
1956 assert_eq!(decoded.timestamp, TEST_TIMESTAMP);
1957 }
1958
1959 #[test]
1960 fn test_peripheral_new() {
1961 let peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor);
1962 assert_eq!(peripheral.id, 0x12345678);
1963 assert_eq!(peripheral.peripheral_type, PeripheralType::SoldierSensor);
1964 assert_eq!(peripheral.parent_node, 0);
1965 assert!(peripheral.last_event.is_none());
1966 }
1967
1968 #[test]
1969 fn test_peripheral_with_callsign() {
1970 let peripheral = Peripheral::new(1, PeripheralType::SoldierSensor).with_callsign("ALPHA-1");
1971 assert_eq!(peripheral.callsign_str(), "ALPHA-1");
1972
1973 let peripheral2 = Peripheral::new(2, PeripheralType::SoldierSensor)
1975 .with_callsign("THIS_IS_A_VERY_LONG_CALLSIGN");
1976 assert_eq!(peripheral2.callsign_str(), "THIS_IS_A_VE");
1977 }
1978
1979 #[test]
1980 fn test_peripheral_set_event() {
1981 let mut peripheral = Peripheral::new(1, PeripheralType::SoldierSensor);
1982 peripheral.set_event(EventType::Emergency, TEST_TIMESTAMP);
1983
1984 assert!(peripheral.last_event.is_some());
1985 let event = peripheral.last_event.as_ref().unwrap();
1986 assert_eq!(event.event_type, EventType::Emergency);
1987 assert_eq!(event.timestamp, TEST_TIMESTAMP);
1988 assert_eq!(peripheral.timestamp, TEST_TIMESTAMP);
1989
1990 peripheral.clear_event();
1991 assert!(peripheral.last_event.is_none());
1992 }
1993
1994 #[test]
1995 fn test_peripheral_encode_decode_without_event() {
1996 let peripheral = Peripheral::new(0xAABBCCDD, PeripheralType::SoldierSensor)
1997 .with_callsign("BRAVO-2")
1998 .with_parent(0x11223344);
1999
2000 let encoded = peripheral.encode();
2001 assert_eq!(encoded.len(), 34); let decoded = Peripheral::decode(&encoded).unwrap();
2004 assert_eq!(decoded.id, 0xAABBCCDD);
2005 assert_eq!(decoded.parent_node, 0x11223344);
2006 assert_eq!(decoded.peripheral_type, PeripheralType::SoldierSensor);
2007 assert_eq!(decoded.callsign_str(), "BRAVO-2");
2008 assert!(decoded.last_event.is_none());
2009 }
2010
2011 #[test]
2012 fn test_peripheral_encode_decode_with_event() {
2013 let mut peripheral = Peripheral::new(0x12345678, PeripheralType::SoldierSensor)
2014 .with_callsign("CHARLIE")
2015 .with_parent(0x87654321);
2016 peripheral.health = HealthStatus::new(85);
2017 peripheral.set_event(EventType::NeedAssist, TEST_TIMESTAMP);
2018
2019 let encoded = peripheral.encode();
2020 assert_eq!(encoded.len(), 43); let decoded = Peripheral::decode(&encoded).unwrap();
2023 assert_eq!(decoded.id, 0x12345678);
2024 assert_eq!(decoded.parent_node, 0x87654321);
2025 assert_eq!(decoded.callsign_str(), "CHARLIE");
2026 assert_eq!(decoded.health.battery_percent, 85);
2027 assert!(decoded.last_event.is_some());
2028 let event = decoded.last_event.as_ref().unwrap();
2029 assert_eq!(event.event_type, EventType::NeedAssist);
2030 assert_eq!(event.timestamp, TEST_TIMESTAMP);
2031 }
2032
2033 #[test]
2034 fn test_peripheral_decode_invalid_data() {
2035 assert!(Peripheral::decode(&[0u8; 10]).is_none());
2037
2038 let mut data = vec![0u8; 34];
2040 data[25] = 0; assert!(Peripheral::decode(&data).is_none()); data[0..4].copy_from_slice(&1u32.to_le_bytes()); assert!(Peripheral::decode(&data).is_some());
2046
2047 data[25] = 1; assert!(Peripheral::decode(&data).is_none());
2050 }
2051
2052 #[test]
2057 fn test_emergency_event_new() {
2058 let peers = vec![0x22222222, 0x33333333];
2059 let event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2060
2061 assert_eq!(event.source_node(), 0x11111111);
2062 assert_eq!(event.timestamp(), TEST_TIMESTAMP);
2063 assert_eq!(event.peer_count(), 3); assert!(event.has_acked(0x11111111));
2067 assert!(!event.has_acked(0x22222222));
2069 assert!(!event.has_acked(0x33333333));
2070 }
2071
2072 #[test]
2073 fn test_emergency_event_ack() {
2074 let peers = vec![0x22222222, 0x33333333];
2075 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2076
2077 assert_eq!(event.ack_count(), 1); assert!(!event.all_acked());
2079
2080 assert!(event.ack(0x22222222)); assert_eq!(event.ack_count(), 2);
2083 assert!(!event.all_acked());
2084
2085 assert!(!event.ack(0x22222222)); assert!(event.ack(0x33333333));
2090 assert_eq!(event.ack_count(), 3);
2091 assert!(event.all_acked());
2092 }
2093
2094 #[test]
2095 fn test_emergency_event_pending_nodes() {
2096 let peers = vec![0x22222222, 0x33333333];
2097 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2098
2099 let pending = event.pending_nodes();
2100 assert_eq!(pending.len(), 2);
2101 assert!(pending.contains(&0x22222222));
2102 assert!(pending.contains(&0x33333333));
2103
2104 event.ack(0x22222222);
2105 let pending = event.pending_nodes();
2106 assert_eq!(pending.len(), 1);
2107 assert!(pending.contains(&0x33333333));
2108 }
2109
2110 #[test]
2111 fn test_emergency_event_encode_decode() {
2112 let peers = vec![0x22222222, 0x33333333];
2113 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2114 event.ack(0x22222222);
2115
2116 let encoded = event.encode();
2117 let decoded = EmergencyEvent::decode(&encoded).unwrap();
2118
2119 assert_eq!(decoded.source_node(), 0x11111111);
2120 assert_eq!(decoded.timestamp(), TEST_TIMESTAMP);
2121 assert!(decoded.has_acked(0x11111111));
2122 assert!(decoded.has_acked(0x22222222));
2123 assert!(!decoded.has_acked(0x33333333));
2124 }
2125
2126 #[test]
2127 fn test_emergency_event_merge_same_event() {
2128 let peers = vec![0x22222222, 0x33333333];
2130 let mut event1 = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2131 let mut event2 = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &peers);
2132
2133 event1.ack(0x22222222);
2134 event2.ack(0x33333333);
2135
2136 let changed = event1.merge(&event2);
2138 assert!(changed);
2139 assert!(event1.has_acked(0x22222222));
2140 assert!(event1.has_acked(0x33333333));
2141 assert!(event1.all_acked());
2142 }
2143
2144 #[test]
2145 fn test_emergency_event_merge_different_events() {
2146 let mut old_event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &[0x22222222]);
2148 old_event.ack(0x22222222);
2149
2150 let new_event =
2152 EmergencyEvent::new(0x33333333, TEST_TIMESTAMP + 1000, &[0x11111111, 0x22222222]);
2153
2154 let changed = old_event.merge(&new_event);
2156 assert!(changed);
2157 assert_eq!(old_event.source_node(), 0x33333333);
2158 assert_eq!(old_event.timestamp(), TEST_TIMESTAMP + 1000);
2159 assert!(!old_event.has_acked(0x22222222));
2161 }
2162
2163 #[test]
2164 fn test_emergency_event_merge_older_event_ignored() {
2165 let mut current = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP + 1000, &[0x22222222]);
2167
2168 let older = EmergencyEvent::new(0x33333333, TEST_TIMESTAMP, &[0x11111111]);
2170
2171 let changed = current.merge(&older);
2173 assert!(!changed);
2174 assert_eq!(current.source_node(), 0x11111111);
2175 assert_eq!(current.timestamp(), TEST_TIMESTAMP + 1000);
2176 }
2177
2178 #[test]
2179 fn test_emergency_event_add_peer() {
2180 let mut event = EmergencyEvent::new(0x11111111, TEST_TIMESTAMP, &[]);
2181
2182 event.add_peer(0x22222222);
2184 assert!(!event.has_acked(0x22222222));
2185 assert_eq!(event.peer_count(), 2);
2186
2187 event.ack(0x22222222);
2189 event.add_peer(0x22222222);
2190 assert!(event.has_acked(0x22222222)); }
2192
2193 #[test]
2194 fn test_emergency_event_decode_invalid() {
2195 assert!(EmergencyEvent::decode(&[0u8; 10]).is_none());
2197
2198 let mut data = vec![0u8; 16];
2200 data[12] = 5; assert!(EmergencyEvent::decode(&data).is_none());
2202 }
2203
2204 #[test]
2209 fn test_chat_message_new() {
2210 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "ALPHA-1", "Hello mesh!");
2211 assert_eq!(msg.origin_node, 0x12345678);
2212 assert_eq!(msg.timestamp, TEST_TIMESTAMP);
2213 assert_eq!(msg.sender(), "ALPHA-1");
2214 assert_eq!(msg.text(), "Hello mesh!");
2215 assert!(msg.is_broadcast);
2216 assert!(!msg.requires_ack);
2217 assert!(!msg.is_reply());
2218 }
2219
2220 #[test]
2221 fn test_chat_message_reply_to() {
2222 let mut msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP + 1000, "BRAVO", "Roger that");
2223 msg.set_reply_to(0xAABBCCDD, TEST_TIMESTAMP);
2224
2225 assert!(msg.is_reply());
2226 assert_eq!(msg.reply_to_node, 0xAABBCCDD);
2227 assert_eq!(msg.reply_to_timestamp, TEST_TIMESTAMP);
2228 }
2229
2230 #[test]
2231 fn test_chat_message_truncation() {
2232 let msg = ChatMessage::new(0x1, TEST_TIMESTAMP, "VERY_LONG_CALLSIGN", "Hi");
2234 assert_eq!(msg.sender(), "VERY_LONG_CA"); let long_text = "A".repeat(200);
2238 let msg = ChatMessage::new(0x1, TEST_TIMESTAMP, "X", &long_text);
2239 assert_eq!(msg.text().len(), 128);
2240 }
2241
2242 #[test]
2243 fn test_chat_message_id() {
2244 let msg = ChatMessage::new(0x12345678, 0x18D4A51_ABCDEF01, "X", "Y");
2245 let id = msg.message_id();
2246 assert_eq!(id, (0x12345678u64 << 32) | 0xABCDEF01);
2248 }
2249
2250 #[test]
2251 fn test_chat_message_encode_decode() {
2252 let mut msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "CHARLIE", "Test message");
2253 msg.is_broadcast = true;
2254 msg.requires_ack = true;
2255 msg.set_reply_to(0xAABBCCDD, TEST_TIMESTAMP - 1000);
2256
2257 let encoded = msg.encode();
2258 let (decoded, len) = ChatMessage::decode(&encoded).unwrap();
2259
2260 assert_eq!(len, encoded.len());
2261 assert_eq!(decoded.origin_node, 0x12345678);
2262 assert_eq!(decoded.timestamp, TEST_TIMESTAMP);
2263 assert_eq!(decoded.sender(), "CHARLIE");
2264 assert_eq!(decoded.text(), "Test message");
2265 assert!(decoded.is_broadcast);
2266 assert!(decoded.requires_ack);
2267 assert_eq!(decoded.reply_to_node, 0xAABBCCDD);
2268 assert_eq!(decoded.reply_to_timestamp, TEST_TIMESTAMP - 1000);
2269 }
2270
2271 #[test]
2272 fn test_chat_message_decode_empty_text() {
2273 let msg = ChatMessage::new(0x1, TEST_TIMESTAMP, "ACK-NODE", "");
2275 let encoded = msg.encode();
2276 let (decoded, _) = ChatMessage::decode(&encoded).unwrap();
2277 assert_eq!(decoded.sender(), "ACK-NODE");
2278 assert_eq!(decoded.text(), "");
2279 }
2280
2281 #[test]
2286 fn test_chat_message_decode_rejects_zero_origin() {
2287 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "TEST", "msg");
2289 let mut encoded = msg.encode();
2290 encoded[0] = 0;
2292 encoded[1] = 0;
2293 encoded[2] = 0;
2294 encoded[3] = 0;
2295
2296 assert!(ChatMessage::decode(&encoded).is_none());
2297 }
2298
2299 #[test]
2300 fn test_chat_message_decode_rejects_old_timestamp() {
2301 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "TEST", "msg");
2303 let mut encoded = msg.encode();
2304 let old_ts: u64 = 1000;
2306 encoded[4..12].copy_from_slice(&old_ts.to_le_bytes());
2307
2308 assert!(ChatMessage::decode(&encoded).is_none());
2309 }
2310
2311 #[test]
2312 fn test_chat_message_decode_rejects_empty_sender() {
2313 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "X", "msg");
2315 let mut encoded = msg.encode();
2316 encoded[12] = 0;
2318 let mut raw = Vec::new();
2322 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(0); raw.push(3); raw.extend_from_slice(b"msg"); raw.push(0x01); assert!(ChatMessage::decode(&raw).is_none());
2330 }
2331
2332 #[test]
2333 fn test_chat_message_decode_rejects_invalid_utf8_sender() {
2334 let mut raw = Vec::new();
2336 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(4); raw.extend_from_slice(&[0x66, 0x59, 0xFF, 0xFE]); raw.push(3); raw.extend_from_slice(b"msg"); raw.push(0x01); raw.extend_from_slice(&0u32.to_le_bytes()); raw.extend_from_slice(&0u64.to_le_bytes()); assert!(ChatMessage::decode(&raw).is_none());
2347 }
2348
2349 #[test]
2350 fn test_chat_message_decode_rejects_invalid_utf8_text() {
2351 let mut raw = Vec::new();
2353 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(4); raw.extend_from_slice(b"TEST"); raw.push(4); raw.extend_from_slice(&[0x80, 0x81, 0x82, 0x83]); raw.push(0x01); raw.extend_from_slice(&0u32.to_le_bytes()); raw.extend_from_slice(&0u64.to_le_bytes()); assert!(ChatMessage::decode(&raw).is_none());
2364 }
2365
2366 #[test]
2367 fn test_chat_message_decode_accepts_valid_utf8() {
2368 let mut raw = Vec::new();
2370 raw.extend_from_slice(&0x12345678u32.to_le_bytes()); raw.extend_from_slice(&TEST_TIMESTAMP.to_le_bytes()); raw.push(6); raw.extend_from_slice("TËST".as_bytes()); let sender_bytes = "TËST1".as_bytes(); raw[12] = sender_bytes.len() as u8;
2377 raw.truncate(13);
2378 raw.extend_from_slice(sender_bytes);
2379 raw.push(4); raw.extend_from_slice(b"test"); raw.push(0x01); raw.extend_from_slice(&0u32.to_le_bytes()); raw.extend_from_slice(&0u64.to_le_bytes()); let result = ChatMessage::decode(&raw);
2386 assert!(result.is_some());
2387 let (msg, _) = result.unwrap();
2388 assert_eq!(msg.sender(), "TËST1");
2389 }
2390
2391 #[test]
2396 fn test_chat_crdt_new() {
2397 let chat = ChatCRDT::new();
2398 assert!(chat.is_empty());
2399 assert_eq!(chat.len(), 0);
2400 }
2401
2402 #[test]
2403 fn test_chat_crdt_add_message() {
2404 let mut chat = ChatCRDT::new();
2405
2406 let msg = ChatMessage::new(0x12345678, TEST_TIMESTAMP, "ALPHA", "Hello");
2407 assert!(chat.add_message(msg.clone()));
2408 assert_eq!(chat.len(), 1);
2409
2410 assert!(!chat.add_message(msg));
2412 assert_eq!(chat.len(), 1);
2413 }
2414
2415 #[test]
2416 fn test_chat_crdt_send_message() {
2417 let mut chat = ChatCRDT::new();
2418
2419 assert!(chat.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "First"));
2420 assert!(chat.send_message(0x2, TEST_TIMESTAMP + 1, "BRAVO", "Second"));
2421 assert_eq!(chat.len(), 2);
2422
2423 assert!(!chat.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "Duplicate"));
2425 assert_eq!(chat.len(), 2);
2426 }
2427
2428 #[test]
2429 fn test_chat_crdt_get_message() {
2430 let mut chat = ChatCRDT::new();
2431 chat.send_message(0x12345678, TEST_TIMESTAMP, "ALPHA", "Test");
2432
2433 let msg = chat.get_message(0x12345678, TEST_TIMESTAMP);
2434 assert!(msg.is_some());
2435 assert_eq!(msg.unwrap().text(), "Test");
2436
2437 assert!(chat.get_message(0x99999999, TEST_TIMESTAMP).is_none());
2439 }
2440
2441 #[test]
2442 fn test_chat_crdt_merge() {
2443 let mut chat1 = ChatCRDT::new();
2444 let mut chat2 = ChatCRDT::new();
2445
2446 chat1.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "From 1");
2447 chat2.send_message(0x2, TEST_TIMESTAMP + 1, "BRAVO", "From 2");
2448
2449 let changed = chat1.merge(&chat2);
2451 assert!(changed);
2452 assert_eq!(chat1.len(), 2);
2453
2454 let changed = chat1.merge(&chat2);
2456 assert!(!changed);
2457 assert_eq!(chat1.len(), 2);
2458 }
2459
2460 #[test]
2461 fn test_chat_crdt_merge_duplicates() {
2462 let mut chat1 = ChatCRDT::new();
2463 let mut chat2 = ChatCRDT::new();
2464
2465 chat1.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "Same message");
2467 chat2.send_message(0x1, TEST_TIMESTAMP, "ALPHA", "Same message");
2468
2469 chat1.merge(&chat2);
2471 assert_eq!(chat1.len(), 1);
2472 }
2473
2474 #[test]
2475 fn test_chat_crdt_pruning() {
2476 let mut chat = ChatCRDT::new();
2477
2478 for i in 0..(CHAT_MAX_MESSAGES + 10) {
2480 chat.send_message(i as u32 + 1, TEST_TIMESTAMP + i as u64, "X", "Y");
2481 }
2482
2483 assert_eq!(chat.len(), CHAT_MAX_MESSAGES);
2485
2486 assert!(chat.get_message(1, TEST_TIMESTAMP).is_none());
2490 assert!(chat.get_message(10, TEST_TIMESTAMP + 9).is_none());
2491 assert!(chat.get_message(11, TEST_TIMESTAMP + 10).is_some());
2493 }
2494
2495 #[test]
2496 fn test_chat_crdt_encode_decode() {
2497 let mut chat = ChatCRDT::new();
2498 chat.send_message(0x12345678, TEST_TIMESTAMP, "ALPHA", "First message");
2499 chat.send_message(0xAABBCCDD, TEST_TIMESTAMP + 1000, "BRAVO", "Second message");
2500
2501 let encoded = chat.encode();
2502 let decoded = ChatCRDT::decode(&encoded).unwrap();
2503
2504 assert_eq!(decoded.len(), 2);
2505 assert!(decoded.get_message(0x12345678, TEST_TIMESTAMP).is_some());
2506 assert!(decoded
2507 .get_message(0xAABBCCDD, TEST_TIMESTAMP + 1000)
2508 .is_some());
2509 }
2510
2511 #[test]
2512 fn test_chat_crdt_messages_since() {
2513 let mut chat = ChatCRDT::new();
2514 chat.send_message(0x1, TEST_TIMESTAMP, "A", "Old");
2515 chat.send_message(0x2, TEST_TIMESTAMP + 1000, "B", "Mid");
2516 chat.send_message(0x3, TEST_TIMESTAMP + 2000, "C", "New");
2517
2518 let recent: Vec<_> = chat.messages_since(TEST_TIMESTAMP + 500).collect();
2519 assert_eq!(recent.len(), 2);
2520 }
2521
2522 #[test]
2523 fn test_chat_crdt_newest_timestamp() {
2524 let mut chat = ChatCRDT::new();
2525 assert!(chat.newest_timestamp().is_none());
2526
2527 chat.send_message(0x1, TEST_TIMESTAMP, "A", "1");
2528 assert_eq!(chat.newest_timestamp(), Some(TEST_TIMESTAMP));
2529
2530 chat.send_message(0x2, TEST_TIMESTAMP + 2000, "B", "2");
2531 assert_eq!(chat.newest_timestamp(), Some(TEST_TIMESTAMP + 2000));
2532
2533 chat.send_message(0x3, TEST_TIMESTAMP + 1000, "C", "3"); assert_eq!(chat.newest_timestamp(), Some(TEST_TIMESTAMP + 2000));
2535 }
2536
2537 #[test]
2542 fn test_chat_crdt_decode_skips_invalid_messages() {
2543 let mut valid_chat = ChatCRDT::new();
2545 valid_chat.send_message(0x12345678, TEST_TIMESTAMP, "VALID", "Good message");
2546
2547 let encoded = valid_chat.encode();
2548
2549 let decoded = ChatCRDT::decode(&encoded).unwrap();
2551 assert_eq!(decoded.len(), 1);
2552 assert!(decoded.get_message(0x12345678, TEST_TIMESTAMP).is_some());
2553 }
2554
2555 #[test]
2556 fn test_chat_crdt_decode_handles_truncated_data() {
2557 let mut chat = ChatCRDT::new();
2558 chat.send_message(0x12345678, TEST_TIMESTAMP, "TEST", "Message");
2559
2560 let encoded = chat.encode();
2561
2562 let truncated = &encoded[..2];
2564 let decoded = ChatCRDT::decode(truncated);
2565 assert!(decoded.is_some());
2566 assert_eq!(decoded.unwrap().len(), 0); }
2568}