1use crate::node_id::NodeId;
10use crate::wire::{
11 CANNED_MESSAGE_MARKER, CANNED_MESSAGE_SIGNED_SIZE, CANNED_MESSAGE_UNSIGNED_SIZE, SIGNATURE_SIZE,
12};
13use heapless::FnvIndexMap;
14
15pub const MAX_CANNED_ACKS: usize = 64;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
31#[repr(u8)]
32pub enum CannedMessage {
33 #[default]
36 Ack = 0x00,
37 AckWilco = 0x01,
39 AckNegative = 0x02,
41 AckSayAgain = 0x03,
43
44 CheckIn = 0x10,
47 Moving = 0x11,
49 Holding = 0x12,
51 OnStation = 0x13,
53 Returning = 0x14,
55 Complete = 0x15,
57
58 Emergency = 0x20,
61 Alert = 0x21,
63 AllClear = 0x22,
65 Contact = 0x23,
67 UnderFire = 0x24,
69
70 NeedExtract = 0x30,
73 NeedSupport = 0x31,
75 NeedMedic = 0x32,
77 NeedResupply = 0x33,
79
80 Custom = 0xFF,
83}
84
85impl CannedMessage {
86 pub fn from_u8(value: u8) -> Option<Self> {
90 match value {
91 0x00 => Some(Self::Ack),
92 0x01 => Some(Self::AckWilco),
93 0x02 => Some(Self::AckNegative),
94 0x03 => Some(Self::AckSayAgain),
95 0x10 => Some(Self::CheckIn),
96 0x11 => Some(Self::Moving),
97 0x12 => Some(Self::Holding),
98 0x13 => Some(Self::OnStation),
99 0x14 => Some(Self::Returning),
100 0x15 => Some(Self::Complete),
101 0x20 => Some(Self::Emergency),
102 0x21 => Some(Self::Alert),
103 0x22 => Some(Self::AllClear),
104 0x23 => Some(Self::Contact),
105 0x24 => Some(Self::UnderFire),
106 0x30 => Some(Self::NeedExtract),
107 0x31 => Some(Self::NeedSupport),
108 0x32 => Some(Self::NeedMedic),
109 0x33 => Some(Self::NeedResupply),
110 0xFF => Some(Self::Custom),
111 _ => None,
112 }
113 }
114
115 #[inline]
117 pub const fn as_u8(self) -> u8 {
118 self as u8
119 }
120
121 #[inline]
123 pub const fn is_alert(self) -> bool {
124 matches!(
125 self,
126 Self::Emergency | Self::Alert | Self::Contact | Self::UnderFire
127 )
128 }
129
130 #[inline]
132 pub const fn is_ack(self) -> bool {
133 matches!(
134 self,
135 Self::Ack | Self::AckWilco | Self::AckNegative | Self::AckSayAgain
136 )
137 }
138
139 pub const fn short_name(self) -> &'static str {
141 match self {
142 Self::Ack => "ACK",
143 Self::AckWilco => "WILCO",
144 Self::AckNegative => "NEGATIVE",
145 Self::AckSayAgain => "SAY AGAIN",
146 Self::CheckIn => "CHECK IN",
147 Self::Moving => "MOVING",
148 Self::Holding => "HOLDING",
149 Self::OnStation => "ON STATION",
150 Self::Returning => "RTB",
151 Self::Complete => "COMPLETE",
152 Self::Emergency => "EMERGENCY",
153 Self::Alert => "ALERT",
154 Self::AllClear => "ALL CLEAR",
155 Self::Contact => "CONTACT",
156 Self::UnderFire => "UNDER FIRE",
157 Self::NeedExtract => "NEED EXTRACT",
158 Self::NeedSupport => "NEED SUPPORT",
159 Self::NeedMedic => "MEDIC",
160 Self::NeedResupply => "RESUPPLY",
161 Self::Custom => "CUSTOM",
162 }
163 }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171pub struct CannedMessageEvent {
172 pub message: CannedMessage,
174 pub source_node: NodeId,
176 pub target_node: Option<NodeId>,
178 pub timestamp: u64,
180 pub sequence: u32,
182}
183
184impl CannedMessageEvent {
185 pub fn new(
187 message: CannedMessage,
188 source_node: NodeId,
189 target_node: Option<NodeId>,
190 timestamp: u64,
191 ) -> Self {
192 Self {
193 message,
194 source_node,
195 target_node,
196 timestamp,
197 sequence: 0,
198 }
199 }
200
201 pub fn with_sequence(
203 message: CannedMessage,
204 source_node: NodeId,
205 target_node: Option<NodeId>,
206 timestamp: u64,
207 sequence: u32,
208 ) -> Self {
209 Self {
210 message,
211 source_node,
212 target_node,
213 timestamp,
214 sequence,
215 }
216 }
217
218 pub fn encode(&self) -> heapless::Vec<u8, 22> {
230 let mut buf = heapless::Vec::new();
231
232 let _ = buf.push(CANNED_MESSAGE_MARKER);
234
235 let _ = buf.push(self.message.as_u8());
237
238 for b in self.source_node.to_le_bytes() {
240 let _ = buf.push(b);
241 }
242
243 let target = self.target_node.unwrap_or(NodeId::NULL);
245 for b in target.to_le_bytes() {
246 let _ = buf.push(b);
247 }
248
249 for b in self.timestamp.to_le_bytes() {
251 let _ = buf.push(b);
252 }
253
254 for b in self.sequence.to_le_bytes() {
256 let _ = buf.push(b);
257 }
258
259 buf
260 }
261
262 pub fn decode(data: &[u8]) -> Option<Self> {
266 if data.len() < 22 {
267 return None;
268 }
269
270 if data[0] != CANNED_MESSAGE_MARKER {
271 return None;
272 }
273
274 let message = CannedMessage::from_u8(data[1])?;
275
276 let source_node = NodeId::from_le_bytes([data[2], data[3], data[4], data[5]]);
277
278 let target_bytes = [data[6], data[7], data[8], data[9]];
279 let target_node = if target_bytes == [0, 0, 0, 0] {
280 None
281 } else {
282 Some(NodeId::from_le_bytes(target_bytes))
283 };
284
285 let timestamp = u64::from_le_bytes([
286 data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17],
287 ]);
288
289 let sequence = u32::from_le_bytes([data[18], data[19], data[20], data[21]]);
290
291 Some(Self {
292 message,
293 source_node,
294 target_node,
295 timestamp,
296 sequence,
297 })
298 }
299
300 pub fn is_newer_than(&self, other: &Self) -> bool {
302 self.timestamp > other.timestamp
303 || (self.timestamp == other.timestamp && self.sequence > other.sequence)
304 }
305
306 pub fn encode_signed(&self, signature: &[u8; SIGNATURE_SIZE]) -> heapless::Vec<u8, 86> {
322 let mut buf = heapless::Vec::new();
323
324 let unsigned = self.encode();
326 for b in unsigned.iter() {
327 let _ = buf.push(*b);
328 }
329
330 for b in signature.iter() {
332 let _ = buf.push(*b);
333 }
334
335 buf
336 }
337
338 pub fn decode_signed(data: &[u8]) -> Option<(Self, [u8; SIGNATURE_SIZE])> {
349 if data.len() != CANNED_MESSAGE_SIGNED_SIZE {
350 return None;
351 }
352
353 let event = Self::decode(&data[..CANNED_MESSAGE_UNSIGNED_SIZE])?;
355
356 let mut signature = [0u8; SIGNATURE_SIZE];
358 signature.copy_from_slice(&data[CANNED_MESSAGE_UNSIGNED_SIZE..]);
359
360 Some((event, signature))
361 }
362
363 #[inline]
374 pub fn signable_payload(&self) -> heapless::Vec<u8, 22> {
375 self.encode()
376 }
377
378 #[inline]
382 pub fn is_signed_format(data: &[u8]) -> bool {
383 data.len() == CANNED_MESSAGE_SIGNED_SIZE && data.first() == Some(&CANNED_MESSAGE_MARKER)
384 }
385
386 #[inline]
388 pub fn is_unsigned_format(data: &[u8]) -> bool {
389 data.len() == CANNED_MESSAGE_UNSIGNED_SIZE && data.first() == Some(&CANNED_MESSAGE_MARKER)
390 }
391
392 pub fn decode_auto(data: &[u8]) -> Option<(Self, Option<[u8; SIGNATURE_SIZE]>)> {
400 if Self::is_signed_format(data) {
401 Self::decode_signed(data).map(|(e, s)| (e, Some(s)))
402 } else if Self::is_unsigned_format(data) {
403 Self::decode(data).map(|e| (e, None))
404 } else {
405 None
406 }
407 }
408}
409
410#[derive(Debug, Clone)]
432pub struct CannedMessageAckEvent {
433 pub message: CannedMessage,
435 pub source_node: NodeId,
437 pub target_node: Option<NodeId>,
439 pub timestamp: u64,
441 pub sequence: u32,
443 acks: FnvIndexMap<NodeId, u64, MAX_CANNED_ACKS>,
445}
446
447impl CannedMessageAckEvent {
448 pub fn new(
450 message: CannedMessage,
451 source_node: NodeId,
452 target_node: Option<NodeId>,
453 timestamp: u64,
454 ) -> Self {
455 let mut acks = FnvIndexMap::new();
456 let _ = acks.insert(source_node, timestamp);
458
459 Self {
460 message,
461 source_node,
462 target_node,
463 timestamp,
464 sequence: 0,
465 acks,
466 }
467 }
468
469 pub fn with_sequence(
471 message: CannedMessage,
472 source_node: NodeId,
473 target_node: Option<NodeId>,
474 timestamp: u64,
475 sequence: u32,
476 ) -> Self {
477 let mut event = Self::new(message, source_node, target_node, timestamp);
478 event.sequence = sequence;
479 event
480 }
481
482 pub fn ack(&mut self, node_id: NodeId, ack_timestamp: u64) -> bool {
488 if node_id == NodeId::NULL {
489 return false;
490 }
491
492 match self.acks.get(&node_id) {
493 Some(&existing_ts) if existing_ts >= ack_timestamp => false,
494 Some(_) => {
495 let _ = self.acks.insert(node_id, ack_timestamp);
497 true
498 }
499 None => {
500 self.acks.insert(node_id, ack_timestamp).is_ok()
502 }
503 }
504 }
505
506 pub fn has_acked(&self, node_id: NodeId) -> bool {
508 self.acks.contains_key(&node_id)
509 }
510
511 pub fn acked_nodes(&self) -> impl Iterator<Item = NodeId> + '_ {
513 self.acks.keys().copied()
514 }
515
516 pub fn ack_timestamp(&self, node_id: NodeId) -> Option<u64> {
518 self.acks.get(&node_id).copied()
519 }
520
521 pub fn ack_count(&self) -> usize {
523 self.acks.len()
524 }
525
526 pub fn merge(&mut self, other: &Self) -> bool {
533 if self.source_node != other.source_node || self.timestamp != other.timestamp {
535 if other.timestamp > self.timestamp {
536 *self = other.clone();
537 return true;
538 }
539 return false;
540 }
541
542 let mut changed = false;
544 for (node_id, &other_ts) in other.acks.iter() {
545 match self.acks.get(node_id) {
546 Some(&existing_ts) if existing_ts >= other_ts => {}
547 _ => {
548 if self.acks.insert(*node_id, other_ts).is_ok() {
549 changed = true;
550 }
551 }
552 }
553 }
554 changed
555 }
556
557 pub fn encode(&self) -> heapless::Vec<u8, 792> {
562 let mut buf = heapless::Vec::new();
563
564 let _ = buf.push(CANNED_MESSAGE_MARKER);
566
567 let _ = buf.push(self.message.as_u8());
569
570 for b in self.source_node.to_le_bytes() {
572 let _ = buf.push(b);
573 }
574
575 let target = self.target_node.unwrap_or(NodeId::NULL);
577 for b in target.to_le_bytes() {
578 let _ = buf.push(b);
579 }
580
581 for b in self.timestamp.to_le_bytes() {
583 let _ = buf.push(b);
584 }
585
586 for b in self.sequence.to_le_bytes() {
588 let _ = buf.push(b);
589 }
590
591 let num_acks = self.acks.len() as u16;
593 for b in num_acks.to_le_bytes() {
594 let _ = buf.push(b);
595 }
596
597 for (node_id, &ack_ts) in self.acks.iter() {
599 for b in node_id.to_le_bytes() {
600 let _ = buf.push(b);
601 }
602 for b in ack_ts.to_le_bytes() {
603 let _ = buf.push(b);
604 }
605 }
606
607 buf
608 }
609
610 pub fn decode(data: &[u8]) -> Option<Self> {
615 if data.len() < 22 {
617 return None;
618 }
619
620 if data[0] != CANNED_MESSAGE_MARKER {
621 return None;
622 }
623
624 let message = CannedMessage::from_u8(data[1])?;
625
626 let source_node = NodeId::from_le_bytes([data[2], data[3], data[4], data[5]]);
627
628 if source_node == NodeId::NULL {
630 return None;
631 }
632
633 let target_bytes = [data[6], data[7], data[8], data[9]];
634 let target_node = if target_bytes == [0, 0, 0, 0] {
635 None
636 } else {
637 Some(NodeId::from_le_bytes(target_bytes))
638 };
639
640 let timestamp = u64::from_le_bytes([
641 data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17],
642 ]);
643
644 let sequence = u32::from_le_bytes([data[18], data[19], data[20], data[21]]);
645
646 let mut acks = FnvIndexMap::new();
648 let _ = acks.insert(source_node, timestamp);
649
650 if data.len() >= 24 {
652 let num_acks = u16::from_le_bytes([data[22], data[23]]);
653
654 if num_acks as usize > MAX_CANNED_ACKS {
656 return None;
657 }
658
659 let expected_len = 24 + (num_acks as usize * 12);
660 if data.len() < expected_len {
661 return None;
662 }
663
664 let mut offset = 24;
666 for _ in 0..num_acks {
667 let acker_node = NodeId::from_le_bytes([
668 data[offset],
669 data[offset + 1],
670 data[offset + 2],
671 data[offset + 3],
672 ]);
673 let ack_ts = u64::from_le_bytes([
674 data[offset + 4],
675 data[offset + 5],
676 data[offset + 6],
677 data[offset + 7],
678 data[offset + 8],
679 data[offset + 9],
680 data[offset + 10],
681 data[offset + 11],
682 ]);
683 offset += 12;
684
685 if acker_node != NodeId::NULL {
687 let _ = acks.insert(acker_node, ack_ts);
688 }
689 }
690 }
691
692 Some(Self {
693 message,
694 source_node,
695 target_node,
696 timestamp,
697 sequence,
698 acks,
699 })
700 }
701
702 pub fn as_event(&self) -> CannedMessageEvent {
704 CannedMessageEvent {
705 message: self.message,
706 source_node: self.source_node,
707 target_node: self.target_node,
708 timestamp: self.timestamp,
709 sequence: self.sequence,
710 }
711 }
712
713 pub fn from_event(event: CannedMessageEvent) -> Self {
715 let mut acks = FnvIndexMap::new();
716 let _ = acks.insert(event.source_node, event.timestamp);
717
718 Self {
719 message: event.message,
720 source_node: event.source_node,
721 target_node: event.target_node,
722 timestamp: event.timestamp,
723 sequence: event.sequence,
724 acks,
725 }
726 }
727}
728
729impl PartialEq for CannedMessageAckEvent {
730 fn eq(&self, other: &Self) -> bool {
731 self.message == other.message
732 && self.source_node == other.source_node
733 && self.target_node == other.target_node
734 && self.timestamp == other.timestamp
735 && self.sequence == other.sequence
736 && self.acks.len() == other.acks.len()
737 && self.acks.iter().all(|(k, v)| other.acks.get(k) == Some(v))
738 }
739}
740
741impl Eq for CannedMessageAckEvent {}
742
743pub struct CannedMessageStore<const MAX_ENTRIES: usize = 256> {
751 events: FnvIndexMap<(NodeId, CannedMessage), CannedMessageEvent, MAX_ENTRIES>,
753}
754
755impl<const MAX_ENTRIES: usize> Default for CannedMessageStore<MAX_ENTRIES> {
756 fn default() -> Self {
757 Self::new()
758 }
759}
760
761impl<const MAX_ENTRIES: usize> CannedMessageStore<MAX_ENTRIES> {
762 pub const fn new() -> Self {
764 Self {
765 events: FnvIndexMap::new(),
766 }
767 }
768
769 pub fn insert(&mut self, event: CannedMessageEvent) -> bool {
774 let key = (event.source_node, event.message);
775
776 match self.events.get(&key) {
777 Some(existing) if !event.is_newer_than(existing) => false,
778 _ => {
779 if self.events.len() >= MAX_ENTRIES {
781 if let Some(oldest_key) = self.find_oldest_key() {
783 self.events.remove(&oldest_key);
784 }
785 }
786 self.events.insert(key, event).is_ok()
787 }
788 }
789 }
790
791 pub fn get(&self, source: NodeId, message: CannedMessage) -> Option<&CannedMessageEvent> {
793 self.events.get(&(source, message))
794 }
795
796 pub fn events_from(&self, source: NodeId) -> impl Iterator<Item = &CannedMessageEvent> {
798 self.events
799 .iter()
800 .filter(move |((src, _), _)| *src == source)
801 .map(|(_, event)| event)
802 }
803
804 pub fn events_of_type(
806 &self,
807 message: CannedMessage,
808 ) -> impl Iterator<Item = &CannedMessageEvent> {
809 self.events
810 .iter()
811 .filter(move |((_, msg), _)| *msg == message)
812 .map(|(_, event)| event)
813 }
814
815 pub fn alerts(&self) -> impl Iterator<Item = &CannedMessageEvent> {
817 self.events
818 .iter()
819 .filter(|((_, msg), _)| msg.is_alert())
820 .map(|(_, event)| event)
821 }
822
823 pub fn len(&self) -> usize {
825 self.events.len()
826 }
827
828 pub fn is_empty(&self) -> bool {
830 self.events.is_empty()
831 }
832
833 pub fn clear(&mut self) {
835 self.events.clear();
836 }
837
838 fn find_oldest_key(&self) -> Option<(NodeId, CannedMessage)> {
840 self.events
841 .iter()
842 .min_by_key(|(_, event)| (event.timestamp, event.sequence))
843 .map(|(key, _)| *key)
844 }
845}
846
847#[cfg(test)]
848mod tests {
849 use super::*;
850
851 #[test]
852 fn test_canned_message_roundtrip() {
853 for code in [
854 CannedMessage::Ack,
855 CannedMessage::Emergency,
856 CannedMessage::CheckIn,
857 CannedMessage::Custom,
858 ] {
859 let recovered = CannedMessage::from_u8(code.as_u8()).unwrap();
860 assert_eq!(code, recovered);
861 }
862 }
863
864 #[test]
865 fn test_event_encode_decode() {
866 let event = CannedMessageEvent::with_sequence(
867 CannedMessage::Ack,
868 NodeId::new(0x12345678),
869 Some(NodeId::new(0xDEADBEEF)),
870 1706234567000,
871 42,
872 );
873
874 let encoded = event.encode();
875 assert_eq!(encoded.len(), 22);
876 assert_eq!(encoded[0], CANNED_MESSAGE_MARKER);
877
878 let decoded = CannedMessageEvent::decode(&encoded).unwrap();
879 assert_eq!(decoded.message, event.message);
880 assert_eq!(decoded.source_node, event.source_node);
881 assert_eq!(decoded.target_node, event.target_node);
882 assert_eq!(decoded.timestamp, event.timestamp);
883 assert_eq!(decoded.sequence, event.sequence);
884 }
885
886 #[test]
887 fn test_event_no_target() {
888 let event = CannedMessageEvent::new(
889 CannedMessage::Emergency,
890 NodeId::new(0x12345678),
891 None,
892 1706234567000,
893 );
894
895 let encoded = event.encode();
896 let decoded = CannedMessageEvent::decode(&encoded).unwrap();
897 assert_eq!(decoded.target_node, None);
898 }
899
900 #[test]
901 fn test_store_lww() {
902 let mut store = CannedMessageStore::<16>::new();
903
904 let node = NodeId::new(0x123);
905
906 let event1 = CannedMessageEvent::with_sequence(CannedMessage::Ack, node, None, 1000, 1);
908 assert!(store.insert(event1));
909
910 let event_old = CannedMessageEvent::with_sequence(CannedMessage::Ack, node, None, 500, 1);
912 assert!(!store.insert(event_old));
913
914 let event2 = CannedMessageEvent::with_sequence(CannedMessage::Ack, node, None, 2000, 1);
916 assert!(store.insert(event2));
917
918 let stored = store.get(node, CannedMessage::Ack).unwrap();
919 assert_eq!(stored.timestamp, 2000);
920 }
921
922 #[test]
923 fn test_store_different_types() {
924 let mut store = CannedMessageStore::<16>::new();
925 let node = NodeId::new(0x123);
926
927 store.insert(CannedMessageEvent::new(
928 CannedMessage::Ack,
929 node,
930 None,
931 1000,
932 ));
933 store.insert(CannedMessageEvent::new(
934 CannedMessage::Emergency,
935 node,
936 None,
937 1000,
938 ));
939 store.insert(CannedMessageEvent::new(
940 CannedMessage::CheckIn,
941 node,
942 None,
943 1000,
944 ));
945
946 assert_eq!(store.len(), 3);
947 assert!(store.get(node, CannedMessage::Ack).is_some());
948 assert!(store.get(node, CannedMessage::Emergency).is_some());
949 assert!(store.get(node, CannedMessage::CheckIn).is_some());
950 }
951
952 #[test]
955 fn test_ack_event_creation() {
956 let source = NodeId::new(0x12345678);
957 let event = CannedMessageAckEvent::new(CannedMessage::CheckIn, source, None, 1706234567000);
958
959 assert!(event.has_acked(source));
961 assert_eq!(event.ack_count(), 1);
962 assert_eq!(event.ack_timestamp(source), Some(1706234567000));
963 }
964
965 #[test]
966 fn test_ack_recording() {
967 let source = NodeId::new(0x111);
968 let acker = NodeId::new(0x222);
969
970 let mut event = CannedMessageAckEvent::new(CannedMessage::Emergency, source, None, 1000);
971
972 assert!(event.ack(acker, 1500));
974 assert!(event.has_acked(acker));
975 assert_eq!(event.ack_count(), 2);
976
977 assert!(!event.ack(acker, 1500));
979
980 assert!(!event.ack(acker, 1400));
982
983 assert!(event.ack(acker, 1600));
985 assert_eq!(event.ack_timestamp(acker), Some(1600));
986
987 assert!(!event.ack(NodeId::NULL, 2000));
989 }
990
991 #[test]
992 fn test_ack_merge_same_event() {
993 let source = NodeId::new(0x111);
994 let node_a = NodeId::new(0x222);
995 let node_b = NodeId::new(0x333);
996
997 let mut event1 = CannedMessageAckEvent::new(CannedMessage::CheckIn, source, None, 1000);
999 event1.ack(node_a, 1100);
1000
1001 let mut event2 = CannedMessageAckEvent::new(CannedMessage::CheckIn, source, None, 1000);
1003 event2.ack(node_b, 1200);
1004
1005 let changed = event1.merge(&event2);
1007 assert!(changed);
1008 assert!(event1.has_acked(source));
1009 assert!(event1.has_acked(node_a));
1010 assert!(event1.has_acked(node_b));
1011 assert_eq!(event1.ack_count(), 3);
1012
1013 assert!(!event1.merge(&event2));
1015 }
1016
1017 #[test]
1018 fn test_ack_merge_different_event() {
1019 let source = NodeId::new(0x111);
1020 let acker = NodeId::new(0x222);
1021
1022 let mut older = CannedMessageAckEvent::new(CannedMessage::CheckIn, source, None, 1000);
1024 older.ack(acker, 1100);
1025
1026 let newer = CannedMessageAckEvent::new(
1028 CannedMessage::Alert, source,
1030 None,
1031 2000,
1032 );
1033
1034 let changed = older.merge(&newer);
1036 assert!(changed);
1037 assert_eq!(older.timestamp, 2000);
1038 assert_eq!(older.message, CannedMessage::Alert);
1039 assert!(!older.has_acked(acker));
1041 assert_eq!(older.ack_count(), 1);
1042
1043 let mut newer2 = CannedMessageAckEvent::new(CannedMessage::Alert, source, None, 2000);
1045 let older2 = CannedMessageAckEvent::new(CannedMessage::CheckIn, source, None, 1000);
1046 assert!(!newer2.merge(&older2));
1047 }
1048
1049 #[test]
1050 fn test_ack_encode_decode() {
1051 let source = NodeId::new(0x12345678);
1052 let target = NodeId::new(0xDEADBEEF);
1053 let acker1 = NodeId::new(0xAAAA);
1054 let acker2 = NodeId::new(0xBBBB);
1055
1056 let mut event = CannedMessageAckEvent::with_sequence(
1057 CannedMessage::Emergency,
1058 source,
1059 Some(target),
1060 1706234567000,
1061 42,
1062 );
1063 event.ack(acker1, 1706234568000);
1064 event.ack(acker2, 1706234569000);
1065
1066 let encoded = event.encode();
1067 assert_eq!(encoded.len(), 24 + 3 * 12);
1069 assert_eq!(encoded[0], CANNED_MESSAGE_MARKER);
1070
1071 let decoded = CannedMessageAckEvent::decode(&encoded).unwrap();
1072 assert_eq!(decoded.message, event.message);
1073 assert_eq!(decoded.source_node, event.source_node);
1074 assert_eq!(decoded.target_node, event.target_node);
1075 assert_eq!(decoded.timestamp, event.timestamp);
1076 assert_eq!(decoded.sequence, event.sequence);
1077 assert_eq!(decoded.ack_count(), 3);
1078 assert!(decoded.has_acked(source));
1079 assert!(decoded.has_acked(acker1));
1080 assert!(decoded.has_acked(acker2));
1081 assert_eq!(decoded.ack_timestamp(acker1), Some(1706234568000));
1082 assert_eq!(decoded.ack_timestamp(acker2), Some(1706234569000));
1083 }
1084
1085 #[test]
1086 fn test_ack_decode_base_event() {
1087 let base_event = CannedMessageEvent::with_sequence(
1089 CannedMessage::CheckIn,
1090 NodeId::new(0x12345678),
1091 None,
1092 1706234567000,
1093 5,
1094 );
1095
1096 let encoded = base_event.encode();
1097 assert_eq!(encoded.len(), 22);
1098
1099 let decoded = CannedMessageAckEvent::decode(&encoded).unwrap();
1101 assert_eq!(decoded.message, base_event.message);
1102 assert_eq!(decoded.source_node, base_event.source_node);
1103 assert_eq!(decoded.timestamp, base_event.timestamp);
1104 assert_eq!(decoded.sequence, base_event.sequence);
1105 assert_eq!(decoded.ack_count(), 1);
1107 assert!(decoded.has_acked(base_event.source_node));
1108 }
1109
1110 #[test]
1111 fn test_ack_max_limit() {
1112 let source = NodeId::new(0x111);
1113 let mut event = CannedMessageAckEvent::new(CannedMessage::Emergency, source, None, 1000);
1114
1115 for i in 1..MAX_CANNED_ACKS {
1117 let acker = NodeId::new(i as u32 + 1000);
1118 assert!(
1119 event.ack(acker, 2000 + i as u64),
1120 "ack {} should succeed",
1121 i
1122 );
1123 }
1124
1125 assert_eq!(event.ack_count(), MAX_CANNED_ACKS);
1126
1127 let overflow_acker = NodeId::new(0xFFFFFF);
1129 assert!(!event.ack(overflow_acker, 9999));
1130 assert!(!event.has_acked(overflow_acker));
1131 }
1132
1133 #[test]
1134 fn test_ack_validation() {
1135 assert!(CannedMessageAckEvent::decode(&[0xAF]).is_none());
1137 assert!(CannedMessageAckEvent::decode(&[0xAF; 21]).is_none());
1138
1139 let mut bad_marker = [0u8; 22];
1141 bad_marker[0] = 0x00;
1142 assert!(CannedMessageAckEvent::decode(&bad_marker).is_none());
1143
1144 let mut null_source = [0u8; 22];
1146 null_source[0] = CANNED_MESSAGE_MARKER;
1147 null_source[1] = CannedMessage::Ack.as_u8();
1148 assert!(CannedMessageAckEvent::decode(&null_source).is_none());
1150
1151 let mut bad_code = [0u8; 22];
1153 bad_code[0] = CANNED_MESSAGE_MARKER;
1154 bad_code[1] = 0xEE; bad_code[2] = 1; assert!(CannedMessageAckEvent::decode(&bad_code).is_none());
1157
1158 let mut excessive_acks = [0u8; 24];
1160 excessive_acks[0] = CANNED_MESSAGE_MARKER;
1161 excessive_acks[1] = CannedMessage::Ack.as_u8();
1162 excessive_acks[2] = 1; excessive_acks[22] = 0xFF;
1165 excessive_acks[23] = 0xFF;
1166 assert!(CannedMessageAckEvent::decode(&excessive_acks).is_none());
1167
1168 let mut truncated = [0u8; 24];
1170 truncated[0] = CANNED_MESSAGE_MARKER;
1171 truncated[1] = CannedMessage::Ack.as_u8();
1172 truncated[2] = 1; truncated[22] = 5; truncated[23] = 0;
1175 assert!(CannedMessageAckEvent::decode(&truncated).is_none());
1176 }
1177
1178 #[test]
1179 fn test_ack_event_as_event_roundtrip() {
1180 let source = NodeId::new(0x12345678);
1181 let target = NodeId::new(0xDEADBEEF);
1182
1183 let ack_event = CannedMessageAckEvent::with_sequence(
1184 CannedMessage::NeedMedic,
1185 source,
1186 Some(target),
1187 1706234567000,
1188 99,
1189 );
1190
1191 let base = ack_event.as_event();
1192 assert_eq!(base.message, CannedMessage::NeedMedic);
1193 assert_eq!(base.source_node, source);
1194 assert_eq!(base.target_node, Some(target));
1195 assert_eq!(base.timestamp, 1706234567000);
1196 assert_eq!(base.sequence, 99);
1197
1198 let restored = CannedMessageAckEvent::from_event(base);
1200 assert_eq!(restored.message, ack_event.message);
1201 assert_eq!(restored.source_node, ack_event.source_node);
1202 assert_eq!(restored.target_node, ack_event.target_node);
1203 assert_eq!(restored.timestamp, ack_event.timestamp);
1204 assert_eq!(restored.sequence, ack_event.sequence);
1205 assert_eq!(restored.ack_count(), 1);
1207 assert!(restored.has_acked(source));
1208 }
1209
1210 #[test]
1211 fn test_ack_event_acked_nodes_iterator() {
1212 let source = NodeId::new(0x111);
1213 let mut event = CannedMessageAckEvent::new(CannedMessage::CheckIn, source, None, 1000);
1214 event.ack(NodeId::new(0x222), 1100);
1215 event.ack(NodeId::new(0x333), 1200);
1216
1217 let nodes: heapless::Vec<NodeId, 8> = event.acked_nodes().collect();
1218 assert_eq!(nodes.len(), 3);
1219 assert!(nodes.contains(&source));
1220 assert!(nodes.contains(&NodeId::new(0x222)));
1221 assert!(nodes.contains(&NodeId::new(0x333)));
1222 }
1223
1224 #[test]
1227 fn test_signed_event_encode_decode() {
1228 let event = CannedMessageEvent::with_sequence(
1229 CannedMessage::Emergency,
1230 NodeId::new(0x12345678),
1231 Some(NodeId::new(0xDEADBEEF)),
1232 1706234567000,
1233 42,
1234 );
1235
1236 let signature = [0xABu8; 64];
1238
1239 let encoded = event.encode_signed(&signature);
1240 assert_eq!(encoded.len(), 86);
1241 assert_eq!(encoded[0], CANNED_MESSAGE_MARKER);
1242
1243 let (decoded, decoded_sig) = CannedMessageEvent::decode_signed(&encoded).unwrap();
1244 assert_eq!(decoded.message, event.message);
1245 assert_eq!(decoded.source_node, event.source_node);
1246 assert_eq!(decoded.target_node, event.target_node);
1247 assert_eq!(decoded.timestamp, event.timestamp);
1248 assert_eq!(decoded.sequence, event.sequence);
1249 assert_eq!(decoded_sig, signature);
1250 }
1251
1252 #[test]
1253 fn test_signed_format_detection() {
1254 let event = CannedMessageEvent::new(
1255 CannedMessage::CheckIn,
1256 NodeId::new(0x12345678),
1257 None,
1258 1706234567000,
1259 );
1260
1261 let unsigned = event.encode();
1263 assert!(CannedMessageEvent::is_unsigned_format(&unsigned));
1264 assert!(!CannedMessageEvent::is_signed_format(&unsigned));
1265
1266 let signature = [0x00u8; 64];
1268 let signed = event.encode_signed(&signature);
1269 assert!(CannedMessageEvent::is_signed_format(&signed));
1270 assert!(!CannedMessageEvent::is_unsigned_format(&signed));
1271
1272 assert!(!CannedMessageEvent::is_signed_format(&[0xAF; 50]));
1274 assert!(!CannedMessageEvent::is_unsigned_format(&[0xAF; 50]));
1275 assert!(!CannedMessageEvent::is_signed_format(&[0x00; 86])); }
1277
1278 #[test]
1279 fn test_decode_auto() {
1280 let event = CannedMessageEvent::with_sequence(
1281 CannedMessage::Alert,
1282 NodeId::new(0xAAAA),
1283 None,
1284 1000,
1285 5,
1286 );
1287
1288 let unsigned = event.encode();
1290 let (decoded, sig_opt) = CannedMessageEvent::decode_auto(&unsigned).unwrap();
1291 assert_eq!(decoded.message, event.message);
1292 assert!(sig_opt.is_none());
1293
1294 let signature = [0xFFu8; 64];
1296 let signed = event.encode_signed(&signature);
1297 let (decoded, sig_opt) = CannedMessageEvent::decode_auto(&signed).unwrap();
1298 assert_eq!(decoded.message, event.message);
1299 assert_eq!(sig_opt, Some(signature));
1300
1301 assert!(CannedMessageEvent::decode_auto(&[0xAF; 50]).is_none());
1303 }
1304
1305 #[test]
1306 fn test_signable_payload() {
1307 let event = CannedMessageEvent::new(
1308 CannedMessage::Moving,
1309 NodeId::new(0x12345678),
1310 None,
1311 1706234567000,
1312 );
1313
1314 let payload = event.signable_payload();
1315 let encoded = event.encode();
1316
1317 assert_eq!(payload.as_slice(), encoded.as_slice());
1319 assert_eq!(payload.len(), 22);
1320 }
1321
1322 #[test]
1323 fn test_signed_decode_wrong_size() {
1324 assert!(CannedMessageEvent::decode_signed(&[0xAF; 85]).is_none());
1326
1327 assert!(CannedMessageEvent::decode_signed(&[0xAF; 87]).is_none());
1329
1330 let mut bad = [0u8; 86];
1332 bad[0] = 0x00;
1333 assert!(CannedMessageEvent::decode_signed(&bad).is_none());
1334 }
1335
1336 #[test]
1337 fn test_wire_size_constants() {
1338 use crate::wire::{
1339 CANNED_MESSAGE_SIGNED_SIZE, CANNED_MESSAGE_UNSIGNED_SIZE, SIGNATURE_SIZE,
1340 };
1341
1342 assert_eq!(CANNED_MESSAGE_UNSIGNED_SIZE, 22);
1343 assert_eq!(SIGNATURE_SIZE, 64);
1344 assert_eq!(CANNED_MESSAGE_SIGNED_SIZE, 86);
1345 assert_eq!(
1346 CANNED_MESSAGE_SIGNED_SIZE,
1347 CANNED_MESSAGE_UNSIGNED_SIZE + SIGNATURE_SIZE
1348 );
1349 }
1350}