mboot/mboot/
packets.rs

1// Copyright 2025 NXP
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5//! McuBoot Protocol Packet Implementation
6//!
7//! The module defines traits for packet construction and parsing, packet type constants,
8//! and the common packet header format used across all McuBoot packet types.
9//!
10//! # Packet Structure
11//! All McuBoot packets follow this format:
12//! - Start byte (0x5A)
13//! - Packet type code (1 byte)
14//! - Length (2 bytes, little-endian)
15//! - CRC16 (2 bytes, little-endian)
16//! - Data payload (variable length)
17
18use super::ResultComm;
19
20pub mod command;
21pub mod data_phase;
22pub mod ping;
23
24/// Trait for packet type identification
25///
26/// All packet types must implement this trait to provide their unique identifier
27/// as defined by the McuBoot protocol specification.
28pub trait Packet {
29    /// Returns the packet type code
30    #[must_use]
31    fn get_code() -> u8;
32}
33
34/// Trait for packet construction
35///
36/// Implemented by packet types that can be serialized into bytes for transmission.
37/// The constructed packet includes the complete protocol header and payload.
38pub trait PacketConstruct {
39    /// Constructs the complete packet as bytes ready for transmission
40    #[must_use]
41    fn construct(&self) -> Vec<u8>;
42}
43
44/// Trait for packet parsing
45///
46/// Implemented by packet types that can be deserialized from received bytes.
47/// The input bytes should contain only the payload data, with the protocol
48/// header already processed and removed.
49pub trait PacketParse: Sized {
50    /// Parses bytes into a packet instance
51    ///
52    /// # Arguments
53    /// * `bytes` - Raw payload bytes (without protocol header)
54    ///
55    /// # Returns
56    /// A Result containing the parsed packet or an error
57    ///
58    /// # Errors
59    /// If `bytes` contains improper data for current packet.
60    fn parse(bytes: &[u8]) -> ResultComm<Self>;
61}
62
63/// CRC16 calculator using XMODEM polynomial
64///
65/// Used for packet integrity verification as specified by the McuBoot protocol.
66/// All packets include a CRC16 checksum calculated over the header and payload.
67pub(super) const CRC_CHECK: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_XMODEM);
68
69// McuBoot packet type constants as defined by the protocol specification
70#[expect(dead_code, reason = "remove this expect if you have used the variable")]
71const ABORT: u8 = 0xA3;
72/// Command packet identifier
73const CMD: u8 = 0xA4;
74#[expect(dead_code, reason = "remove this expect if you have used the variable")]
75const DATA: u8 = 0xA5;
76/// Ping packet identifier
77const PING: u8 = 0xA6;
78/// Ping response packet identifier
79const PINGR: u8 = 0xA7;
80
81/// Constructs a complete McuBoot packet header with payload
82///
83/// This function creates a properly formatted McuBoot packet by combining the
84/// packet type code, length, CRC checksum, and payload data according to the
85/// protocol specification.
86///
87/// # Arguments
88/// * `packet_code` - The packet type identifier (e.g., CMD, DATA, PING)
89/// * `data` - The packet payload data
90///
91/// # Returns
92/// A [`Vec<u8>`] containing the complete packet with header and payload
93///
94/// # Packet Format
95/// The constructed packet follows this structure:
96/// - Start byte: 0x5A
97/// - Packet code: 1 byte
98/// - Length: 2 bytes (little-endian, length of data)
99/// - CRC16: 2 bytes (little-endian, calculated over header + data)
100/// - Data: variable length payload
101fn construct_header(packet_code: u8, data: Vec<u8>) -> Vec<u8> {
102    let length = data.len() as u16;
103    let length = length.to_le_bytes();
104
105    let mut v = vec![0x5A, packet_code, length[0], length[1]];
106    v.extend(data);
107
108    let crc = CRC_CHECK.checksum(&v).to_le_bytes();
109
110    v.insert(4, crc[0]);
111    v.insert(5, crc[1]);
112
113    v
114}