satrs_core/encoding/
cobs.rs

1use crate::tmtc::ReceivesTcCore;
2use cobs::{decode_in_place, encode, max_encoding_length};
3
4/// This function encodes the given packet with COBS and also wraps the encoded packet with
5/// the sentinel value 0. It can be used repeatedly on the same encoded buffer by expecting
6/// and incrementing the mutable reference of the current packet index. This is also used
7/// to retrieve the total encoded size.
8///
9/// This function will return [false] if the given encoding buffer is not large enough to hold
10/// the encoded buffer and the two sentinel bytes and [true] if the encoding was successfull.
11///
12/// ## Example
13///
14/// ```
15/// use cobs::decode_in_place_report;
16/// use satrs_core::encoding::{encode_packet_with_cobs};
17//
18/// const SIMPLE_PACKET: [u8; 5] = [1, 2, 3, 4, 5];
19/// const INVERTED_PACKET: [u8; 5] = [5, 4, 3, 2, 1];
20///
21/// let mut encoding_buf: [u8; 32] = [0; 32];
22/// let mut current_idx = 0;
23/// assert!(encode_packet_with_cobs(&SIMPLE_PACKET, &mut encoding_buf, &mut current_idx));
24/// assert!(encode_packet_with_cobs(&INVERTED_PACKET, &mut encoding_buf, &mut current_idx));
25/// assert_eq!(encoding_buf[0], 0);
26/// let dec_report = decode_in_place_report(&mut encoding_buf[1..]).expect("decoding failed");
27/// assert_eq!(encoding_buf[1 + dec_report.src_used], 0);
28/// assert_eq!(dec_report.dst_used, 5);
29/// assert_eq!(current_idx, 16);
30/// ```
31pub fn encode_packet_with_cobs(
32    packet: &[u8],
33    encoded_buf: &mut [u8],
34    current_idx: &mut usize,
35) -> bool {
36    let max_encoding_len = max_encoding_length(packet.len());
37    if *current_idx + max_encoding_len + 2 > encoded_buf.len() {
38        return false;
39    }
40    encoded_buf[*current_idx] = 0;
41    *current_idx += 1;
42    *current_idx += encode(packet, &mut encoded_buf[*current_idx..]);
43    encoded_buf[*current_idx] = 0;
44    *current_idx += 1;
45    true
46}
47
48/// This function parses a given buffer for COBS encoded packets. The packet structure is
49/// expected to be like this, assuming a sentinel value of 0 as the packet delimiter:
50///
51/// 0 | ... Encoded Packet Data ... | 0 | 0 | ... Encoded Packet Data ... | 0
52///
53/// This function is also able to deal with broken tail packets at the end. If broken tail
54/// packets are detected, they are moved to the front of the buffer, and the write index for
55/// future write operations will be written to the `next_write_idx` argument.
56///
57/// The parser will write all packets which were decoded successfully to the given `tc_receiver`.
58pub fn parse_buffer_for_cobs_encoded_packets<E>(
59    buf: &mut [u8],
60    tc_receiver: &mut dyn ReceivesTcCore<Error = E>,
61    next_write_idx: &mut usize,
62) -> Result<u32, E> {
63    let mut start_index_packet = 0;
64    let mut start_found = false;
65    let mut last_byte = false;
66    let mut packets_found = 0;
67    for i in 0..buf.len() {
68        if i == buf.len() - 1 {
69            last_byte = true;
70        }
71        if buf[i] == 0 {
72            if !start_found && !last_byte && buf[i + 1] == 0 {
73                // Special case: Consecutive sentinel values or all zeroes.
74                // Skip.
75                continue;
76            }
77            if start_found {
78                let decode_result = decode_in_place(&mut buf[start_index_packet..i]);
79                if let Ok(packet_len) = decode_result {
80                    packets_found += 1;
81                    tc_receiver
82                        .pass_tc(&buf[start_index_packet..start_index_packet + packet_len])?;
83                }
84                start_found = false;
85            } else {
86                start_index_packet = i + 1;
87                start_found = true;
88            }
89        }
90    }
91    // Move split frame at the end to the front of the buffer.
92    if start_index_packet > 0 && start_found && packets_found > 0 {
93        buf.copy_within(start_index_packet - 1.., 0);
94        *next_write_idx = buf.len() - start_index_packet + 1;
95    }
96    Ok(packets_found)
97}
98
99#[cfg(test)]
100pub(crate) mod tests {
101    use cobs::encode;
102
103    use crate::encoding::tests::{encode_simple_packet, TcCacher, INVERTED_PACKET, SIMPLE_PACKET};
104
105    use super::parse_buffer_for_cobs_encoded_packets;
106
107    #[test]
108    fn test_parsing_simple_packet() {
109        let mut test_sender = TcCacher::default();
110        let mut encoded_buf: [u8; 16] = [0; 16];
111        let mut current_idx = 0;
112        encode_simple_packet(&mut encoded_buf, &mut current_idx);
113        let mut next_read_idx = 0;
114        let packets = parse_buffer_for_cobs_encoded_packets(
115            &mut encoded_buf[0..current_idx],
116            &mut test_sender,
117            &mut next_read_idx,
118        )
119        .unwrap();
120        assert_eq!(packets, 1);
121        assert_eq!(test_sender.tc_queue.len(), 1);
122        let packet = &test_sender.tc_queue[0];
123        assert_eq!(packet, &SIMPLE_PACKET);
124    }
125
126    #[test]
127    fn test_parsing_consecutive_packets() {
128        let mut test_sender = TcCacher::default();
129        let mut encoded_buf: [u8; 16] = [0; 16];
130        let mut current_idx = 0;
131        encode_simple_packet(&mut encoded_buf, &mut current_idx);
132
133        // Second packet
134        encoded_buf[current_idx] = 0;
135        current_idx += 1;
136        current_idx += encode(&INVERTED_PACKET, &mut encoded_buf[current_idx..]);
137        encoded_buf[current_idx] = 0;
138        current_idx += 1;
139        let mut next_read_idx = 0;
140        let packets = parse_buffer_for_cobs_encoded_packets(
141            &mut encoded_buf[0..current_idx],
142            &mut test_sender,
143            &mut next_read_idx,
144        )
145        .unwrap();
146        assert_eq!(packets, 2);
147        assert_eq!(test_sender.tc_queue.len(), 2);
148        let packet0 = &test_sender.tc_queue[0];
149        assert_eq!(packet0, &SIMPLE_PACKET);
150        let packet1 = &test_sender.tc_queue[1];
151        assert_eq!(packet1, &INVERTED_PACKET);
152    }
153
154    #[test]
155    fn test_split_tail_packet_only() {
156        let mut test_sender = TcCacher::default();
157        let mut encoded_buf: [u8; 16] = [0; 16];
158        let mut current_idx = 0;
159        encode_simple_packet(&mut encoded_buf, &mut current_idx);
160        let mut next_read_idx = 0;
161        let packets = parse_buffer_for_cobs_encoded_packets(
162            // Cut off the sentinel byte at the end.
163            &mut encoded_buf[0..current_idx - 1],
164            &mut test_sender,
165            &mut next_read_idx,
166        )
167        .unwrap();
168        assert_eq!(packets, 0);
169        assert_eq!(test_sender.tc_queue.len(), 0);
170        assert_eq!(next_read_idx, 0);
171    }
172
173    fn generic_test_split_packet(cut_off: usize) {
174        let mut test_sender = TcCacher::default();
175        let mut encoded_buf: [u8; 16] = [0; 16];
176        assert!(cut_off < INVERTED_PACKET.len() + 1);
177        let mut current_idx = 0;
178        encode_simple_packet(&mut encoded_buf, &mut current_idx);
179        // Second packet
180        encoded_buf[current_idx] = 0;
181        let packet_start = current_idx;
182        current_idx += 1;
183        let encoded_len = encode(&INVERTED_PACKET, &mut encoded_buf[current_idx..]);
184        assert_eq!(encoded_len, 6);
185        current_idx += encoded_len;
186        // We cut off the sentinel byte, so we expecte the write index to be the length of the
187        // packet minus the sentinel byte plus the first sentinel byte.
188        let next_expected_write_idx = 1 + encoded_len - cut_off + 1;
189        encoded_buf[current_idx] = 0;
190        current_idx += 1;
191        let mut next_write_idx = 0;
192        let expected_at_start = encoded_buf[packet_start..current_idx - cut_off].to_vec();
193        let packets = parse_buffer_for_cobs_encoded_packets(
194            // Cut off the sentinel byte at the end.
195            &mut encoded_buf[0..current_idx - cut_off],
196            &mut test_sender,
197            &mut next_write_idx,
198        )
199        .unwrap();
200        assert_eq!(packets, 1);
201        assert_eq!(test_sender.tc_queue.len(), 1);
202        assert_eq!(&test_sender.tc_queue[0], &SIMPLE_PACKET);
203        assert_eq!(next_write_idx, next_expected_write_idx);
204        assert_eq!(encoded_buf[..next_expected_write_idx], expected_at_start);
205    }
206
207    #[test]
208    fn test_one_packet_and_split_tail_packet_0() {
209        generic_test_split_packet(1);
210    }
211
212    #[test]
213    fn test_one_packet_and_split_tail_packet_1() {
214        generic_test_split_packet(2);
215    }
216
217    #[test]
218    fn test_one_packet_and_split_tail_packet_2() {
219        generic_test_split_packet(3);
220    }
221
222    #[test]
223    fn test_zero_at_end() {
224        let mut test_sender = TcCacher::default();
225        let mut encoded_buf: [u8; 16] = [0; 16];
226        let mut next_write_idx = 0;
227        let mut current_idx = 0;
228        encoded_buf[current_idx] = 5;
229        current_idx += 1;
230        encode_simple_packet(&mut encoded_buf, &mut current_idx);
231        encoded_buf[current_idx] = 0;
232        current_idx += 1;
233        let packets = parse_buffer_for_cobs_encoded_packets(
234            // Cut off the sentinel byte at the end.
235            &mut encoded_buf[0..current_idx],
236            &mut test_sender,
237            &mut next_write_idx,
238        )
239        .unwrap();
240        assert_eq!(packets, 1);
241        assert_eq!(test_sender.tc_queue.len(), 1);
242        assert_eq!(&test_sender.tc_queue[0], &SIMPLE_PACKET);
243        assert_eq!(next_write_idx, 1);
244        assert_eq!(encoded_buf[0], 0);
245    }
246
247    #[test]
248    fn test_all_zeroes() {
249        let mut test_sender = TcCacher::default();
250        let mut all_zeroes: [u8; 5] = [0; 5];
251        let mut next_write_idx = 0;
252        let packets = parse_buffer_for_cobs_encoded_packets(
253            // Cut off the sentinel byte at the end.
254            &mut all_zeroes,
255            &mut test_sender,
256            &mut next_write_idx,
257        )
258        .unwrap();
259        assert_eq!(packets, 0);
260        assert!(test_sender.tc_queue.is_empty());
261        assert_eq!(next_write_idx, 0);
262    }
263}