1use bon::bon;
7use zerocopy::FromBytes;
8use zerocopy::Immutable;
9use zerocopy::IntoBytes;
10use zerocopy::KnownLayout;
11use zerocopy::Unaligned;
12use zerocopy::byteorder::network_endian::U16;
13
14use crate::ids::Scid;
15use crate::utils::get_bits_u8;
16use crate::utils::get_bits_u16;
17use crate::utils::set_bits_u8;
18use crate::utils::set_bits_u16;
19
20#[repr(C, packed)]
45#[derive(FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
46pub struct Proximity1TransferFrame {
47 header: Proximity1Header,
48 data_field: [u8],
49}
50
51#[repr(C)]
53#[derive(
54 FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable,
55 Debug, Copy, Clone,
56)]
57pub struct Proximity1Header {
58 version_qos_pdu_dfc_scid: U16,
60 pcid_port_srcdst_len: U16,
62 fsn: u8,
64}
65
66#[rustfmt::skip]
68pub mod bitmask {
69 pub const VERSION_MASK: u16 = 0b_1100_0000_0000_0000;
72 pub const QOS_MASK: u16 = 0b_0010_0000_0000_0000;
74 pub const PDU_TYPE_MASK: u16 = 0b_0001_0000_0000_0000;
76 pub const DFC_ID_MASK: u16 = 0b_0000_1100_0000_0000;
78 pub const SCID_MASK: u16 = 0b_0000_0011_1111_1111;
80
81 pub const PCID_MASK: u16 = 0b_1000_0000_0000_0000;
84 pub const PORT_ID_MASK: u16 = 0b_0111_0000_0000_0000;
86 pub const SRC_DEST_MASK: u16 = 0b_0000_1000_0000_0000;
88 pub const FRAME_LEN_MASK: u16 = 0b_0000_0111_1111_1111;
90}
91
92use bitmask::*;
93
94#[derive(Debug, Copy, Clone, Eq, PartialEq)]
96#[repr(u8)]
97pub enum QoS {
98 SequenceControlled = 0,
100 Expedited = 1,
102}
103
104#[derive(Debug, Copy, Clone, Eq, PartialEq)]
106#[repr(u8)]
107pub enum PduType {
108 UserData = 0,
110 Supervisory = 1,
112}
113
114#[derive(Debug, Copy, Clone, Eq, PartialEq)]
119#[repr(u8)]
120pub enum DfcId {
121 Packets = 0b00,
123 Segments = 0b01,
125 Reserved = 0b10,
127 UserDefined = 0b11,
129}
130
131#[derive(Debug, Copy, Clone, Eq, PartialEq)]
133#[repr(u8)]
134pub enum SrcDest {
135 Source = 0,
137 Destination = 1,
139}
140
141#[derive(Debug, Copy, Clone, Eq, PartialEq)]
143pub enum BuildError {
144 InvalidScid(Scid),
146 InvalidPortId(u8),
148 DataTooLong(usize),
150 BufferTooSmall {
152 required: usize,
154 provided: usize,
156 },
157}
158
159#[derive(Debug, Copy, Clone, Eq, PartialEq)]
161pub enum ParseError {
162 TooShortForHeader {
164 actual: usize,
166 },
167 IncompleteFrame {
169 header_len: usize,
171 buffer_len: usize,
173 },
174 InvalidVersion(u8),
176}
177
178pub const PROXIMITY1_VERSION: u8 = 0b10;
180
181pub const MAX_FRAME_LEN: usize = 2048;
183
184pub const MAX_DATA_FIELD_LEN: usize = 2043;
186
187#[bon]
188impl Proximity1TransferFrame {
189 pub const HEADER_SIZE: usize = 5;
191
192 pub fn parse(bytes: &[u8]) -> Result<&Self, ParseError> {
194 if bytes.len() < Self::HEADER_SIZE {
195 return Err(ParseError::TooShortForHeader {
196 actual: bytes.len(),
197 });
198 }
199
200 let (header, _) =
201 Proximity1Header::ref_from_prefix(bytes).unwrap();
202 let total = header.frame_len();
203
204 if total > bytes.len() {
205 return Err(ParseError::IncompleteFrame {
206 header_len: total,
207 buffer_len: bytes.len(),
208 });
209 }
210
211 let version = header.version();
212 if version != PROXIMITY1_VERSION {
213 return Err(ParseError::InvalidVersion(version));
214 }
215
216 Ok(Self::ref_from_bytes(&bytes[..total]).unwrap())
217 }
218
219 pub fn parse_mut(
221 bytes: &mut [u8],
222 ) -> Result<&mut Self, ParseError> {
223 if bytes.len() < Self::HEADER_SIZE {
224 return Err(ParseError::TooShortForHeader {
225 actual: bytes.len(),
226 });
227 }
228
229 let (header, _) =
230 Proximity1Header::ref_from_prefix(bytes).unwrap();
231 let total = header.frame_len();
232 let version = header.version();
233
234 if total > bytes.len() {
235 return Err(ParseError::IncompleteFrame {
236 header_len: total,
237 buffer_len: bytes.len(),
238 });
239 }
240 if version != PROXIMITY1_VERSION {
241 return Err(ParseError::InvalidVersion(version));
242 }
243
244 Ok(Self::mut_from_bytes(&mut bytes[..total]).unwrap())
245 }
246
247 pub fn header(&self) -> &Proximity1Header {
249 &self.header
250 }
251
252 pub fn data_field(&self) -> &[u8] {
254 &self.data_field
255 }
256
257 pub fn data_field_mut(&mut self) -> &mut [u8] {
259 &mut self.data_field
260 }
261
262 pub fn frame_len(&self) -> usize {
264 Self::HEADER_SIZE + self.data_field.len()
265 }
266
267 #[builder]
269 pub fn new(
270 buffer: &mut [u8],
271 scid: Scid,
272 qos: QoS,
273 pdu_type: PduType,
274 dfc_id: DfcId,
275 pcid: bool,
276 port_id: u8,
277 src_dest: SrcDest,
278 fsn: u8,
279 data_field_len: usize,
280 ) -> Result<&mut Self, BuildError> {
281 if scid.num_bits() > 10 {
282 return Err(BuildError::InvalidScid(scid));
283 }
284 if port_id > 0x07 {
285 return Err(BuildError::InvalidPortId(port_id));
286 }
287 if data_field_len > MAX_DATA_FIELD_LEN {
288 return Err(BuildError::DataTooLong(data_field_len));
289 }
290
291 let total_len = Self::HEADER_SIZE + data_field_len;
292 if buffer.len() < total_len {
293 return Err(BuildError::BufferTooSmall {
294 required: total_len,
295 provided: buffer.len(),
296 });
297 }
298
299 let frame_buf = &mut buffer[..total_len];
300 let frame = Self::mut_from_bytes(frame_buf).unwrap();
301
302 frame.header.set_version(PROXIMITY1_VERSION);
303 frame.header.set_qos(qos);
304 frame.header.set_pdu_type(pdu_type);
305 frame.header.set_dfc_id(dfc_id);
306 frame.header.set_scid(scid);
307 frame.header.set_pcid(pcid);
308 frame.header.set_port_id(port_id);
309 frame.header.set_src_dest(src_dest);
310 frame.header.set_frame_len(total_len);
311 frame.header.set_fsn(fsn);
312
313 Ok(frame)
314 }
315}
316
317impl Proximity1Header {
320 pub fn version(&self) -> u8 {
322 get_bits_u16(self.version_qos_pdu_dfc_scid, VERSION_MASK)
323 as u8
324 }
325 pub fn set_version(&mut self, v: u8) {
327 set_bits_u16(
328 &mut self.version_qos_pdu_dfc_scid,
329 VERSION_MASK,
330 v as u16,
331 );
332 }
333
334 pub fn qos(&self) -> QoS {
336 if get_bits_u16(self.version_qos_pdu_dfc_scid, QOS_MASK) == 1
337 {
338 QoS::Expedited
339 } else {
340 QoS::SequenceControlled
341 }
342 }
343 pub fn set_qos(&mut self, qos: QoS) {
345 set_bits_u16(
346 &mut self.version_qos_pdu_dfc_scid,
347 QOS_MASK,
348 qos as u16,
349 );
350 }
351
352 pub fn pdu_type(&self) -> PduType {
354 if get_bits_u16(self.version_qos_pdu_dfc_scid, PDU_TYPE_MASK)
355 == 1
356 {
357 PduType::Supervisory
358 } else {
359 PduType::UserData
360 }
361 }
362 pub fn set_pdu_type(&mut self, t: PduType) {
364 set_bits_u16(
365 &mut self.version_qos_pdu_dfc_scid,
366 PDU_TYPE_MASK,
367 t as u16,
368 );
369 }
370
371 pub fn dfc_id(&self) -> DfcId {
373 let v = get_bits_u16(
374 self.version_qos_pdu_dfc_scid,
375 DFC_ID_MASK,
376 );
377 match v {
378 0b00 => DfcId::Packets,
379 0b01 => DfcId::Segments,
380 0b10 => DfcId::Reserved,
381 _ => DfcId::UserDefined,
382 }
383 }
384 pub fn set_dfc_id(&mut self, dfc: DfcId) {
386 set_bits_u16(
387 &mut self.version_qos_pdu_dfc_scid,
388 DFC_ID_MASK,
389 dfc as u16,
390 );
391 }
392
393 pub fn scid(&self) -> Scid {
395 Scid::new(get_bits_u16(self.version_qos_pdu_dfc_scid, SCID_MASK) as u32)
396 }
397 pub fn set_scid(&mut self, scid: Scid) {
399 set_bits_u16(
400 &mut self.version_qos_pdu_dfc_scid,
401 SCID_MASK,
402 scid.get() as u16,
403 );
404 }
405
406 pub fn pcid(&self) -> bool {
408 get_bits_u16(self.pcid_port_srcdst_len, PCID_MASK) != 0
409 }
410 pub fn set_pcid(&mut self, pcid: bool) {
412 set_bits_u16(
413 &mut self.pcid_port_srcdst_len,
414 PCID_MASK,
415 u16::from(pcid),
416 );
417 }
418
419 pub fn port_id(&self) -> u8 {
421 get_bits_u16(self.pcid_port_srcdst_len, PORT_ID_MASK) as u8
422 }
423 pub fn set_port_id(&mut self, id: u8) {
425 set_bits_u16(
426 &mut self.pcid_port_srcdst_len,
427 PORT_ID_MASK,
428 id as u16,
429 );
430 }
431
432 pub fn src_dest(&self) -> SrcDest {
434 if get_bits_u16(self.pcid_port_srcdst_len, SRC_DEST_MASK) == 1
435 {
436 SrcDest::Destination
437 } else {
438 SrcDest::Source
439 }
440 }
441 pub fn set_src_dest(&mut self, sd: SrcDest) {
443 set_bits_u16(
444 &mut self.pcid_port_srcdst_len,
445 SRC_DEST_MASK,
446 sd as u16,
447 );
448 }
449
450 pub fn frame_len(&self) -> usize {
454 get_bits_u16(self.pcid_port_srcdst_len, FRAME_LEN_MASK)
455 as usize
456 + 1
457 }
458 pub fn set_frame_len(&mut self, len: usize) {
460 set_bits_u16(
461 &mut self.pcid_port_srcdst_len,
462 FRAME_LEN_MASK,
463 (len - 1) as u16,
464 );
465 }
466
467 pub fn fsn(&self) -> u8 {
469 self.fsn
470 }
471 pub fn set_fsn(&mut self, fsn: u8) {
473 self.fsn = fsn;
474 }
475}
476
477#[rustfmt::skip]
495pub mod plcw_bitmask {
496 pub const FORMAT_ID_MASK: u16 = 0b_1000_0000_0000_0000;
498 pub const TYPE_ID_MASK: u16 = 0b_0100_0000_0000_0000;
500 pub const RETRANSMIT_MASK: u16 = 0b_0010_0000_0000_0000;
502 pub const PLCW_PCID_MASK: u16 = 0b_0001_0000_0000_0000;
504 pub const _RESERVED_MASK: u16 = 0b_0000_1000_0000_0000;
506 pub const EXP_COUNTER_MASK: u16 = 0b_0000_0111_0000_0000;
508 pub const REPORT_VALUE_MASK: u16 = 0b_0000_0000_1111_1111;
510}
511
512#[derive(Debug, Copy, Clone, Eq, PartialEq)]
518pub struct Plcw(u16);
519
520impl Plcw {
521 pub fn new(
523 retransmit: bool,
524 pcid: bool,
525 expedited_counter: u8,
526 report_value: u8,
527 ) -> Self {
528 use plcw_bitmask::*;
529 let mut val = 0u16;
530 val |= FORMAT_ID_MASK;
532 if retransmit {
534 val |= RETRANSMIT_MASK;
535 }
536 if pcid {
537 val |= PLCW_PCID_MASK;
538 }
539 val |= ((expedited_counter & 0x07) as u16)
540 << EXP_COUNTER_MASK.trailing_zeros();
541 val |= report_value as u16;
542 Self(val)
543 }
544
545 pub fn from_bytes(bytes: &[u8; 2]) -> Self {
547 Self(u16::from_be_bytes(*bytes))
548 }
549
550 pub fn to_bytes(self) -> [u8; 2] {
552 self.0.to_be_bytes()
553 }
554
555 pub fn raw(self) -> u16 {
557 self.0
558 }
559
560 pub fn retransmit(&self) -> bool {
564 self.0 & plcw_bitmask::RETRANSMIT_MASK != 0
565 }
566
567 pub fn pcid(&self) -> bool {
569 self.0 & plcw_bitmask::PLCW_PCID_MASK != 0
570 }
571
572 pub fn expedited_counter(&self) -> u8 {
574 ((self.0 & plcw_bitmask::EXP_COUNTER_MASK)
575 >> plcw_bitmask::EXP_COUNTER_MASK.trailing_zeros())
576 as u8
577 }
578
579 pub fn report_value(&self) -> u8 {
583 (self.0 & plcw_bitmask::REPORT_VALUE_MASK) as u8
584 }
585}
586
587impl core::fmt::Display for Plcw {
588 fn fmt(
589 &self,
590 f: &mut core::fmt::Formatter<'_>,
591 ) -> core::fmt::Result {
592 write!(
593 f,
594 "PLCW[rt={} pcid={} exp={} vr={}]",
595 self.retransmit() as u8,
596 self.pcid() as u8,
597 self.expedited_counter(),
598 self.report_value(),
599 )
600 }
601}
602
603#[rustfmt::skip]
613pub mod segment_bitmask {
614 pub const FLAGS_MASK: u8 = 0b_1100_0000;
616 pub const PSEUDO_PACKET_ID_MASK: u8 = 0b_0011_1111;
618}
619
620#[derive(Debug, Copy, Clone, Eq, PartialEq)]
622#[repr(u8)]
623pub enum SequenceFlag {
624 First = 0b01,
626 Continuation = 0b00,
628 Last = 0b10,
630 Unsegmented = 0b11,
632}
633
634#[derive(Debug, Copy, Clone, Eq, PartialEq)]
636pub struct SegmentHeader(u8);
637
638impl SegmentHeader {
639 pub fn new(flags: SequenceFlag, pseudo_packet_id: u8) -> Self {
641 let mut val = 0u8;
642 set_bits_u8(&mut val, segment_bitmask::FLAGS_MASK, flags as u8);
643 set_bits_u8(&mut val, segment_bitmask::PSEUDO_PACKET_ID_MASK, pseudo_packet_id);
644 Self(val)
645 }
646
647 pub fn from_byte(b: u8) -> Self {
649 Self(b)
650 }
651
652 pub fn to_byte(self) -> u8 {
654 self.0
655 }
656
657 pub fn flags(&self) -> SequenceFlag {
659 match get_bits_u8(self.0, segment_bitmask::FLAGS_MASK) {
660 0b01 => SequenceFlag::First,
661 0b00 => SequenceFlag::Continuation,
662 0b10 => SequenceFlag::Last,
663 _ => SequenceFlag::Unsegmented,
664 }
665 }
666
667 pub fn pseudo_packet_id(&self) -> u8 {
669 get_bits_u8(self.0, segment_bitmask::PSEUDO_PACKET_ID_MASK)
670 }
671}
672
673impl core::fmt::Display for Proximity1Header {
676 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
677 write!(
678 f,
679 "Prox1[v={} qos={:?} pdu={:?} dfc={:?} scid={} \
680 pcid={} port={} sd={:?} len={} fsn={}]",
681 self.version(),
682 self.qos(),
683 self.pdu_type(),
684 self.dfc_id(),
685 self.scid(),
686 self.pcid() as u8,
687 self.port_id(),
688 self.src_dest(),
689 self.frame_len(),
690 self.fsn(),
691 )
692 }
693}
694
695impl core::fmt::Display for Proximity1TransferFrame {
696 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
697 write!(
698 f,
699 "{} data=[{}B]",
700 self.header,
701 self.data_field.len(),
702 )
703 }
704}
705
706use super::super::{FrameRead, FrameWrite, PushError};
709
710#[derive(Debug, Clone)]
712pub struct Prox1FrameWriterConfig {
713 pub scid: Scid,
715 pub qos: QoS,
717 pub pdu_type: PduType,
719 pub dfc_id: DfcId,
721 pub pcid: bool,
723 pub port_id: u8,
725 pub src_dest: SrcDest,
727 pub max_data_field_len: usize,
729}
730
731pub struct Prox1FrameWriter<const BUF: usize> {
738 config: Prox1FrameWriterConfig,
739 fsn: u8,
740 data_len: usize,
741 buf: [u8; BUF],
742}
743
744impl<const BUF: usize> Prox1FrameWriter<BUF> {
745 pub fn new(config: Prox1FrameWriterConfig) -> Self {
747 Self {
748 config,
749 fsn: 0,
750 data_len: 0,
751 buf: [0u8; BUF],
752 }
753 }
754}
755
756impl<const BUF: usize> Prox1FrameWriter<BUF> {
757 fn remaining(&self) -> usize {
758 self.config.max_data_field_len.saturating_sub(self.data_len)
759 }
760}
761
762impl<const BUF: usize> FrameWrite for Prox1FrameWriter<BUF> {
763 type Error = BuildError;
764
765 fn is_empty(&self) -> bool {
766 self.data_len == 0
767 }
768
769 fn push(&mut self, data: &[u8]) -> Result<(), PushError> {
770 if data.len() > self.config.max_data_field_len {
771 return Err(PushError::TooLarge);
772 }
773 if data.len() > self.remaining() {
774 return Err(PushError::Full);
775 }
776 let off =
777 Proximity1TransferFrame::HEADER_SIZE + self.data_len;
778 self.buf[off..off + data.len()].copy_from_slice(data);
779 self.data_len += data.len();
780 Ok(())
781 }
782
783 fn finish(&mut self) -> Result<&[u8], BuildError> {
784 let total =
785 Proximity1TransferFrame::HEADER_SIZE + self.data_len;
786 let fsn = self.fsn;
787 self.fsn = self.fsn.wrapping_add(1);
788
789 Proximity1TransferFrame::builder()
790 .buffer(&mut self.buf[..total])
791 .scid(self.config.scid)
792 .qos(self.config.qos)
793 .pdu_type(self.config.pdu_type)
794 .dfc_id(self.config.dfc_id)
795 .pcid(self.config.pcid)
796 .port_id(self.config.port_id)
797 .src_dest(self.config.src_dest)
798 .fsn(fsn)
799 .data_field_len(self.data_len)
800 .build()?;
801
802 self.data_len = 0;
803 Ok(&self.buf[..total])
804 }
805}
806
807pub struct Prox1FrameReader<const BUF: usize> {
815 buf: [u8; BUF],
816 data_start: usize,
817 data_end: usize,
818}
819
820impl<const BUF: usize> Prox1FrameReader<BUF> {
821 pub fn new() -> Self {
823 Self {
824 buf: [0u8; BUF],
825 data_start: 0,
826 data_end: 0,
827 }
828 }
829}
830
831impl<const BUF: usize> FrameRead for Prox1FrameReader<BUF> {
832 type Error = ParseError;
833
834 fn buffer_mut(&mut self) -> &mut [u8] {
835 &mut self.buf
836 }
837
838 fn feed(&mut self, len: usize) -> Result<(), ParseError> {
839 let parsed =
840 Proximity1TransferFrame::parse(&self.buf[..len])?;
841 let data = parsed.data_field();
842 self.data_start = Proximity1TransferFrame::HEADER_SIZE;
843 self.data_end = self.data_start + data.len();
844 Ok(())
845 }
846
847 fn data_field(&self) -> &[u8] {
848 &self.buf[self.data_start..self.data_end]
849 }
850}
851
852#[cfg(test)]
853mod tests {
854 use super::*;
855 use crate::ids::Scid;
856
857 #[test]
858 fn build_and_parse_u_frame() {
859 let mut buf = [0u8; 256];
860 let payload = [0xDE, 0xAD, 0xBE, 0xEF];
861
862 let frame = Proximity1TransferFrame::builder()
863 .buffer(&mut buf)
864 .scid(Scid::new(42))
865 .qos(QoS::SequenceControlled)
866 .pdu_type(PduType::UserData)
867 .dfc_id(DfcId::Packets)
868 .pcid(false)
869 .port_id(3)
870 .src_dest(SrcDest::Source)
871 .fsn(0x7F)
872 .data_field_len(payload.len())
873 .build()
874 .unwrap();
875
876 frame.data_field_mut().copy_from_slice(&payload);
877
878 assert_eq!(frame.header().version(), PROXIMITY1_VERSION);
879 assert_eq!(frame.header().qos(), QoS::SequenceControlled);
880 assert_eq!(frame.header().pdu_type(), PduType::UserData);
881 assert_eq!(frame.header().dfc_id(), DfcId::Packets);
882 assert_eq!(frame.header().scid(), Scid::new(42));
883 assert!(!frame.header().pcid());
884 assert_eq!(frame.header().port_id(), 3);
885 assert_eq!(frame.header().src_dest(), SrcDest::Source);
886 assert_eq!(frame.header().frame_len(), 5 + payload.len());
887 assert_eq!(frame.header().fsn(), 0x7F);
888 assert_eq!(frame.data_field(), &payload);
889 }
890
891 #[test]
892 fn build_and_parse_p_frame() {
893 let mut buf = [0u8; 64];
894
895 let frame = Proximity1TransferFrame::builder()
896 .buffer(&mut buf)
897 .scid(Scid::new(1023))
898 .qos(QoS::Expedited)
899 .pdu_type(PduType::Supervisory)
900 .dfc_id(DfcId::Packets) .pcid(true)
902 .port_id(0) .src_dest(SrcDest::Destination)
904 .fsn(255)
905 .data_field_len(8)
906 .build()
907 .unwrap();
908
909 assert_eq!(frame.header().scid(), Scid::new(1023));
910 assert_eq!(frame.header().qos(), QoS::Expedited);
911 assert_eq!(frame.header().pdu_type(), PduType::Supervisory);
912 assert!(frame.header().pcid());
913 assert_eq!(frame.header().src_dest(), SrcDest::Destination);
914 assert_eq!(frame.header().fsn(), 255);
915 }
916
917 #[test]
918 fn parse_roundtrip() {
919 let mut buf = [0u8; 128];
920
921 let frame = Proximity1TransferFrame::builder()
922 .buffer(&mut buf)
923 .scid(Scid::new(500))
924 .qos(QoS::Expedited)
925 .pdu_type(PduType::UserData)
926 .dfc_id(DfcId::UserDefined)
927 .pcid(false)
928 .port_id(7)
929 .src_dest(SrcDest::Source)
930 .fsn(42)
931 .data_field_len(10)
932 .build()
933 .unwrap();
934
935 let total = frame.frame_len();
936
937 let parsed =
938 Proximity1TransferFrame::parse(&buf[..total]).unwrap();
939 assert_eq!(parsed.header().scid(), Scid::new(500));
940 assert_eq!(parsed.header().qos(), QoS::Expedited);
941 assert_eq!(parsed.header().dfc_id(), DfcId::UserDefined);
942 assert_eq!(parsed.header().port_id(), 7);
943 assert_eq!(parsed.header().fsn(), 42);
944 assert_eq!(parsed.data_field().len(), 10);
945 }
946
947 #[test]
948 fn invalid_scid_rejected() {
949 let mut buf = [0u8; 64];
950 let err = Proximity1TransferFrame::builder()
951 .buffer(&mut buf)
952 .scid(Scid::new(1024)) .qos(QoS::SequenceControlled)
954 .pdu_type(PduType::UserData)
955 .dfc_id(DfcId::Packets)
956 .pcid(false)
957 .port_id(0)
958 .src_dest(SrcDest::Source)
959 .fsn(0)
960 .data_field_len(1)
961 .build();
962 assert!(matches!(err, Err(BuildError::InvalidScid(s)) if s == Scid::new(1024)));
963 }
964
965 #[test]
966 fn invalid_port_id_rejected() {
967 let mut buf = [0u8; 64];
968 let err = Proximity1TransferFrame::builder()
969 .buffer(&mut buf)
970 .scid(Scid::new(0))
971 .qos(QoS::SequenceControlled)
972 .pdu_type(PduType::UserData)
973 .dfc_id(DfcId::Packets)
974 .pcid(false)
975 .port_id(8) .src_dest(SrcDest::Source)
977 .fsn(0)
978 .data_field_len(1)
979 .build();
980 assert!(matches!(err, Err(BuildError::InvalidPortId(8))));
981 }
982
983 #[test]
984 fn data_too_long_rejected() {
985 let mut buf = [0u8; 64];
986 let err = Proximity1TransferFrame::builder()
987 .buffer(&mut buf)
988 .scid(Scid::new(0))
989 .qos(QoS::SequenceControlled)
990 .pdu_type(PduType::UserData)
991 .dfc_id(DfcId::Packets)
992 .pcid(false)
993 .port_id(0)
994 .src_dest(SrcDest::Source)
995 .fsn(0)
996 .data_field_len(2044) .build();
998 assert!(matches!(err, Err(BuildError::DataTooLong(2044))));
999 }
1000
1001 #[test]
1002 fn buffer_too_small_rejected() {
1003 let mut buf = [0u8; 4]; let err = Proximity1TransferFrame::builder()
1005 .buffer(&mut buf)
1006 .scid(Scid::new(0))
1007 .qos(QoS::SequenceControlled)
1008 .pdu_type(PduType::UserData)
1009 .dfc_id(DfcId::Packets)
1010 .pcid(false)
1011 .port_id(0)
1012 .src_dest(SrcDest::Source)
1013 .fsn(0)
1014 .data_field_len(1)
1015 .build();
1016 assert!(matches!(
1017 err,
1018 Err(BuildError::BufferTooSmall {
1019 required: 6,
1020 provided: 4,
1021 })
1022 ));
1023 }
1024
1025 #[test]
1026 fn parse_too_short() {
1027 let buf = [0u8; 3];
1028 let err = Proximity1TransferFrame::parse(&buf);
1029 assert!(matches!(
1030 err,
1031 Err(ParseError::TooShortForHeader { actual: 3 })
1032 ));
1033 }
1034
1035 #[test]
1036 fn parse_invalid_version() {
1037 let mut buf = [0u8; 16];
1038 buf[0] = 0x00;
1040 buf[1] = 0x00;
1041 buf[2] = 0x00;
1042 buf[3] = 0x0F; let err = Proximity1TransferFrame::parse(&buf);
1044 assert!(matches!(
1045 err,
1046 Err(ParseError::InvalidVersion(0))
1047 ));
1048 }
1049
1050 #[test]
1051 fn max_frame_size() {
1052 let mut buf = [0u8; MAX_FRAME_LEN];
1053 let frame = Proximity1TransferFrame::builder()
1054 .buffer(&mut buf)
1055 .scid(Scid::new(0))
1056 .qos(QoS::Expedited)
1057 .pdu_type(PduType::UserData)
1058 .dfc_id(DfcId::UserDefined)
1059 .pcid(false)
1060 .port_id(0)
1061 .src_dest(SrcDest::Source)
1062 .fsn(0)
1063 .data_field_len(MAX_DATA_FIELD_LEN)
1064 .build()
1065 .unwrap();
1066
1067 assert_eq!(frame.frame_len(), MAX_FRAME_LEN);
1068 assert_eq!(frame.data_field().len(), MAX_DATA_FIELD_LEN);
1069 }
1070
1071 #[test]
1072 fn all_dfc_id_variants() {
1073 for (dfc, expected_raw) in [
1074 (DfcId::Packets, 0b00u8),
1075 (DfcId::Segments, 0b01),
1076 (DfcId::Reserved, 0b10),
1077 (DfcId::UserDefined, 0b11),
1078 ] {
1079 let mut buf = [0u8; 16];
1080 let frame = Proximity1TransferFrame::builder()
1081 .buffer(&mut buf)
1082 .scid(Scid::new(0))
1083 .qos(QoS::SequenceControlled)
1084 .pdu_type(PduType::UserData)
1085 .dfc_id(dfc)
1086 .pcid(false)
1087 .port_id(0)
1088 .src_dest(SrcDest::Source)
1089 .fsn(0)
1090 .data_field_len(1)
1091 .build()
1092 .unwrap();
1093
1094 assert_eq!(frame.header().dfc_id(), dfc);
1095 let raw = get_bits_u16(
1096 frame.header().version_qos_pdu_dfc_scid,
1097 DFC_ID_MASK,
1098 );
1099 assert_eq!(raw as u8, expected_raw);
1100 }
1101 }
1102
1103 #[test]
1104 fn display_format() {
1105 let mut buf = [0u8; 16];
1106 let frame = Proximity1TransferFrame::builder()
1107 .buffer(&mut buf)
1108 .scid(Scid::new(100))
1109 .qos(QoS::Expedited)
1110 .pdu_type(PduType::Supervisory)
1111 .dfc_id(DfcId::Packets)
1112 .pcid(true)
1113 .port_id(5)
1114 .src_dest(SrcDest::Destination)
1115 .fsn(77)
1116 .data_field_len(4)
1117 .build()
1118 .unwrap();
1119
1120 let mut out = [0u8; 128];
1121 let n = crate::fmt!(&mut out, "{}", frame).unwrap();
1122 let s = core::str::from_utf8(&out[..n]).unwrap();
1123 assert!(s.contains("scid=100"));
1124 assert!(s.contains("fsn=77"));
1125 }
1126
1127 #[test]
1130 fn plcw_roundtrip() {
1131 let plcw = Plcw::new(true, false, 5, 0xAB);
1132 assert!(plcw.retransmit());
1133 assert!(!plcw.pcid());
1134 assert_eq!(plcw.expedited_counter(), 5);
1135 assert_eq!(plcw.report_value(), 0xAB);
1136
1137 let bytes = plcw.to_bytes();
1138 let parsed = Plcw::from_bytes(&bytes);
1139 assert_eq!(parsed, plcw);
1140 }
1141
1142 #[test]
1143 fn plcw_format_id_always_set() {
1144 let plcw = Plcw::new(false, false, 0, 0);
1145 assert!(plcw.raw() & plcw_bitmask::FORMAT_ID_MASK != 0);
1147 assert!(plcw.raw() & plcw_bitmask::TYPE_ID_MASK == 0);
1149 }
1150
1151 #[test]
1152 fn plcw_all_fields() {
1153 let plcw = Plcw::new(false, true, 7, 255);
1154 assert!(!plcw.retransmit());
1155 assert!(plcw.pcid());
1156 assert_eq!(plcw.expedited_counter(), 7);
1157 assert_eq!(plcw.report_value(), 255);
1158 }
1159
1160 #[test]
1161 fn plcw_display() {
1162 let plcw = Plcw::new(true, false, 3, 42);
1163 let mut out = [0u8; 64];
1164 let n = crate::fmt!(&mut out, "{}", plcw).unwrap();
1165 let s = core::str::from_utf8(&out[..n]).unwrap();
1166 assert!(s.contains("rt=1"));
1167 assert!(s.contains("vr=42"));
1168 }
1169
1170 #[test]
1173 fn segment_header_roundtrip() {
1174 let hdr = SegmentHeader::new(SequenceFlag::First, 42);
1175 assert_eq!(hdr.flags(), SequenceFlag::First);
1176 assert_eq!(hdr.pseudo_packet_id(), 42);
1177
1178 let b = hdr.to_byte();
1179 let parsed = SegmentHeader::from_byte(b);
1180 assert_eq!(parsed, hdr);
1181 }
1182
1183 #[test]
1184 fn segment_header_all_flags() {
1185 for (flag, expected_bits) in [
1186 (SequenceFlag::First, 0b01),
1187 (SequenceFlag::Continuation, 0b00),
1188 (SequenceFlag::Last, 0b10),
1189 (SequenceFlag::Unsegmented, 0b11),
1190 ] {
1191 let hdr = SegmentHeader::new(flag, 0);
1192 assert_eq!(hdr.flags(), flag);
1193 assert_eq!(hdr.to_byte() >> 6, expected_bits);
1194 }
1195 }
1196
1197 #[test]
1198 fn segment_header_pseudo_id_masked() {
1199 let hdr = SegmentHeader::new(SequenceFlag::Unsegmented, 0xFF);
1201 assert_eq!(hdr.pseudo_packet_id(), 0x3F);
1202 }
1203}