hadusos 0.2.1

Half-duplex session over serial.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
//! Implementation for session packets. See [`Packet`] for details.

use crate::{
    link::{self, Link, LinkError},
    serial::Serial,
    timer::Timer,
};

/// Use 4 bits (`0b1010`) to encode zero (`even`).
const EVEN_4BIT_PATTERN: u8 = 0b1010;

/// Use 4 bits (`0b0101`) to encode one (`odd`).
const ODD_4BIT_PATTERN: u8 = 0b0101;

/// Use 8 bits (`0b1010_1010`) to encode zero (`even_even`).
const EVEN_EVEN_8BIT_PATTERN: u8 = (EVEN_4BIT_PATTERN << 4) | EVEN_4BIT_PATTERN;

/// Use 8 bits (`0b1010_0101`) to encode one (`even_odd`).
const EVEN_ODD_8BIT_PATTERN: u8 = (EVEN_4BIT_PATTERN << 4) | ODD_4BIT_PATTERN;

/// Use 8 bits (`0b0101_1010`) to encode two (`odd_even`).
const ODD_EVEN_8BIT_PATTERN: u8 = (ODD_4BIT_PATTERN << 4) | EVEN_4BIT_PATTERN;

/// Use 8 bits (`0b0101_0101`) to encode three (`odd_odd`).
const ODD_ODD_8BIT_PATTERN: u8 = (ODD_4BIT_PATTERN << 4) | ODD_4BIT_PATTERN;

/// The session packet is the unit of transmission at the session layer. A
/// packet is devided into a fixed-length header part and a variable-length
/// content part. The length of the content part can be inferred from the
/// `type` field in the header.
///
/// The following figure shows the generic layout of a packet. See
/// [`PacketContent`] for the specific layout of each packet type.
///
/// ```plain
/// |<- 4 bits ->|<- 4 bits  ->|<- 8 bits ->|<- variable length ->|
/// +------------+-------------+------------+---------------------+
/// |  SEQUENCE  | ACKNOWLEDGE |    TYPE    | ..VARIABLE CONTENT..|
/// +------------+-------------+------------+---------------------+
/// |<--------------  HEADER -------------->|<----- CONTENT ----->|
/// ```
///
/// The packet can detect transmission error. If a packet losses bytes or gains
/// spurious bytes during transmission, or if no more than three bits get
/// flipped, parsing the packet will result in an error
/// ([`PacketError::Clobbered`]).
///
/// The `sequence` field has two variants: `even` and `odd`. A sender
/// alternates the `sequence` between `even` and `odd` when sending data to the
/// receiver. For other non-data packet, the `sequence` is set to `even` as a
/// sanity check.
///
/// The `acknowledge` field conveys the confirmation from a receiver to the
/// sender, which can be either `ack` or `nack`. The receiver replies `ack`
/// when a received packet is well-formed, otherwise `nack`. The replied packet
/// carries the same `sequence` as the previously received data packet.
///
/// The `acknowledge` field is meaningful only when a receiver replies
/// confirmation to the sender. In all other cases the field is set to `ack` as
/// a sanity check.
///
/// The `type` field has four variants, representing four packet types:
/// `send_request`, `send_clearance`, `data`, and `reset`.
///
/// A prospective sender initiates a session by sending a `send_request` packet
/// to the receiver. If the receiver is ready, it will reply with a
/// `send_clearance` packet. This procedure forms a handshake. Additionally,
/// the `send_request` packet conveys the totel length of the data to be sent,
/// so that the receiver can allocate a buffer accordingly.
///
/// After the initial handshake, the sender and receiver then proceed to
/// exchange packets of `data` type. The `data` packets from the sender have
/// non-zero content length, which is the data being sent. In contrast, the
/// `data` packets from the receiver have zero content length, which is used to
/// deliver `ack` or `nack` confirmation. To reduce confusion, we call the
/// `data` packet from the receiver to the sender as the acknowledge packet.
///
/// A `data` packet always carries as much data as possible, up to the `data`
/// payload size limit ([`MAX_DATA_PACKET_PAYLOAD_SIZE`]). Since both
/// transmission party know the total data length, they will also share a
/// consensus of the total number of `data` packet.
///
/// The sender terminates a session when it receives `ack` for the last `data`
/// packet from the receiver, upon which the sender sends a `reset` packet.
/// The receiver does not reply to the `reset` packet.
///
/// If a session cannot be established or proceed due to serious transmission
/// errors, either the sender or the receiver may send a `reset` packet to
/// abort the session.
///
/// Since the correctness of the header is critical to the protocol, the
/// header uses 4 bits to encode every 1 bit, so three or less bit flips can be
/// detected. The data content is protected by a crc32 checksum, which can also
/// detect up to three bit flips.
#[must_use]
pub(crate) struct Packet<'a> {
    sequence: Sequence,
    acknowledge: Acknowledge,
    content: PacketContent<'a>,
}

/// The sequence number alternates between even and odd. There is no
/// pipelining in sending. In other words, the maximum number of packet in
/// flight is 1. Thus, it suffices to have two variants.
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum Sequence {
    Even,
    Odd,
}

impl Sequence {
    /// Alternate between even and odd. This is *not* an in-place update.
    pub(crate) fn toggled(&self) -> Self {
        match self {
            Sequence::Even => Sequence::Odd,
            Sequence::Odd => Sequence::Even,
        }
    }
}

/// Whether or not the previously received data packet is well formed. The
/// receiver informs the sender to either proceed to sending the next packet
/// or to resend the previous packet.
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum Acknowledge {
    Ack,
    Nack,
}

/// The enumeration of contents of different packet type. See [`Packet`] for an
/// overall description of the session packet.
#[derive(Clone, Copy)]
pub(crate) enum PacketContent<'a> {
    /// The sender wants to start sending data. This is the first packet of the
    /// handshake to establish a session. The figure below shows the content
    /// layout.
    ///
    /// ```plain
    /// |<- 2 bytes ->|<- 2 bytes ->|<-  4 bytes ->|
    /// +-------------+-------------+--------------+
    /// |   DATA LEN  | SESSION NUM |   CHECKSUM   |
    /// +-------------+-------------+--------------+
    /// ```
    ///
    /// `data_len` conveys the length of the data that a sender intends to send
    /// in a session. `session_num` is an arbitrary number identifying the
    /// session being initiated. These two fields are protected by a crc32
    /// checksum during transmission.
    SendRequest { data_len: u16, session_num: u16 },
    /// The receiver is ready to receive data. This is the second packet of the
    /// handshake to establish a session. The figure below shows the content
    /// layout.
    ///
    /// ```plain
    /// |<- 2 bytes ->|<- 4 bytes ->|
    /// +-------------+-------------+
    /// | SESSION NUM |   CHECKSUM  |
    /// +-------------+-------------+
    /// ```
    ///
    /// `session_num` identifies the session being initiated to remove
    /// ambiguity of which session was cleared to establish in case there is
    /// packet loss. The `session_num` field is protected by a crc32 checksum
    /// during transmission.
    SendClearance { session_num: u16 },
    /// The sender wants to deliver data or the receiver wants to `ack` or
    /// `nack` the previously received data packet.
    ///
    /// The data packet transmitted by the receiver contains no content. To
    /// avoid confusion, such packet will be called acknowledge packet.
    ///
    /// The data packet transmitted by the sender has the following layout.
    ///
    /// ```plain
    /// |<- 1~58 bytes ->|<- 4 bytes ->|
    /// +----------------+-------------+
    /// |      DATA      |   CHECKSUM  |
    /// +----------------+-------------+
    /// ```
    ///
    /// The `data` field has variable length. A data packet always transmit as
    /// much data as possible, thus only the last data packet in a session may
    /// have a `data` field shorter than the maximum length. The `data` field
    /// is protected by a crc32 checksum during transmission.
    Data { buffer: Option<&'a [u8]> },
    /// The sender or the receiver wants to terminate or abort the session. The
    /// sender sends reset to terminate the session after all data packets are
    /// acknowledged. Either side may send reset to abort a session if fatal
    /// error occurs.
    ///
    /// The reset packet has no content but only header.
    Reset,
}

/// The enumeration different packet types. See [`PacketContent`] for the
/// details of each packet type. This enum is used only at an intermediate
/// stage while parsing a packet from received bytes.
#[derive(Clone, Copy, PartialEq, Debug)]
enum PacketType {
    SendRequest,
    SendClearance,
    Data,
    Reset,
}

/// The overhead in bytes of a data packet. The header contributes 2 bytes. The
/// crc32 checksum contributes 4 bytes.
const DATA_PACKET_OVERHEAD: usize = 6;

/// The maximum data payload size is the maximum link layer frame size minus
/// the data packet overhead.
pub(crate) const MAX_DATA_PACKET_PAYLOAD_SIZE: usize =
    link::MAX_FRAME_PAYLOAD_SIZE - DATA_PACKET_OVERHEAD;

/// An opaque type that the receiving client should pass in while receiving
/// a packet. It contains several buffers to facilitate packet receiving. For
/// better performance, the client should construct one scratchpad instance and
/// reuse it for every receiving.
pub(crate) struct Scratchpad {
    /// The header goes into this buffer.
    header_buf: [u8; 2],
    /// The crc32 checksum goes into this buffer.
    crc_buf: [u8; 4],
    /// Used when the buffer provided by the client is not long enough.
    backup_buf: [u8; 4],
}

impl Scratchpad {
    /// Construct a new scratchpad instance.
    pub(crate) const fn new() -> Self {
        Self {
            header_buf: [0u8; 2],
            crc_buf: [0u8; 4],
            backup_buf: [0u8; 4],
        }
    }
}

/// Enumeration of possible packet errors.
pub(crate) enum PacketError<RE, WE> {
    /// Error occurred during serial read.
    SerialReadErr(RE),
    /// Error occurred during serial write.
    SerialWriteErr(WE),
    /// Operation timed out.
    Timeout,
    /// Received a cloberred packet.
    Clobbered,
    /// Received a data packet but no buffer was provided to store the data.
    NoBuffer,
}

/// Implement conversion from [`LinkError`] to [`PacketError`].
impl<RE, WE> From<LinkError<RE, WE>> for PacketError<RE, WE> {
    fn from(le: LinkError<RE, WE>) -> Self {
        match le {
            LinkError::SerialReadErr(e) => PacketError::SerialReadErr(e),
            LinkError::SerialWriteErr(e) => PacketError::SerialWriteErr(e),
            LinkError::Timeout => PacketError::Timeout,
            LinkError::Overrun => PacketError::Clobbered,
        }
    }
}

/// Public functions and methods.
impl<'a> Packet<'a> {
    /// Construct a send request packet.
    ///
    /// # Parameters
    /// - `session_num`: Identifies the session which the sender attempts to
    ///   establish.
    pub(crate) fn build_send_request(data_len: u16, session_num: u16) -> Self {
        Self {
            sequence: Sequence::Even,
            acknowledge: Acknowledge::Ack,
            content: PacketContent::SendRequest {
                data_len,
                session_num,
            },
        }
    }

    /// Construct a send clearance packet.
    ///
    /// # Parameters
    /// - `session_num`: Identifies the session which the receiver clears the
    ///   sender to proceed.
    pub(crate) fn build_send_clearance(session_num: u16) -> Self {
        Self {
            sequence: Sequence::Even,
            acknowledge: Acknowledge::Ack,
            content: PacketContent::SendClearance { session_num },
        }
    }

    /// Construct a data packet for the sender to deliver data.
    ///
    /// # Parameters
    /// - `sequence`: Alternates between [`Sequence::Even`] and
    ///   [`Sequence::Odd`] to distinguish between new and retransmitted data.
    /// - `buffer`: Data to be transmitted. All data packets from the sender
    ///   must have a buffer size equal to [`MAX_DATA_PACKET_PAYLOAD_SIZE`]
    ///   except the last packet in a session.
    pub(crate) fn build_data(sequence: Sequence, buffer: &'a [u8]) -> Self {
        Self {
            sequence,
            acknowledge: Acknowledge::Ack,
            content: PacketContent::Data {
                buffer: Some(buffer),
            },
        }
    }

    /// Construct a data packet for the receiver to `ack` the previously
    /// received data packet.
    ///
    /// # Parameters
    /// - `sequence`: The sequence number of the previously received data
    ///   packet.
    pub(crate) fn build_ack(sequence: Sequence) -> Self {
        Self {
            sequence,
            acknowledge: Acknowledge::Ack,
            content: PacketContent::Data { buffer: None },
        }
    }

    /// Construct a data packet for the receiver to `nack` the previously
    /// received data packet.
    ///
    /// # Parameters
    /// - `sequence`: The sequence number of the previously received data
    ///   packet.
    pub(crate) fn build_nack(sequence: Sequence) -> Self {
        Self {
            sequence,
            acknowledge: Acknowledge::Nack,
            content: PacketContent::Data { buffer: None },
        }
    }

    /// Construct a reset packet.
    pub(crate) fn build_reset() -> Self {
        Self {
            sequence: Sequence::Even,
            acknowledge: Acknowledge::Ack,
            content: PacketContent::Reset,
        }
    }

    /// Send the packet. This operation should not block.
    ///
    /// # Parameters
    /// - `link`: A link layer instance.
    ///
    /// # Returns
    /// - `Ok(())`: Packet sent successfully.
    /// - `Err(PacketError)`: An error occurred.
    pub(crate) fn send<S, T>(
        &self,
        link: &mut Link<S, T>,
    ) -> Result<(), PacketError<S::ReadError, S::WriteError>>
    where
        S: Serial,
        T: Timer,
    {
        // See the documentation of `Packet` and `PacketContent` to find the
        // layout of each packet type.
        match self.content {
            PacketContent::SendRequest {
                data_len,
                session_num,
            } => link.send_frame(&[
                &self.header_to_le_bytes(),
                &data_len.to_le_bytes(),
                &session_num.to_le_bytes(),
                &Self::get_checksum(&[&data_len.to_le_bytes(), &session_num.to_le_bytes()]),
            ]),
            PacketContent::SendClearance { session_num } => link.send_frame(&[
                &self.header_to_le_bytes(),
                &session_num.to_le_bytes(),
                &Self::get_checksum(&[&session_num.to_le_bytes()]),
            ]),
            PacketContent::Data { buffer } => match buffer {
                Some(buffer) => link.send_frame(&[
                    &self.header_to_le_bytes(),
                    buffer,
                    &Self::get_checksum(&[buffer]),
                ]),
                None => link.send_frame(&[&self.header_to_le_bytes()]),
            },
            PacketContent::Reset => link.send_frame(&[&self.header_to_le_bytes()]),
        }
        .map_err(|e| e.into())
    }

    /// Receive a packet or timeout.
    ///
    /// # Parameters
    /// - `link`: A link layer instance.
    /// - `client_buf`: Buffer provided by the client to receive data in case
    ///   the received packet is a data packet. Set to `None` if the client
    ///   expects a packet type other than data packet. Also set to `None` if
    ///   the client expects to receive `ack` or `nack`.
    /// - `timeout_ms`: Timeout in milliseconds.
    /// - `scratchpad`: An opaque object that the client should pass in while
    ///   receiving a packet.
    ///
    /// # Returns
    /// - Ok(Packet): The successfully received packet.
    /// - Err(PacketError): An error occurred.
    pub(crate) fn receive<'b, S, T>(
        link: &mut Link<S, T>,
        mut client_buf: Option<&'a mut [u8]>,
        timeout_ms: u32,
        scratchpad: &'b mut Scratchpad,
    ) -> Result<Self, PacketError<S::ReadError, S::WriteError>>
    where
        'b: 'a,
        S: Serial,
        T: Timer,
    {
        // Use the client provided buffer if it is long enough, or otherwise
        // use the backup buffer. The client provided buffer is the preferred
        // choice so that no further data copying is needed for a received data
        // packet.
        let (active_buf, backup_is_active) =
            Self::pick_buffer(&mut client_buf, &mut scratchpad.backup_buf);

        // Read the packet bytes from the link. If too many bytes are received,
        // the link frame overrun error will be automatically converted to a
        // clobbered packet error.
        //
        // Note that the link layer fills up the following buffers in order.
        // There is a chance that the crc32 checksum is not filled into the
        // `crc_buf`. We will later handle this corner case.
        let byte_cnt = link.receive_frame_with_timeout(
            &mut [
                &mut scratchpad.header_buf,
                active_buf,
                &mut scratchpad.crc_buf,
            ],
            timeout_ms,
        )?;

        // A reset packet or an acknowledge packet has a length of 2 bytes. The
        // next smallest possible packet is a data packet containing 1 byte,
        // which has a length of 7 bytes. Packets smaller than 7 bytes but not
        // 2 bytes must be clobbered.
        if !(byte_cnt == 2 || byte_cnt >= 7) {
            return Err(PacketError::Clobbered);
        }

        // If the packet cannot possibly be a reset packet or acknowledge
        // packet (i.e. length is not 2), then the packet must have a crc32
        // checksum field at the end. However, the `active_buf` may be longer
        // than the received content, causing part or all of the crc32 checksum
        // to be saved also in the `active_buf` rather than the `crc_buf`. So
        // now we copy the last four bytes into the `crc_buf`.
        if byte_cnt != 2 {
            // |<-------- byte count --------->|<- offset ->|
            // +------------+----------------+--------------+
            // | HEADER BUF |   ACTIVE BUF   |    CRC BUF   |
            // +------------+----------------+--------------+
            let offset = (active_buf.len() + scratchpad.crc_buf.len())
                .saturating_sub(byte_cnt - scratchpad.header_buf.len());

            // Perform the copy if the offset is not zero. If otherwise the
            // offset is zero, it means the crc32 checksum is already in the
            // `crc_buf`, thus we should skip the copying.
            if offset > 0 {
                // Copy in reverse order to avoid overwriting existing checksum
                // bytes in the `crc_buf`.
                for idx in (0..=3).rev() {
                    if idx >= offset {
                        scratchpad.crc_buf[idx] = scratchpad.crc_buf[idx - offset];
                    } else {
                        scratchpad.crc_buf[idx] = active_buf[active_buf.len() - (offset - idx)];
                    }
                }
            }
        }

        // Parse the packet header.
        let (sequence, acknowledge, packet_type) = Self::parse_header::<S>(&scratchpad.header_buf)?;

        // Parse the packet content based on the packet type.
        match packet_type {
            PacketType::SendRequest => Self::parse_send_request::<S>(
                byte_cnt,
                sequence,
                acknowledge,
                active_buf[0..4].try_into().unwrap(),
                &scratchpad.crc_buf,
            ),
            PacketType::SendClearance => Self::parse_send_clearance::<S>(
                byte_cnt,
                sequence,
                acknowledge,
                active_buf[0..2].try_into().unwrap(),
                &scratchpad.crc_buf,
            ),
            PacketType::Data => Self::parse_data::<S>(
                byte_cnt,
                sequence,
                acknowledge,
                client_buf,
                active_buf,
                &scratchpad.crc_buf,
                backup_is_active,
            ),
            PacketType::Reset => Self::parse_reset::<S>(byte_cnt, sequence, acknowledge),
        }
    }

    /// Get the sequence number of the given packet.
    pub(crate) fn get_sequence(&self) -> Sequence {
        self.sequence
    }

    /// Get the acknowledge field of the given packet.
    pub(crate) fn get_acknowledge(&self) -> Acknowledge {
        self.acknowledge
    }

    /// Get the content field of the given packet.
    pub(crate) fn get_content(&self) -> PacketContent {
        self.content
    }
}

/// Private functions and methods.
impl<'a> Packet<'a> {
    /// Get the little-endian byte representation of the header field.
    fn header_to_le_bytes(&self) -> [u8; 2] {
        let sequence = match self.sequence {
            Sequence::Even => EVEN_4BIT_PATTERN,
            Sequence::Odd => ODD_4BIT_PATTERN,
        };
        let acknowledge = match self.acknowledge {
            Acknowledge::Ack => EVEN_4BIT_PATTERN,
            Acknowledge::Nack => ODD_4BIT_PATTERN,
        };

        let content_type = match &self.content {
            PacketContent::SendRequest { .. } => EVEN_EVEN_8BIT_PATTERN,
            PacketContent::SendClearance { .. } => EVEN_ODD_8BIT_PATTERN,
            PacketContent::Data { .. } => ODD_EVEN_8BIT_PATTERN,
            PacketContent::Reset => ODD_ODD_8BIT_PATTERN,
        };

        [(sequence << 4) | acknowledge, content_type]
    }

    /// Parse the given bytes as a packet header. Report error if the given
    /// bytes does not match recognizable bit patterns.
    ///
    /// # Parameters
    /// - `header_buf`: The bytes to be parsed as a header.
    ///
    /// # Returns
    /// - `Ok((Sequence, Acknowledge, PacketType))`: Parsed header fields.
    /// - `Err(PacketError)`: An error occurred during parsing.
    fn parse_header<S>(
        header_buf: &[u8; 2],
    ) -> Result<(Sequence, Acknowledge, PacketType), PacketError<S::ReadError, S::WriteError>>
    where
        S: Serial,
    {
        // Get the received bits for each header field.
        let sequence = header_buf[0] >> 4;
        let acknowledge = header_buf[0] & 0xf;
        let packet_type = header_buf[1];

        // Match the bits against recognizable bit patterns.
        let sequence = match sequence {
            EVEN_4BIT_PATTERN => Sequence::Even,
            ODD_4BIT_PATTERN => Sequence::Odd,
            _ => return Err(PacketError::Clobbered),
        };
        let acknowledge = match acknowledge {
            EVEN_4BIT_PATTERN => Acknowledge::Ack,
            ODD_4BIT_PATTERN => Acknowledge::Nack,
            _ => return Err(PacketError::Clobbered),
        };
        let packet_type = match packet_type {
            EVEN_EVEN_8BIT_PATTERN => PacketType::SendRequest,
            EVEN_ODD_8BIT_PATTERN => PacketType::SendClearance,
            ODD_EVEN_8BIT_PATTERN => PacketType::Data,
            ODD_ODD_8BIT_PATTERN => PacketType::Reset,
            _ => return Err(PacketError::Clobbered),
        };

        Ok((sequence, acknowledge, packet_type))
    }

    /// Parse the content of a send request packet.
    ///
    /// # Parameters
    /// - `byte_cnt`: The number of bytes read from the link layer.
    /// - `sequence`: The parsed sequence number.
    /// - `acknowledge`: The parsed acknowledge field.
    /// - `buffer`: The bytes to be parsed as the send request content.
    ///
    /// # Returns
    /// - Ok(Packet): A send request packet.
    /// - Err(PacketError): An error occurred during parsing.
    fn parse_send_request<'b, 'c, S>(
        byte_cnt: usize,
        sequence: Sequence,
        acknowledge: Acknowledge,
        buffer: &'b [u8; 4],
        crc_buf: &'c [u8; 4],
    ) -> Result<Self, PacketError<S::ReadError, S::WriteError>>
    where
        S: Serial,
    {
        // A send request packet must have a length of 10 bytes.
        if byte_cnt != 10 {
            return Err(PacketError::Clobbered);
        }

        // Read content fields.
        let data_len = u16::from_le_bytes(buffer[0..2].try_into().unwrap());
        let session_num = u16::from_le_bytes(buffer[2..4].try_into().unwrap());

        // Verify the checksum.
        if *crc_buf != Self::get_checksum(&[&data_len.to_le_bytes(), &session_num.to_le_bytes()]) {
            return Err(PacketError::Clobbered);
        }

        // A send request packet must have `Sequence::Even` and
        // `Acknowledge::Ack`.
        if sequence != Sequence::Even || acknowledge != Acknowledge::Ack {
            return Err(PacketError::Clobbered);
        }

        Ok(Self {
            sequence,
            acknowledge,
            content: PacketContent::SendRequest {
                data_len,
                session_num,
            },
        })
    }

    /// Parse the content of a send clearance packet.
    ///
    /// # Parameters
    /// - `byte_cnt`: The number of bytes read from the link layer.
    /// - `sequence`: The parsed sequence number.
    /// - `acknowledge`: The parsed acknowledge field.
    /// - `buffer`: The bytes to be parsed as the send clearance content.
    ///
    /// # Returns
    /// - Ok(Packet): A send clearance packet.
    /// - Err(PacketError): An error occurred during parsing.
    fn parse_send_clearance<'b, 'c, S>(
        byte_cnt: usize,
        sequence: Sequence,
        acknowledge: Acknowledge,
        buffer: &'b [u8; 2],
        crc_buf: &'c [u8; 4],
    ) -> Result<Self, PacketError<S::ReadError, S::WriteError>>
    where
        S: Serial,
    {
        // A send clearance packet must have a length of 8 bytes.
        if byte_cnt != 8 {
            return Err(PacketError::Clobbered);
        }

        // Read content fields.
        let session_num = u16::from_le_bytes(buffer[0..2].try_into().unwrap());

        // Verify the checksum.
        if *crc_buf != Self::get_checksum(&[&session_num.to_le_bytes()]) {
            return Err(PacketError::Clobbered);
        }

        // A send clearance packet must have `Sequence::Even` and
        // `Acknowledge::Ack`.
        if sequence != Sequence::Even || acknowledge != Acknowledge::Ack {
            return Err(PacketError::Clobbered);
        }

        Ok(Self {
            sequence,
            acknowledge,
            content: PacketContent::SendClearance { session_num },
        })
    }

    /// Parse the content of a data packet. This might be a packet from the
    /// sender to the receiver carrying data, in which case the content length
    /// is zero. Or it might be a packet from the receiver to the sender
    /// carrying `ack` or `nack`, in which case the content length is zero.
    ///
    /// # Parameters
    /// - `byte_cnt`: The number of bytes read from the link layer.
    /// - `sequence`: The parsed sequence number.
    /// - `acknowledge`: The parsed acknowledge field.
    /// - `client_buf`: The buffer optionally provided by the client.
    /// - `active_buf`: The active buffer picked by [`Self::pick_buffer`].
    /// - `crc_buf`: The bytes to be parsed as a crc32 checksum.
    /// - `backup_is_active`: Whether the `active_buf` is the backup buffer.
    ///
    /// # Returns
    /// - Ok(Packet): A data packet or an acknowledge packet.
    /// - Err(PacketError): An error occurred during parsing.
    fn parse_data<'c, S>(
        byte_cnt: usize,
        sequence: Sequence,
        acknowledge: Acknowledge,
        client_buf: Option<&'a mut [u8]>,
        active_buf: &'a [u8],
        crc_buf: &'c [u8; 4],
        backup_is_active: bool,
    ) -> Result<Self, PacketError<S::ReadError, S::WriteError>>
    where
        S: Serial,
    {
        // If there is no content, this is an acknowledge packet.
        if byte_cnt == 2 {
            return Ok(Packet {
                sequence,
                acknowledge,
                content: PacketContent::Data { buffer: None },
            });
        }

        // Reference the client provided buffer.
        let final_client_buf: &[u8];

        // When the backup buffer is active, we must copy the data received
        // by the backup buffer back to the client provided buffer.
        if backup_is_active {
            // Copy if the client buffer is provided.
            if let Some(client_buf) = client_buf {
                client_buf.copy_from_slice(&active_buf[0..client_buf.len()]);
                final_client_buf = client_buf;
            // Otherwise the client is expecting a packet type other than a
            // data packet, so it did not provide a buffer. Report that we have
            // no buffer to store the received data.
            } else {
                return Err(PacketError::NoBuffer);
            }
        // If we were using the client provided buffer as the active buffer,
        // nothing needs to be done.
        } else {
            final_client_buf = active_buf;
        }

        // If the client provides a buffer expecting to receive data, the link
        // layer must fill up the buffer exactly. Otherwise the packet is
        // considered to be clobbered.
        if byte_cnt != final_client_buf.len() + DATA_PACKET_OVERHEAD {
            return Err(PacketError::Clobbered);
        }

        // Verify the checksum.
        if *crc_buf != Self::get_checksum(&[&final_client_buf]) {
            return Err(PacketError::Clobbered);
        }

        // A data packet carrying data must always have `Acknowledge::Ack`.
        if acknowledge != Acknowledge::Ack {
            return Err(PacketError::Clobbered);
        }

        Ok(Self {
            sequence,
            acknowledge,
            content: PacketContent::Data {
                buffer: Some(final_client_buf),
            },
        })
    }

    /// Parse the content of a reset packet.
    ///
    /// # Parameters
    /// - `byte_cnt`: The number of bytes read from the link layer.
    /// - `sequence`: The parsed sequence number.
    /// - `acknowledge`: The parsed acknowledge field.
    ///
    /// # Returns
    /// - Ok(Packet): A reset packet.
    /// - Err(PacketError): An error occurred during parsing.
    fn parse_reset<S>(
        byte_cnt: usize,
        sequence: Sequence,
        acknowledge: Acknowledge,
    ) -> Result<Self, PacketError<S::ReadError, S::WriteError>>
    where
        S: Serial,
    {
        // A reset packet must have a length of 2 bytes. All is the header
        // but any content.
        if byte_cnt != 2 {
            return Err(PacketError::Clobbered);
        }

        // A reset packet must have `Sequence::Even` and `Acknowledge::Ack`.
        if sequence != Sequence::Even || acknowledge != Acknowledge::Ack {
            return Err(PacketError::Clobbered);
        }

        Ok(Packet {
            sequence,
            acknowledge,
            content: PacketContent::Reset,
        })
    }

    /// Pick between the client provided buffer and the backup buffer to
    /// receive data. The backup buffer will be used only if the client
    /// provided buffer is not large enough. The client provided buffer is
    /// the preferred choice so that the received data needs no further
    /// copying.
    ///
    /// The backup buffer has a length that is enough to receive a packet of
    /// of type send request, send clearance, acknowledge, and reset. The
    /// backup buffer will be used if the client provided buffer is smaller
    /// than it.
    ///
    /// The backup buffer may not be able to hold all bytes of a data packet
    /// However, when the backup buffer is used, the client provided buffer
    /// must be even smaller. Thus, as long as the client provided buffer is
    /// able to hold the received data, the provided buffer must also be.
    ///
    /// # Parameters
    /// - `client_buf`: The buffer optionally provided by the client.
    /// - `backup_buf`: The backup buffer.
    ///
    /// # Returns
    /// - `.0`: The chosen buffer.
    /// - `.1`: Whether the backup buffer is chosen.
    fn pick_buffer<'b>(
        client_buf: &mut Option<&'a mut [u8]>,
        backup_buf: &'b mut [u8; 4],
    ) -> (&'a mut [u8], bool)
    where
        'b: 'a,
    {
        match client_buf.take() {
            // If the client provides a buffer, check its length and decide.
            Some(buf) => {
                // The backup buffer is just large enough to hold any packet
                // content other than data. If the provided buffer is larger,
                // use the provided one.
                if buf.len() >= backup_buf.len() {
                    (buf, false)
                // Otherwise, put back the provided buffer and use the backup
                // instead.
                } else {
                    client_buf.replace(buf);
                    (backup_buf, true)
                }
            }
            // If no client provided buffer, use backup.
            None => (backup_buf, true),
        }
    }

    /// Calculate the crc32 checksum of the given byte slices. The bytes slices
    /// will be flatten into one to calculate the checksum.
    fn get_checksum(byte_slices: &[&[u8]]) -> [u8; 4] {
        let mut hasher = crc32fast::Hasher::new();
        for &slice in byte_slices {
            hasher.update(slice);
        }
        hasher.finalize().to_le_bytes()
    }
}