1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4use std::mem;
5
6use fmi_sys::ls_bus;
7
8#[cfg(feature = "can")]
9#[cfg_attr(docsrs, doc(cfg(feature = "can")))]
10pub mod can;
11#[cfg(test)]
12mod tests;
13
14#[derive(Debug, thiserror::Error)]
15pub enum FmiLsBusError {
16 #[error("Buffer overflow: not enough space in buffer")]
17 BufferOverflow,
18 #[error("Invalid variant code: {0}")]
19 InvalidVariant(u32),
20 #[error("Invalid operation code or size mismatch: {0}")]
21 InvalidOperation(ls_bus::fmi3LsBusOperationCode),
22}
23
24pub trait LsBusOperation<'a>: Sized {
25 fn transmit(self, buffer: &mut [u8]) -> Result<usize, FmiLsBusError>;
28
29 fn read_next_operation(
30 buffer: &'a [u8],
31 read_pos: &mut usize,
32 ) -> Result<Option<Self>, FmiLsBusError>;
33}
34
35#[derive(Debug, Default)]
43pub struct FmiLsBus {
44 pub read_pos: usize,
45 pub write_pos: usize,
46}
47
48impl FmiLsBus {
49 pub fn new() -> Self {
51 Self {
52 read_pos: 0,
53 write_pos: 0,
54 }
55 }
56
57 pub fn reset(&mut self) {
61 self.read_pos = 0;
62 self.write_pos = 0;
63 }
64
65 pub fn start(buffer: &[u8]) -> *const u8 {
69 buffer.as_ptr()
70 }
71
72 pub fn write_operation<'a, OP: LsBusOperation<'a>>(
73 &mut self,
74 op: OP,
75 buffer: &mut [u8],
76 ) -> Result<(), FmiLsBusError> {
77 let available_slice = &mut buffer[self.write_pos..];
79 let bytes_written = op.transmit(available_slice)?;
80 self.write_pos += bytes_written;
81 Ok(())
82 }
83
84 pub fn write(&mut self, buffer: &mut [u8], data: &[u8]) -> Result<(), FmiLsBusError> {
88 if data.len() <= buffer.len() {
89 let copy_len = data.len();
90 buffer[..copy_len].copy_from_slice(data);
91 self.read_pos = 0;
92 self.write_pos = copy_len;
93 Ok(())
94 } else {
95 Err(FmiLsBusError::BufferOverflow)
96 }
97 }
98
99 pub fn peek_next_operation(
101 &self,
102 buffer: &[u8],
103 ) -> Option<(ls_bus::fmi3LsBusOperationCode, usize)> {
104 let remaining = buffer.len() - self.read_pos;
105
106 if remaining < mem::size_of::<ls_bus::fmi3LsBusOperationHeader>() {
108 return None;
109 }
110
111 let header_bytes = &buffer
113 [self.read_pos..self.read_pos + mem::size_of::<ls_bus::fmi3LsBusOperationHeader>()];
114 let header = unsafe {
115 std::ptr::read_unaligned(
116 header_bytes.as_ptr() as *const ls_bus::fmi3LsBusOperationHeader
117 )
118 };
119
120 Some((header.opCode, header.length as usize))
121 }
122
123 pub fn read_next_operation<'a, OP: LsBusOperation<'a>>(
130 &mut self,
131 buffer: &'a [u8],
132 ) -> Result<Option<OP>, FmiLsBusError> {
133 OP::read_next_operation(buffer, &mut self.read_pos)
134 }
135}