1use anyhow::Result;
2
3use crate::applayer::PayloadCodec;
4
5pub enum Cid {
6 PackageVersionReq,
7 PackageVersionAns,
8 FragSessionStatusReq,
9 FragSessionStatusAns,
10 FragSessionSetupReq,
11 FragSessionSetupAns,
12 FragSessionDeleteReq,
13 FragSessionDeleteAns,
14 DataFragment,
15}
16
17impl Cid {
18 pub fn from_u8(uplink: bool, value: u8) -> Result<Self> {
19 Ok(match uplink {
20 true => match value {
21 0x00 => Cid::PackageVersionAns,
22 0x01 => Cid::FragSessionStatusAns,
23 0x02 => Cid::FragSessionSetupAns,
24 0x03 => Cid::FragSessionDeleteAns,
25 _ => return Err(anyhow!("Invalid CID: {}", value)),
26 },
27 false => match value {
28 0x00 => Cid::PackageVersionReq,
29 0x01 => Cid::FragSessionStatusReq,
30 0x02 => Cid::FragSessionSetupReq,
31 0x03 => Cid::FragSessionDeleteReq,
32 0x08 => Cid::DataFragment,
33 _ => return Err(anyhow!("Invalid CID: {}", value)),
34 },
35 })
36 }
37
38 pub fn to_u8(&self) -> u8 {
39 match self {
40 Cid::PackageVersionReq | Cid::PackageVersionAns => 0x00,
41 Cid::FragSessionStatusReq | Cid::FragSessionStatusAns => 0x01,
42 Cid::FragSessionSetupReq | Cid::FragSessionSetupAns => 0x02,
43 Cid::FragSessionDeleteReq | Cid::FragSessionDeleteAns => 0x03,
44 Cid::DataFragment => 0x08,
45 }
46 }
47}
48
49#[derive(Debug, PartialEq)]
50pub enum Payload {
51 PackageVersionReq,
52 PackageVersionAns(PackageVersionAnsPayload),
53 FragSessionStatusReq(FragSessionStatusReqPayload),
54 FragSessionStatusAns(FragSessionStatusAnsPayload),
55 FragSessionSetupReq(FragSessionSetupReqPayload),
56 FragSessionSetupAns(FragSessionSetupAnsPayload),
57 FragSessionDeleteReq(FragSessionDeleteReqPayload),
58 FragSessionDeleteAns(FragSessionDeleteAnsPayload),
59 DataFragment(DataFragmentPayload),
60}
61
62impl Payload {
63 pub fn cid(&self) -> Cid {
64 match self {
65 Self::PackageVersionReq => Cid::PackageVersionReq,
66 Self::PackageVersionAns(_) => Cid::PackageVersionAns,
67 Self::FragSessionStatusReq(_) => Cid::FragSessionStatusReq,
68 Self::FragSessionStatusAns(_) => Cid::FragSessionStatusAns,
69 Self::FragSessionSetupReq(_) => Cid::FragSessionSetupReq,
70 Self::FragSessionSetupAns(_) => Cid::FragSessionSetupAns,
71 Self::FragSessionDeleteReq(_) => Cid::FragSessionDeleteReq,
72 Self::FragSessionDeleteAns(_) => Cid::FragSessionDeleteAns,
73 Self::DataFragment(_) => Cid::DataFragment,
74 }
75 }
76
77 pub fn from_slice(uplink: bool, b: &[u8]) -> Result<Self> {
78 if b.is_empty() {
79 return Err(anyhow!("At least one byte is expected"));
80 }
81
82 let cid = Cid::from_u8(uplink, b[0])?;
83
84 Ok(match cid {
85 Cid::PackageVersionReq => Payload::PackageVersionReq,
86 Cid::PackageVersionAns => {
87 Payload::PackageVersionAns(PackageVersionAnsPayload::decode(&b[1..])?)
88 }
89 Cid::FragSessionStatusReq => {
90 Payload::FragSessionStatusReq(FragSessionStatusReqPayload::decode(&b[1..])?)
91 }
92 Cid::FragSessionStatusAns => {
93 Payload::FragSessionStatusAns(FragSessionStatusAnsPayload::decode(&b[1..])?)
94 }
95 Cid::FragSessionSetupReq => {
96 Payload::FragSessionSetupReq(FragSessionSetupReqPayload::decode(&b[1..])?)
97 }
98 Cid::FragSessionSetupAns => {
99 Payload::FragSessionSetupAns(FragSessionSetupAnsPayload::decode(&b[1..])?)
100 }
101 Cid::FragSessionDeleteReq => {
102 Payload::FragSessionDeleteReq(FragSessionDeleteReqPayload::decode(&b[1..])?)
103 }
104 Cid::FragSessionDeleteAns => {
105 Payload::FragSessionDeleteAns(FragSessionDeleteAnsPayload::decode(&b[1..])?)
106 }
107 Cid::DataFragment => Payload::DataFragment(DataFragmentPayload::decode(&b[1..])?),
108 })
109 }
110
111 pub fn to_vec(&self) -> Result<Vec<u8>> {
112 let mut out = vec![self.cid().to_u8()];
113
114 match self {
115 Self::PackageVersionReq => {}
116 Self::PackageVersionAns(pl) => out.extend_from_slice(&pl.encode()?),
117 Self::FragSessionStatusReq(pl) => out.extend_from_slice(&pl.encode()?),
118 Self::FragSessionStatusAns(pl) => out.extend_from_slice(&pl.encode()?),
119 Self::FragSessionSetupReq(pl) => out.extend_from_slice(&pl.encode()?),
120 Self::FragSessionSetupAns(pl) => out.extend_from_slice(&pl.encode()?),
121 Self::FragSessionDeleteReq(pl) => out.extend_from_slice(&pl.encode()?),
122 Self::FragSessionDeleteAns(pl) => out.extend_from_slice(&pl.encode()?),
123 Self::DataFragment(pl) => out.extend_from_slice(&pl.encode()?),
124 }
125
126 Ok(out)
127 }
128}
129
130#[derive(Debug, PartialEq)]
131pub struct PackageVersionAnsPayload {
132 pub package_identifier: u8,
133 pub package_version: u8,
134}
135
136impl PayloadCodec for PackageVersionAnsPayload {
137 fn decode(b: &[u8]) -> Result<Self> {
138 if b.len() != 2 {
139 return Err(anyhow!("Expected 2 bytes"));
140 }
141
142 Ok(PackageVersionAnsPayload {
143 package_identifier: b[0],
144 package_version: b[1],
145 })
146 }
147 fn encode(&self) -> Result<Vec<u8>> {
148 Ok(vec![self.package_identifier, self.package_version])
149 }
150}
151
152#[derive(Debug, PartialEq)]
153pub struct FragSessionStatusReqPayload {
154 pub participants: bool,
155 pub frag_index: u8,
156}
157
158impl PayloadCodec for FragSessionStatusReqPayload {
159 fn decode(b: &[u8]) -> Result<Self> {
160 if b.len() != 1 {
161 return Err(anyhow!("Expected 1 byte"));
162 }
163
164 Ok(FragSessionStatusReqPayload {
165 participants: b[0] & 0x01 != 0,
166 frag_index: (b[0] >> 1) & 0x03,
167 })
168 }
169
170 fn encode(&self) -> Result<Vec<u8>> {
171 if self.frag_index > 3 {
172 return Err(anyhow!("Max frag_index value is 3"));
173 }
174
175 let mut b = vec![self.frag_index << 1];
176 if self.participants {
177 b[0] |= 0x01;
178 }
179
180 Ok(b)
181 }
182}
183
184#[derive(Debug, PartialEq)]
185pub struct FragSessionStatusAnsPayload {
186 pub received_and_index: FragSessionStatusAnsPayloadReceivedAndIndex,
187 pub missing_frag: u8,
188 pub status: FragSessionStatusAnsPayloadStatus,
189}
190
191impl PayloadCodec for FragSessionStatusAnsPayload {
192 fn decode(b: &[u8]) -> Result<Self> {
193 if b.len() != 4 {
194 return Err(anyhow!("Expected 4 bytes"));
195 }
196
197 Ok(FragSessionStatusAnsPayload {
198 received_and_index: FragSessionStatusAnsPayloadReceivedAndIndex {
199 nb_frag_received: {
200 let mut bytes = [0; 2];
201 bytes.copy_from_slice(&b[0..2]);
202 u16::from_le_bytes(bytes) & 0x3fff
203 },
204 frag_index: b[1] >> 6,
205 },
206 missing_frag: b[2],
207 status: FragSessionStatusAnsPayloadStatus {
208 not_enough_matrix_memory: b[3] & 0x01 != 0,
209 },
210 })
211 }
212
213 fn encode(&self) -> Result<Vec<u8>> {
214 if self.received_and_index.nb_frag_received > 16383 {
215 return Err(anyhow!("Max nb_frag_received value us 16383"));
216 }
217
218 if self.received_and_index.frag_index > 3 {
219 return Err(anyhow!("Max frag_index value is 3"));
220 }
221
222 let mut b = Vec::with_capacity(4);
223 b.extend_from_slice(&self.received_and_index.nb_frag_received.to_le_bytes());
224 b[1] |= self.received_and_index.frag_index << 6;
225
226 b.push(self.missing_frag);
227
228 b.push(0x00);
229 if self.status.not_enough_matrix_memory {
230 b[3] |= 0x01;
231 }
232
233 Ok(b)
234 }
235}
236
237#[derive(Debug, PartialEq)]
238pub struct FragSessionStatusAnsPayloadStatus {
239 pub not_enough_matrix_memory: bool,
240}
241
242#[derive(Debug, PartialEq)]
243pub struct FragSessionStatusAnsPayloadReceivedAndIndex {
244 pub nb_frag_received: u16,
245 pub frag_index: u8,
246}
247
248#[derive(Debug, PartialEq)]
249pub struct FragSessionSetupReqPayload {
250 pub frag_session: FragSessionSetuReqPayloadFragSession,
251 pub nb_frag: u16,
252 pub frag_size: u8,
253 pub control: FragSessionSetuReqPayloadControl,
254 pub padding: u8,
255 pub descriptor: [u8; 4],
256}
257
258impl PayloadCodec for FragSessionSetupReqPayload {
259 fn decode(b: &[u8]) -> Result<Self> {
260 if b.len() != 10 {
261 return Err(anyhow!("Expected 10 bytes"));
262 }
263
264 Ok(FragSessionSetupReqPayload {
265 frag_session: FragSessionSetuReqPayloadFragSession {
266 mc_group_bit_mask: {
267 let mut mask = [false; 4];
268 for (i, v) in mask.iter_mut().enumerate() {
269 *v = b[0] & (1 << i) != 0;
270 }
271 mask
272 },
273 frag_index: (b[0] >> 4) & 0x03,
274 },
275 nb_frag: {
276 let mut bytes = [0; 2];
277 bytes.copy_from_slice(&b[1..3]);
278 u16::from_le_bytes(bytes)
279 },
280 frag_size: b[3],
281 control: FragSessionSetuReqPayloadControl {
282 block_ack_delay: b[4] & 0x07,
283 fragmentation_matrix: (b[4] >> 3) & 0x07,
284 },
285 padding: b[5],
286 descriptor: {
287 let mut bytes = [0; 4];
288 bytes.copy_from_slice(&b[6..10]);
289 bytes
290 },
291 })
292 }
293
294 fn encode(&self) -> Result<Vec<u8>> {
295 if self.frag_session.frag_index > 3 {
296 return Err(anyhow!("Max frag_index value is 3"));
297 }
298
299 if self.control.block_ack_delay > 7 {
300 return Err(anyhow!("Max block_ack_delay value is 7"));
301 }
302
303 if self.control.fragmentation_matrix > 7 {
304 return Err(anyhow!("Max fragmentation_matrix value is 7"));
305 }
306
307 let mut b = Vec::with_capacity(10);
308
309 b.push(self.frag_session.frag_index << 4);
310 for (i, v) in self.frag_session.mc_group_bit_mask.iter().enumerate() {
311 if *v {
312 b[0] |= 1 << i;
313 }
314 }
315 b.extend_from_slice(&self.nb_frag.to_le_bytes());
316 b.push(self.frag_size);
317 b.push(self.control.block_ack_delay | (self.control.fragmentation_matrix << 3));
318 b.push(self.padding);
319 b.extend_from_slice(&self.descriptor);
320
321 Ok(b)
322 }
323}
324
325#[derive(Debug, PartialEq)]
326pub struct FragSessionSetuReqPayloadFragSession {
327 pub mc_group_bit_mask: [bool; 4],
328 pub frag_index: u8,
329}
330
331#[derive(Debug, PartialEq)]
332pub struct FragSessionSetuReqPayloadControl {
333 pub block_ack_delay: u8,
334 pub fragmentation_matrix: u8,
335}
336
337#[derive(Debug, PartialEq)]
338pub struct FragSessionSetupAnsPayload {
339 pub encoding_unsupported: bool,
340 pub not_enough_memory: bool,
341 pub frag_session_index_not_supported: bool,
342 pub wrong_descriptor: bool,
343 pub frag_index: u8,
344}
345
346impl PayloadCodec for FragSessionSetupAnsPayload {
347 fn decode(b: &[u8]) -> Result<Self> {
348 if b.len() != 1 {
349 return Err(anyhow!("Expected 1 byte"));
350 }
351
352 Ok(FragSessionSetupAnsPayload {
353 encoding_unsupported: b[0] & 0x01 != 0,
354 not_enough_memory: b[0] & 0x02 != 0,
355 frag_session_index_not_supported: b[0] & 0x04 != 0,
356 wrong_descriptor: b[0] & 0x08 != 0,
357 frag_index: (b[0] >> 6),
358 })
359 }
360
361 fn encode(&self) -> Result<Vec<u8>> {
362 if self.frag_index > 3 {
363 return Err(anyhow!("Max frag_index value is 3"));
364 }
365
366 let mut b = vec![self.frag_index << 6];
367 if self.encoding_unsupported {
368 b[0] |= 0x01;
369 }
370 if self.not_enough_memory {
371 b[0] |= 0x02;
372 }
373 if self.frag_session_index_not_supported {
374 b[0] |= 0x04;
375 }
376 if self.wrong_descriptor {
377 b[0] |= 0x08;
378 }
379
380 Ok(b)
381 }
382}
383
384#[derive(Debug, PartialEq)]
385pub struct FragSessionDeleteReqPayload {
386 pub frag_index: u8,
387}
388
389impl PayloadCodec for FragSessionDeleteReqPayload {
390 fn decode(b: &[u8]) -> Result<Self> {
391 if b.len() != 1 {
392 return Err(anyhow!("Expected 1 byte"));
393 }
394
395 Ok(FragSessionDeleteReqPayload {
396 frag_index: b[0] & 0x03,
397 })
398 }
399
400 fn encode(&self) -> Result<Vec<u8>> {
401 if self.frag_index > 3 {
402 return Err(anyhow!("Max frag_index value is 3"));
403 }
404
405 Ok(vec![self.frag_index])
406 }
407}
408
409#[derive(Debug, PartialEq)]
410pub struct FragSessionDeleteAnsPayload {
411 pub frag_index: u8,
412 pub session_does_not_exist: bool,
413}
414
415impl PayloadCodec for FragSessionDeleteAnsPayload {
416 fn decode(b: &[u8]) -> Result<Self> {
417 if b.len() != 1 {
418 return Err(anyhow!("Expected 1 byte"));
419 }
420
421 Ok(FragSessionDeleteAnsPayload {
422 frag_index: b[0] & 0x03,
423 session_does_not_exist: b[0] & 0x04 != 0,
424 })
425 }
426
427 fn encode(&self) -> Result<Vec<u8>> {
428 if self.frag_index > 3 {
429 return Err(anyhow!("Max frag_index value is 3"));
430 }
431
432 let mut b = vec![self.frag_index];
433 if self.session_does_not_exist {
434 b[0] |= 0x04;
435 }
436
437 Ok(b)
438 }
439}
440
441#[derive(Debug, PartialEq)]
442pub struct DataFragmentPayload {
443 pub index_and_n: DataFragmentPayloadIndexAndN,
444 pub data: Vec<u8>,
445}
446
447impl PayloadCodec for DataFragmentPayload {
448 fn decode(b: &[u8]) -> Result<Self> {
449 if b.len() < 2 {
450 return Err(anyhow!("At least 2 bytes expected"));
451 }
452
453 Ok(DataFragmentPayload {
454 index_and_n: DataFragmentPayloadIndexAndN {
455 n: {
456 let mut bytes = [0; 2];
457 bytes.copy_from_slice(&b[0..2]);
458 u16::from_le_bytes(bytes) & 0x3fff
459 },
460 frag_index: b[1] >> 6,
461 },
462 data: b[2..].to_vec(),
463 })
464 }
465
466 fn encode(&self) -> Result<Vec<u8>> {
467 if self.index_and_n.n > 16383 {
468 return Err(anyhow!("Max n value us 16383"));
469 }
470
471 if self.index_and_n.frag_index > 3 {
472 return Err(anyhow!("Max frag_index value is 3"));
473 }
474
475 let mut b = Vec::with_capacity(2 + self.data.len());
476 b.extend_from_slice(&self.index_and_n.n.to_le_bytes());
477 b[1] |= self.index_and_n.frag_index << 6;
478 b.extend_from_slice(&self.data);
479
480 Ok(b)
481 }
482}
483
484#[derive(Debug, PartialEq)]
485pub struct DataFragmentPayloadIndexAndN {
486 pub n: u16,
487 pub frag_index: u8,
488}
489
490pub fn encode(payload: &[u8], fragment_size: usize, redundancy: usize) -> Result<Vec<Vec<u8>>> {
494 if payload.len() % fragment_size != 0 {
495 return Err(anyhow!("Payload size must be a multiple of fragment_size"));
496 }
497
498 let mut data_rows: Vec<Vec<u8>> = payload.chunks(fragment_size).map(|v| v.to_vec()).collect();
500 let w = data_rows.len();
501
502 for y in 0..redundancy {
503 let mut s = vec![0; fragment_size];
504 let a = matrix_line(y + 1, w);
505
506 for x in 0..w {
507 if a[x] == 1 {
508 for (m, s_val) in s.iter_mut().enumerate() {
509 *s_val ^= data_rows[x][m];
510 }
511 }
512 }
513
514 data_rows.push(s);
515 }
516
517 Ok(data_rows)
518}
519
520fn prbs23(x: usize) -> usize {
521 let b0 = x & 1;
522 let b1 = (x & 32) / 32;
523 (x / 2) + (b0 ^ b1) * (1 << 22)
524}
525
526fn is_power_2(num: usize) -> bool {
527 num != 0 && (num & (num - 1)) == 0
528}
529
530fn matrix_line(n: usize, m: usize) -> Vec<usize> {
531 let mut line = vec![0; m];
532
533 let mm = if is_power_2(m) { 1 } else { 0 };
534
535 let mut x = 1 + (1001 * n);
536
537 for _nb_coeff in 0..(m / 2) {
538 let mut r = 1 << 16;
539 while r >= m {
540 x = prbs23(x);
541 r = x % (m + mm);
542 }
543 line[r] = 1;
544 }
545
546 line
547}
548
549#[cfg(test)]
550mod test {
551 use super::*;
552
553 struct CommandTest {
554 name: String,
555 uplink: bool,
556 command: Payload,
557 bytes: Vec<u8>,
558 expected_error: Option<String>,
559 }
560
561 #[test]
562 fn test_package_version_req() {
563 let encode_tests = [CommandTest {
564 name: "encode PackageVersionReq".into(),
565 uplink: false,
566 command: Payload::PackageVersionReq,
567 bytes: vec![0x00],
568 expected_error: None,
569 }];
570
571 let decode_tests = [CommandTest {
572 name: "decode PackageVersionReq".into(),
573 uplink: false,
574 command: Payload::PackageVersionReq,
575 bytes: vec![0x00],
576 expected_error: None,
577 }];
578
579 run_tests_encode(&encode_tests);
580 run_tests_decode(&decode_tests);
581 }
582
583 #[test]
584 fn test_frag_session_status_req() {
585 let encode_tests = [CommandTest {
586 name: "encode FragSessionStatusReq".into(),
587 uplink: false,
588 command: Payload::FragSessionStatusReq(FragSessionStatusReqPayload {
589 participants: true,
590 frag_index: 2,
591 }),
592 bytes: vec![0x01, 0x05],
593 expected_error: None,
594 }];
595
596 let decode_tests = [CommandTest {
597 name: "decode FragSessionStatusReq".into(),
598 uplink: false,
599 command: Payload::FragSessionStatusReq(FragSessionStatusReqPayload {
600 participants: true,
601 frag_index: 2,
602 }),
603 bytes: vec![0x01, 0x05],
604 expected_error: None,
605 }];
606
607 run_tests_encode(&encode_tests);
608 run_tests_decode(&decode_tests);
609 }
610
611 #[test]
612 fn test_frag_session_status_ans() {
613 let encode_tests = [CommandTest {
614 name: "encode FragSessionStatusAns".into(),
615 uplink: true,
616 command: Payload::FragSessionStatusAns(FragSessionStatusAnsPayload {
617 received_and_index: FragSessionStatusAnsPayloadReceivedAndIndex {
618 nb_frag_received: 1024,
619 frag_index: 3,
620 },
621 missing_frag: 128,
622 status: FragSessionStatusAnsPayloadStatus {
623 not_enough_matrix_memory: true,
624 },
625 }),
626 bytes: vec![0x01, 0x00, 0xc4, 0x80, 0x01],
627 expected_error: None,
628 }];
629
630 let decode_tests = [CommandTest {
631 name: "decode FragSessionStatusAns".into(),
632 uplink: true,
633 command: Payload::FragSessionStatusAns(FragSessionStatusAnsPayload {
634 received_and_index: FragSessionStatusAnsPayloadReceivedAndIndex {
635 nb_frag_received: 1024,
636 frag_index: 3,
637 },
638 missing_frag: 128,
639 status: FragSessionStatusAnsPayloadStatus {
640 not_enough_matrix_memory: true,
641 },
642 }),
643 bytes: vec![0x01, 0x00, 0xc4, 0x80, 0x01],
644 expected_error: None,
645 }];
646
647 run_tests_encode(&encode_tests);
648 run_tests_decode(&decode_tests);
649 }
650
651 #[test]
652 fn test_frag_session_setup_req() {
653 let encode_tests = [CommandTest {
654 name: "encode FragSessionSetupReq".into(),
655 uplink: false,
656 command: Payload::FragSessionSetupReq(FragSessionSetupReqPayload {
657 frag_session: FragSessionSetuReqPayloadFragSession {
658 mc_group_bit_mask: [true, false, false, false],
659 frag_index: 3,
660 },
661 nb_frag: 1024,
662 frag_size: 128,
663 control: FragSessionSetuReqPayloadControl {
664 block_ack_delay: 5,
665 fragmentation_matrix: 1,
666 },
667 padding: 64,
668 descriptor: [0x01, 0x02, 0x03, 0x04],
669 }),
670 bytes: vec![
671 0x02, 0x31, 0x00, 0x04, 0x80, 0x0d, 0x40, 0x01, 0x02, 0x03, 0x04,
672 ],
673 expected_error: None,
674 }];
675
676 let decode_tests = [CommandTest {
677 name: "encode FragSessionSetupReq".into(),
678 uplink: false,
679 command: Payload::FragSessionSetupReq(FragSessionSetupReqPayload {
680 frag_session: FragSessionSetuReqPayloadFragSession {
681 mc_group_bit_mask: [true, false, false, false],
682 frag_index: 3,
683 },
684 nb_frag: 1024,
685 frag_size: 128,
686 control: FragSessionSetuReqPayloadControl {
687 block_ack_delay: 5,
688 fragmentation_matrix: 1,
689 },
690 padding: 64,
691 descriptor: [0x01, 0x02, 0x03, 0x04],
692 }),
693 bytes: vec![
694 0x02, 0x31, 0x00, 0x04, 0x80, 0x0d, 0x40, 0x01, 0x02, 0x03, 0x04,
695 ],
696 expected_error: None,
697 }];
698
699 run_tests_encode(&encode_tests);
700 run_tests_decode(&decode_tests);
701 }
702
703 #[test]
704 fn test_frag_session_setup_ans() {
705 let encode_tests = [CommandTest {
706 name: "encode FragSessionSetupAns".into(),
707 uplink: true,
708 command: Payload::FragSessionSetupAns(FragSessionSetupAnsPayload {
709 encoding_unsupported: true,
710 not_enough_memory: true,
711 frag_session_index_not_supported: false,
712 wrong_descriptor: true,
713 frag_index: 2,
714 }),
715 bytes: vec![0x02, 0x8B],
716 expected_error: None,
717 }];
718
719 let decode_tests = [CommandTest {
720 name: "decode FragSessionSetupAns".into(),
721 uplink: true,
722 command: Payload::FragSessionSetupAns(FragSessionSetupAnsPayload {
723 encoding_unsupported: true,
724 not_enough_memory: true,
725 frag_session_index_not_supported: false,
726 wrong_descriptor: true,
727 frag_index: 2,
728 }),
729 bytes: vec![0x02, 0x8B],
730 expected_error: None,
731 }];
732
733 run_tests_encode(&encode_tests);
734 run_tests_decode(&decode_tests);
735 }
736
737 #[test]
738 fn test_frag_session_delete_req() {
739 let encode_tests = [CommandTest {
740 name: "encode FragSessionDelete".into(),
741 uplink: false,
742 command: Payload::FragSessionDeleteReq(FragSessionDeleteReqPayload { frag_index: 3 }),
743 bytes: vec![0x03, 0x03],
744 expected_error: None,
745 }];
746
747 let decode_tests = [CommandTest {
748 name: "decode FragSessionDelete".into(),
749 uplink: false,
750 command: Payload::FragSessionDeleteReq(FragSessionDeleteReqPayload { frag_index: 3 }),
751 bytes: vec![0x03, 0x03],
752 expected_error: None,
753 }];
754
755 run_tests_encode(&encode_tests);
756 run_tests_decode(&decode_tests);
757 }
758
759 #[test]
760 fn test_frag_session_delete_ans() {
761 let encode_tests = [CommandTest {
762 name: "encode FragSessionDeleteAns".into(),
763 uplink: true,
764 command: Payload::FragSessionDeleteAns(FragSessionDeleteAnsPayload {
765 frag_index: 3,
766 session_does_not_exist: true,
767 }),
768 bytes: vec![0x03, 0x07],
769 expected_error: None,
770 }];
771
772 let decode_tests = [CommandTest {
773 name: "decode FragSessionDeleteAns".into(),
774 uplink: true,
775 command: Payload::FragSessionDeleteAns(FragSessionDeleteAnsPayload {
776 frag_index: 3,
777 session_does_not_exist: true,
778 }),
779 bytes: vec![0x03, 0x07],
780 expected_error: None,
781 }];
782
783 run_tests_encode(&encode_tests);
784 run_tests_decode(&decode_tests);
785 }
786
787 #[test]
788 fn test_data_fragment() {
789 let encode_tests = [CommandTest {
790 name: "encode DataFragment".into(),
791 uplink: false,
792 command: Payload::DataFragment(DataFragmentPayload {
793 index_and_n: DataFragmentPayloadIndexAndN {
794 n: 1024,
795 frag_index: 2,
796 },
797 data: vec![0x01, 0x02, 0x03, 0x04],
798 }),
799 bytes: vec![0x08, 0x00, 0x84, 0x01, 0x02, 0x03, 0x04],
800 expected_error: None,
801 }];
802
803 let decode_tests = [CommandTest {
804 name: "decode DataFragment".into(),
805 uplink: false,
806 command: Payload::DataFragment(DataFragmentPayload {
807 index_and_n: DataFragmentPayloadIndexAndN {
808 n: 1024,
809 frag_index: 2,
810 },
811 data: vec![0x01, 0x02, 0x03, 0x04],
812 }),
813 bytes: vec![0x08, 0x00, 0x84, 0x01, 0x02, 0x03, 0x04],
814 expected_error: None,
815 }];
816
817 run_tests_encode(&encode_tests);
818 run_tests_decode(&decode_tests);
819 }
820
821 #[test]
822 fn test_encode() {
823 struct EncodeTest {
824 name: String,
825 data: Vec<u8>,
826 fragment_size: usize,
827 redundancy: usize,
828 expected_fragments: Vec<Vec<u8>>,
829 expected_error: Option<String>,
830 }
831
832 let mut data = vec![0; 100];
833 for (i, v) in data.iter_mut().enumerate() {
834 *v = i as u8;
835 }
836
837 let tests = [
838 EncodeTest {
839 name: "invalid fragment size".into(),
840 data: vec![0; 5],
841 fragment_size: 10,
842 redundancy: 0,
843 expected_fragments: vec![],
844 expected_error: Some("Payload size must be a multiple of fragment_size".into()),
845 },
846 EncodeTest {
847 name: "fragment size 10, redundancy 10".into(),
848 data: data.clone(),
849 fragment_size: 10,
850 redundancy: 10,
851 expected_fragments: vec![
852 vec![0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9],
853 vec![0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13],
854 vec![0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d],
855 vec![0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27],
856 vec![0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31],
857 vec![0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b],
858 vec![0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45],
859 vec![0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f],
860 vec![0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59],
861 vec![0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63],
862 vec![0x26, 0x26, 0x22, 0x22, 0x2e, 0x2e, 0x22, 0x22, 0x26, 0x26],
863 vec![0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x6a, 0x6b, 0x7c, 0x7d],
864 vec![0x5c, 0x5d, 0x6e, 0x6f, 0x10, 0x11, 0x2, 0x3, 0x4, 0x5],
865 vec![0x36, 0x36, 0x32, 0x32, 0x3e, 0x3e, 0x22, 0x22, 0x36, 0x36],
866 vec![0x3a, 0x3a, 0xe, 0xe, 0xa, 0xa, 0x6, 0x6, 0xa, 0xa],
867 vec![0xe, 0xe, 0x32, 0x32, 0x36, 0x36, 0x22, 0x22, 0x3e, 0x3e],
868 vec![0x2, 0x2, 0xe, 0xe, 0x72, 0x72, 0x76, 0x76, 0x62, 0x62],
869 vec![0x1e, 0x1e, 0x1a, 0x1a, 0x66, 0x66, 0x5a, 0x5a, 0x4e, 0x4e],
870 vec![0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x30, 0x31, 0x22, 0x23],
871 vec![0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, 0x19, 0xa, 0xb],
872 ],
873 expected_error: None,
874 },
875 EncodeTest {
876 name: "fragment size 10, redundancy 5".into(),
877 data: data.clone(),
878 fragment_size: 10,
879 redundancy: 5,
880 expected_fragments: vec![
881 vec![0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9],
882 vec![0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13],
883 vec![0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d],
884 vec![0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27],
885 vec![0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31],
886 vec![0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b],
887 vec![0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45],
888 vec![0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f],
889 vec![0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59],
890 vec![0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63],
891 vec![0x26, 0x26, 0x22, 0x22, 0x2e, 0x2e, 0x22, 0x22, 0x26, 0x26],
892 vec![0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x6a, 0x6b, 0x7c, 0x7d],
893 vec![0x5c, 0x5d, 0x6e, 0x6f, 0x10, 0x11, 0x2, 0x3, 0x4, 0x5],
894 vec![0x36, 0x36, 0x32, 0x32, 0x3e, 0x3e, 0x22, 0x22, 0x36, 0x36],
895 vec![0x3a, 0x3a, 0xe, 0xe, 0xa, 0xa, 0x6, 0x6, 0xa, 0xa],
896 ],
897 expected_error: None,
898 },
899 ];
900
901 for tst in &tests {
902 println!("> {}", tst.name);
903
904 let res = encode(&tst.data, tst.fragment_size, tst.redundancy);
905 if let Some(e) = &tst.expected_error {
906 assert_eq!(e, &res.err().unwrap().to_string());
907 } else {
908 assert_eq!(tst.expected_fragments, res.unwrap());
909 }
910 }
911 }
912
913 fn run_tests_encode(tests: &[CommandTest]) {
914 for tst in tests {
915 println!("> {}", tst.name);
916 let resp = tst.command.to_vec();
917 if let Some(e) = &tst.expected_error {
918 assert!(resp.is_err());
919 assert_eq!(e, &resp.err().unwrap().to_string());
920 } else {
921 assert_eq!(tst.bytes, resp.unwrap());
922 }
923 }
924 }
925
926 fn run_tests_decode(tests: &[CommandTest]) {
927 for tst in tests {
928 println!("> {}", tst.name);
929 let resp = Payload::from_slice(tst.uplink, &tst.bytes);
930 if let Some(e) = &tst.expected_error {
931 assert!(resp.is_err());
932 assert_eq!(e, &resp.err().unwrap().to_string());
933 } else {
934 assert_eq!(tst.command, resp.unwrap());
935 }
936 }
937 }
938}