usbpd/protocol_layer/message/
mod.rs1pub mod data;
4pub mod extended;
5pub mod header;
6
7#[cfg(test)]
8mod epr_messages_test;
9
10use byteorder::{ByteOrder, LittleEndian};
11use header::{Header, MessageType};
12
13use crate::protocol_layer::message::extended::ExtendedHeader;
14
15#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum ParseError {
19 #[error("invalid input buffer length (expected {expected:?}, found {found:?})")]
23 InvalidLength {
24 expected: usize,
26 found: usize,
28 },
29 #[error("unsupported specification revision `{0}`")]
31 UnsupportedSpecificationRevision(u8),
32 #[error("unknown or reserved message type `{0}`")]
34 InvalidMessageType(u8),
35 #[error("unknown or reserved data message type `{0}`")]
37 InvalidDataMessageType(u8),
38 #[error("unknown or reserved control message type `{0}`")]
40 InvalidControlMessageType(u8),
41 #[error("chunked extended message (chunk {chunk_number}, total size {data_size})")]
44 ChunkedExtendedMessage {
45 chunk_number: u8,
47 data_size: u16,
49 request_chunk: bool,
51 message_type: header::ExtendedMessageType,
53 },
54 #[error("chunk size {0} exceeds maximum {1}")]
56 ChunkOverflow(usize, usize),
57 #[error("parser already in use, create a new assembler or call reset()")]
60 ParserReuse,
61 #[error("other parse error: {0}")]
63 Other(&'static str),
64}
65
66#[derive(Debug, Clone)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub enum Payload {
71 Data(data::Data),
73 Extended(extended::Extended),
75}
76
77#[derive(Debug, Clone)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81pub struct Message {
82 pub header: Header,
84 pub payload: Option<Payload>,
86}
87
88impl Message {
89 pub fn new(header: Header) -> Self {
91 Self { header, payload: None }
92 }
93
94 pub fn new_with_data(header: Header, data: data::Data) -> Self {
96 Self {
97 header,
98 payload: Some(Payload::Data(data)),
99 }
100 }
101
102 pub fn to_bytes(&self, buffer: &mut [u8]) -> usize {
104 let header_len = self.header.to_bytes(buffer);
105
106 match self.payload.as_ref() {
107 Some(Payload::Data(data)) => header_len + data.to_bytes(&mut buffer[header_len..]),
108 Some(Payload::Extended(extended)) => {
109 let extended_header = ExtendedHeader::new(extended.data_size())
112 .with_chunked(true)
113 .with_chunk_number(0);
114 let ext_header_len = extended_header.to_bytes(&mut buffer[header_len..]);
115 header_len + ext_header_len + extended.to_bytes(&mut buffer[header_len + ext_header_len..])
116 }
117 None => header_len,
118 }
119 }
120
121 pub fn parse_extended_payload(message_type: header::ExtendedMessageType, payload: &[u8]) -> extended::Extended {
129 match message_type {
130 header::ExtendedMessageType::ExtendedControl => {
131 if payload.len() >= 2 {
132 extended::Extended::ExtendedControl(extended::extended_control::ExtendedControl(
133 LittleEndian::read_u16(payload),
134 ))
135 } else {
136 extended::Extended::Unknown
137 }
138 }
139 header::ExtendedMessageType::EprSourceCapabilities => extended::Extended::EprSourceCapabilities(
140 payload
141 .chunks_exact(4)
142 .map(|buf| {
143 crate::protocol_layer::message::data::source_capabilities::parse_raw_pdo(
144 LittleEndian::read_u32(buf),
145 )
146 })
147 .collect(),
148 ),
149 _ => extended::Extended::Unknown,
150 }
151 }
152
153 pub fn parse_extended_chunk(data: &[u8]) -> Result<(Header, ExtendedHeader, &[u8]), ParseError> {
160 if data.len() < 4 {
161 return Err(ParseError::InvalidLength {
162 expected: 4,
163 found: data.len(),
164 });
165 }
166
167 let header = Header::from_bytes(&data[..2])?;
168 let ext_header = ExtendedHeader::from_bytes(&data[2..]);
169
170 let chunk_payload = &data[4..];
172
173 Ok((header, ext_header, chunk_payload))
174 }
175
176 pub fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
178 let header = Header::from_bytes(&data[..2])?;
179 let message = Self::new(header);
180 let payload = &data[2..];
181
182 match message.header.message_type() {
183 MessageType::Control(_) => Ok(message),
184 MessageType::Extended(message_type) => {
185 let ext_header = ExtendedHeader::from_bytes(payload);
186 let data_size = ext_header.data_size() as usize;
187
188 if ext_header.chunked() {
191 let is_chunk_request = ext_header.request_chunk();
192 let chunk_number = ext_header.chunk_number();
193 let available_payload = payload.len().saturating_sub(2);
194
195 let needs_assembly = is_chunk_request || chunk_number > 0 || data_size > available_payload;
200
201 if needs_assembly {
202 return Err(ParseError::ChunkedExtendedMessage {
203 chunk_number,
204 data_size: ext_header.data_size(),
205 request_chunk: is_chunk_request,
206 message_type,
207 });
208 }
209 }
211 if payload.len() < 2 + data_size {
212 return Err(ParseError::InvalidLength {
213 expected: 2 + data_size,
214 found: payload.len(),
215 });
216 }
217
218 let payload_bytes = &payload[2..2 + data_size];
219 Ok(Self {
220 payload: Some(Payload::Extended(match message_type {
221 header::ExtendedMessageType::ExtendedControl => extended::Extended::ExtendedControl(
222 extended::extended_control::ExtendedControl(LittleEndian::read_u16(payload_bytes)),
223 ),
224 header::ExtendedMessageType::EprSourceCapabilities => {
225 extended::Extended::EprSourceCapabilities(
226 payload_bytes
227 .chunks_exact(4)
228 .map(|buf| {
229 crate::protocol_layer::message::data::source_capabilities::parse_raw_pdo(
230 LittleEndian::read_u32(buf),
231 )
232 })
233 .collect(),
234 )
235 }
236 _ => extended::Extended::Unknown,
237 })),
238 ..message
239 })
240 }
241 MessageType::Data(message_type) => data::Data::parse_message(message, message_type, payload, &()),
242 }
243 }
244}