dvb_t2mi/payload/
p2_bias.rs1use dvb_common::{Parse, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct P2BiasPayload {
12 pub frame_idx: u8,
14 pub num_active_bias_cells_per_p2: u16,
16}
17
18const P2_BIAS_HEADER_LEN: usize = 5;
19
20impl<'a> Parse<'a> for P2BiasPayload {
21 type Error = crate::error::Error;
22
23 fn parse(bytes: &'a [u8]) -> Result<Self, crate::error::Error> {
24 if bytes.len() < P2_BIAS_HEADER_LEN {
25 return Err(crate::Error::BufferTooShort {
26 need: P2_BIAS_HEADER_LEN,
27 have: bytes.len(),
28 what: "P2BiasPayload header",
29 });
30 }
31
32 if bytes[1] != 0 || bytes[2] != 0 || (bytes[3] & 0x80) != 0 {
34 return Err(crate::Error::ReservedBitsViolation {
35 field: "17-bit RFU",
36 reason: "Must be zero (ETSI TS 102 773 §5.2.6)",
37 });
38 }
39
40 let num_active = ((bytes[3] as u16 & 0x7F) << 8) | (bytes[4] as u16);
42
43 Ok(P2BiasPayload {
44 frame_idx: bytes[0],
45 num_active_bias_cells_per_p2: num_active,
46 })
47 }
48}
49
50impl<'a> crate::traits::PayloadDef<'a> for P2BiasPayload {
51 const PACKET_TYPE: u8 = 0x12;
52 const NAME: &'static str = "P2_BIAS";
53}
54
55impl Serialize for P2BiasPayload {
56 type Error = crate::error::Error;
57
58 fn serialized_len(&self) -> usize {
59 P2_BIAS_HEADER_LEN
60 }
61
62 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize, crate::error::Error> {
63 if buf.len() < self.serialized_len() {
64 return Err(crate::Error::OutputBufferTooSmall {
65 need: self.serialized_len(),
66 have: buf.len(),
67 });
68 }
69
70 if self.num_active_bias_cells_per_p2 > 0x7FFF {
71 return Err(crate::Error::ReservedBitsViolation {
72 field: "num_active_bias_cells_per_p2",
73 reason: "Must fit in 15 bits",
74 });
75 }
76
77 buf[0] = self.frame_idx;
78 buf[1] = 0; buf[2] = 0; buf[3] = ((self.num_active_bias_cells_per_p2 >> 8) as u8) & 0x7F;
81 buf[4] = (self.num_active_bias_cells_per_p2 & 0xFF) as u8;
82
83 Ok(self.serialized_len())
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn parse_extracts_fields() {
93 let buf = [0x42u8, 0x00, 0x00, 0x00, 0x0F];
95 let result = P2BiasPayload::parse(&buf).unwrap();
96 assert_eq!(result.frame_idx, 0x42);
97 assert_eq!(result.num_active_bias_cells_per_p2, 0x0F);
98 }
99
100 #[test]
101 fn parse_extracts_15bit_max() {
102 let buf = [0x00u8, 0x00, 0x00, 0x7F, 0xFF];
104 let result = P2BiasPayload::parse(&buf).unwrap();
105 assert_eq!(result.num_active_bias_cells_per_p2, 0x7FFF);
106 }
107
108 #[test]
109 fn parse_rejects_nonzero_rfu() {
110 let buf = [0x00u8, 0x00, 0x00, 0x80, 0x00];
112 assert!(P2BiasPayload::parse(&buf).is_err());
113 assert!(P2BiasPayload::parse(&[0x00u8, 0x01, 0x00, 0x00, 0x00]).is_err());
115 }
116
117 #[test]
118 fn parse_rejects_short_buffer() {
119 assert!(P2BiasPayload::parse(&[0x00, 0x00, 0x00, 0x00]).is_err());
120 }
121
122 #[test]
123 fn serialize_round_trip() {
124 let orig = P2BiasPayload {
125 frame_idx: 5,
126 num_active_bias_cells_per_p2: 3000,
127 };
128 let mut buf = [0u8; 5];
129 orig.serialize_into(&mut buf).unwrap();
130 let parsed = P2BiasPayload::parse(&buf).unwrap();
131 assert_eq!(orig, parsed);
132 }
133
134 #[test]
135 fn serialize_rejects_too_small_buffer() {
136 let payload = P2BiasPayload {
137 frame_idx: 0,
138 num_active_bias_cells_per_p2: 0,
139 };
140 let mut buf = [0u8; 4];
141 assert!(payload.serialize_into(&mut buf).is_err());
142 }
143}