1#![forbid(unsafe_code)]
7
8use core::fmt::Debug;
9use guid::Guid;
10use open_enum::open_enum;
11use static_assertions::const_assert_eq;
12use zerocopy::FromBytes;
13use zerocopy::FromZeros;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16use zerocopy::KnownLayout;
17
18pub const MAX_MESSAGE_SIZE: usize = 512;
20
21pub const UART_INTERFACE_TYPE: Guid = guid::guid!("8b60ccf6-709f-4c11-90b5-229c959a9e6a");
24
25pub const UART_INTERFACE_INSTANCE_COM1: Guid = guid::guid!("700df40e-b947-4776-b839-d1b0a35af034");
28
29pub const UART_INTERFACE_INSTANCE_COM2: Guid = guid::guid!("7e55f4b8-af84-4e98-9f1a-8e8d0bde3744");
32
33pub const UART_INTERFACE_INSTANCE_COM3: Guid = guid::guid!("3f158fa1-b0aa-45e9-ba54-9fc73f6c59ec");
36
37pub const UART_INTERFACE_INSTANCE_COM4: Guid = guid::guid!("8688a06f-9b53-48ce-b408-7581626228c5");
40
41const fn make_version(major: u16, minor: u16) -> u32 {
42 (minor as u32) | ((major as u32) << 16)
43}
44
45open_enum! {
46 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
48 pub enum ProtocolVersions: u32 {
49 MANGANESE = make_version(1, 0),
51 }
52}
53
54open_enum! {
55 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
57 pub enum MessageVersions: u8 {
58 INVALID = 0,
60 HEADER_VERSION_1 = 1,
62 }
63}
64
65open_enum! {
66 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
68 pub enum MessageTypes: u8 {
69 INVALID = 0,
71 HOST_NOTIFICATION = 1,
73 HOST_REQUEST = 2,
75 HOST_RESPONSE = 3,
77 GUEST_NOTIFICATION = 4,
79 }
80}
81
82open_enum! {
83 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
86 pub enum HostNotifications: u8 {
87 INVALID = 0,
89 RX_CLEAR_BUFFER = 1,
91 TX_DATA_AVAILABLE = 2,
93 }
94}
95
96open_enum! {
97 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
100 pub enum GuestNotifications: u8 {
101 INVALID = 0,
103 RX_DATA_AVAILABLE = 1,
105 SET_MODEM_STATUS = 2,
107 TX_COMPLETED = 3,
110 }
111}
112
113open_enum! {
114 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
119 pub enum HostRequests: u16 {
120 INVALID = 0,
122 VERSION = 1,
125 GET_RX_DATA = 2,
127 }
128}
129
130#[repr(transparent)]
148#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
149pub struct MessageId(pub u16);
150
151impl Debug for MessageId {
152 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
153 f.debug_struct("MessageId")
154 .field("as_u16", &self.0)
155 .field("host_notification", &self.host_notification())
156 .field("host_request", &self.host_request())
157 .field("guest_notification", &self.guest_notification())
158 .finish()
159 }
160}
161
162impl MessageId {
163 fn guest_notification(&self) -> GuestNotifications {
164 GuestNotifications(self.0 as u8)
165 }
166
167 fn host_request(&self) -> HostRequests {
168 HostRequests(self.0)
169 }
170
171 fn host_notification(&self) -> HostNotifications {
172 HostNotifications(self.0 as u8)
173 }
174
175 fn new_guest_notification(guest_notification: GuestNotifications) -> Self {
176 MessageId(guest_notification.0 as u16)
177 }
178
179 fn new_host_request(host_request: HostRequests) -> Self {
180 MessageId(host_request.0)
181 }
182
183 fn new_host_notification(host_notification: HostNotifications) -> Self {
184 MessageId(host_notification.0 as u16)
185 }
186}
187
188#[repr(C)]
190#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
191pub struct Header {
192 pub message_version: MessageVersions,
194 pub message_type: MessageTypes,
196 pub message_id: MessageId,
198}
199
200impl Debug for Header {
201 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
202 let host_notification = self.message_id.host_notification();
203 let host_request = self.message_id.host_request();
204 let guest_notification = self.message_id.guest_notification();
205
206 f.debug_struct("Header")
207 .field("message_version", &self.message_version)
208 .field("message_type", &self.message_type)
209 .field(
210 "message_id",
211 match self.message_type {
212 MessageTypes::HOST_NOTIFICATION => &host_notification,
213 MessageTypes::HOST_REQUEST => &host_request,
214 MessageTypes::HOST_RESPONSE => &host_request,
215 MessageTypes::GUEST_NOTIFICATION => &guest_notification,
216 _ => &self.message_id.0,
217 },
218 )
219 .finish()
220 }
221}
222
223impl Default for Header {
224 fn default() -> Self {
225 Self {
226 message_version: MessageVersions::INVALID,
227 message_type: MessageTypes::INVALID,
228 message_id: MessageId::new_zeroed(),
229 }
230 }
231}
232
233impl Header {
234 pub fn new_guest_notification(guest_notification: GuestNotifications) -> Self {
236 Self {
237 message_version: MessageVersions::HEADER_VERSION_1,
238 message_type: MessageTypes::GUEST_NOTIFICATION,
239 message_id: MessageId::new_guest_notification(guest_notification),
240 }
241 }
242
243 pub fn guest_notification(&self) -> Option<GuestNotifications> {
245 if self.message_type == MessageTypes::GUEST_NOTIFICATION {
246 Some(self.message_id.guest_notification())
247 } else {
248 None
249 }
250 }
251
252 pub fn host_response(&self) -> Option<HostRequests> {
254 if self.message_type == MessageTypes::HOST_RESPONSE {
257 Some(self.message_id.host_request())
258 } else {
259 None
260 }
261 }
262
263 pub fn new_host_response(host_response: HostRequests) -> Self {
265 Self {
266 message_version: MessageVersions::HEADER_VERSION_1,
267 message_type: MessageTypes::HOST_RESPONSE,
268 message_id: MessageId::new_host_request(host_response),
269 }
270 }
271
272 pub fn host_request(&self) -> Option<HostRequests> {
274 if self.message_type == MessageTypes::HOST_REQUEST {
275 Some(self.message_id.host_request())
276 } else {
277 None
278 }
279 }
280
281 pub fn new_host_request(host_request: HostRequests) -> Self {
283 Self {
284 message_version: MessageVersions::HEADER_VERSION_1,
285 message_type: MessageTypes::HOST_REQUEST,
286 message_id: MessageId::new_host_request(host_request),
287 }
288 }
289
290 pub fn new_host_notification(host_notification: HostNotifications) -> Self {
292 Self {
293 message_version: MessageVersions::HEADER_VERSION_1,
294 message_type: MessageTypes::HOST_NOTIFICATION,
295 message_id: MessageId::new_host_notification(host_notification),
296 }
297 }
298
299 pub fn host_notification(&self) -> Option<HostNotifications> {
301 if self.message_type == MessageTypes::HOST_NOTIFICATION {
302 Some(self.message_id.host_notification())
303 } else {
304 None
305 }
306 }
307}
308
309const_assert_eq!(4, size_of::<Header>());
310
311pub const UART_MSG_MAX_PAYLOAD: usize = 64;
313
314#[repr(C)]
321#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
322pub struct TxDataAvailableMessage {
323 pub header: Header,
325 pub buffer_length: u8,
327 pub buffer: [u8; UART_MSG_MAX_PAYLOAD],
329 pub pad: u8,
331}
332
333impl Default for TxDataAvailableMessage {
334 fn default() -> Self {
335 Self {
336 header: Header::default(),
337 buffer_length: 0,
338 buffer: [0; UART_MSG_MAX_PAYLOAD],
339 pad: 0,
340 }
341 }
342}
343
344const_assert_eq!(70, size_of::<TxDataAvailableMessage>());
345
346#[repr(C)]
350#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
351pub struct SetModumStatusMessage {
352 pub header: Header,
354 pub modem_status: u8,
356 pub is_connected: u8,
358}
359
360const_assert_eq!(6, size_of::<SetModumStatusMessage>());
361
362#[repr(C)]
366#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
367pub struct VersionRequestMessage {
368 pub header: Header,
370 pub requested_version: ProtocolVersions,
372}
373
374impl Default for VersionRequestMessage {
375 fn default() -> Self {
376 Self {
377 header: Header::default(),
378 requested_version: ProtocolVersions(0),
379 }
380 }
381}
382
383const_assert_eq!(8, size_of::<VersionRequestMessage>());
384
385#[repr(C)]
387#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
388pub struct VersionRequestResponse {
389 pub header: Header,
391 pub version_accepted: u8,
393 pub pad: u8,
395}
396
397const_assert_eq!(6, size_of::<VersionRequestResponse>());
398
399#[repr(C)]
401#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
402pub struct RxDataResponse {
403 pub header: Header,
405 pub buffer_length: u8,
407 pub more_data_available: u8,
409 pub buffer: [u8; UART_MSG_MAX_PAYLOAD],
411}
412
413const_assert_eq!(70, size_of::<RxDataResponse>());
414
415impl Default for RxDataResponse {
416 fn default() -> Self {
417 Self {
418 header: Header::default(),
419 buffer_length: 0,
420 more_data_available: 0,
421 buffer: [0; UART_MSG_MAX_PAYLOAD],
422 }
423 }
424}