dvb_t2mi/payload/
bbframe.rs1use dvb_common::{Parse, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize))]
15pub struct BbframePayload<'a> {
16 pub frame_idx: u8,
18 pub plp_id: u8,
20 pub intl_frame_start: bool,
22 pub bbframe: &'a [u8],
24}
25
26impl<'a> Parse<'a> for BbframePayload<'a> {
27 type Error = crate::error::Error;
28
29 fn parse(bytes: &'a [u8]) -> Result<Self, crate::error::Error> {
30 if bytes.len() < 3 {
31 return Err(crate::Error::BufferTooShort {
32 need: 3,
33 have: bytes.len(),
34 what: "BbframePayload header (frame_idx + plp_id + intl_frame_start + rfu)",
35 });
36 }
37
38 let frame_idx = bytes[0];
39 let plp_id = bytes[1];
40 let intl_frame_start = bytes[2] & 0x80 != 0;
41
42 if bytes[2] & 0x7F != 0 {
44 return Err(crate::Error::ReservedBitsViolation {
45 field: "byte 2 bits 6..0",
46 reason: "RFU must be zero (ETSI TS 102 773 §5.2.1)",
47 });
48 }
49
50 let bbframe = &bytes[3..];
51
52 Ok(BbframePayload {
53 frame_idx,
54 plp_id,
55 intl_frame_start,
56 bbframe,
57 })
58 }
59}
60
61impl<'a> crate::traits::PayloadDef<'a> for BbframePayload<'a> {
62 const PACKET_TYPE: u8 = 0x00;
63 const NAME: &'static str = "BBFRAME";
64}
65
66impl Serialize for BbframePayload<'_> {
67 type Error = crate::error::Error;
68
69 fn serialized_len(&self) -> usize {
70 3 + self.bbframe.len()
71 }
72
73 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize, crate::error::Error> {
74 if buf.len() < self.serialized_len() {
75 return Err(crate::Error::OutputBufferTooSmall {
76 need: self.serialized_len(),
77 have: buf.len(),
78 });
79 }
80
81 buf[0] = self.frame_idx;
82 buf[1] = self.plp_id;
83 buf[2] = if self.intl_frame_start { 0x80 } else { 0x00 };
84 if !self.bbframe.is_empty() {
85 buf[3..3 + self.bbframe.len()].copy_from_slice(self.bbframe);
86 }
87
88 Ok(self.serialized_len())
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn parse_extracts_frame_idx_and_plp_id() {
98 let buf = [0x42u8, 0x05, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
99 let result = BbframePayload::parse(&buf).unwrap();
100 assert_eq!(result.frame_idx, 0x42);
101 assert_eq!(result.plp_id, 0x05);
102 assert_eq!(result.bbframe, &[0xDE, 0xAD, 0xBE, 0xEF]);
103 }
104
105 #[test]
106 fn parse_extracts_intl_frame_start_flag() {
107 let buf = [0x00u8, 0x00, 0x80];
108 let result = BbframePayload::parse(&buf).unwrap();
109 assert!(result.intl_frame_start);
110
111 let buf2 = [0x00u8, 0x00, 0x00];
112 let result2 = BbframePayload::parse(&buf2).unwrap();
113 assert!(!result2.intl_frame_start);
114 }
115
116 #[test]
117 fn parse_rejects_nonzero_rfu_bits() {
118 let buf = [0x00u8, 0x00, 0x40];
119 let result = BbframePayload::parse(&buf);
120 assert!(result.is_err());
121 assert!(matches!(
122 result.unwrap_err(),
123 crate::Error::ReservedBitsViolation { .. }
124 ));
125 }
126
127 #[test]
128 fn parse_bbframe_body_slices_from_offset_3() {
129 let body: Vec<u8> = (0..100).collect();
130 let mut buf = vec![0x0Fu8, 0x01, 0x00];
131 buf.extend_from_slice(&body);
132 let result = BbframePayload::parse(&buf).unwrap();
133 assert_eq!(result.bbframe, body.as_slice());
134 }
135
136 #[test]
137 fn parse_rejects_body_shorter_than_3_bytes() {
138 assert!(BbframePayload::parse(&[0x00, 0x00]).is_err());
139 assert!(BbframePayload::parse(&[]).is_err());
140 }
141
142 #[test]
143 fn serialize_round_trip_preserves_all_fields() {
144 let orig = BbframePayload {
145 frame_idx: 0xAB,
146 plp_id: 0x07,
147 intl_frame_start: true,
148 bbframe: &[0xCA, 0xFE, 0xBA, 0xBE],
149 };
150 let mut buf = vec![0u8; orig.serialized_len()];
151 orig.serialize_into(&mut buf).unwrap();
152 let parsed = BbframePayload::parse(&buf).unwrap();
153 assert_eq!(orig, parsed);
154 }
155
156 #[test]
157 fn serialize_zeros_rfu_bits() {
158 let payload = BbframePayload {
159 frame_idx: 0x00,
160 plp_id: 0x00,
161 intl_frame_start: false,
162 bbframe: &[],
163 };
164 let mut buf = [0xFFu8; 3];
165 payload.serialize_into(&mut buf).unwrap();
166 assert_eq!(buf[0], 0x00);
167 assert_eq!(buf[1], 0x00);
168 assert_eq!(buf[2] & 0x7F, 0x00);
169 }
170}