1#![no_std]
7
8use embedded_hal::blocking::{i2c, spi};
9use embedded_hal::serial;
10use phm_icd::{
11 Error as IcdError, ToMcu, ToMcuI2c, ToMcuSpi, ToMcuUart, ToPc, ToPcI2c, ToPcSpi, ToPcUart,
12};
13
14#[derive(Debug, defmt::Format, Eq, PartialEq)]
16pub enum Error {
17 Io,
18 I2c,
19 Spi,
20 Uart,
21 Internal,
22}
23
24pub mod comms {
26 use heapless::spsc::{Consumer, Producer, Queue};
27 use phm_icd::{Error as IcdError, ToMcu, ToPc};
28
29 pub struct CommsLink<const N: usize> {
31 pub to_pc: &'static mut Queue<Result<ToPc, IcdError>, N>,
32 pub to_mcu: &'static mut Queue<ToMcu, N>,
33 }
34
35 impl<const N: usize> CommsLink<N> {
36 pub fn split(self) -> (WorkerComms<N>, InterfaceComms<N>) {
42 let (to_pc_prod, to_pc_cons) = self.to_pc.split();
43 let (to_mcu_prod, to_mcu_cons) = self.to_mcu.split();
44
45 (
46 WorkerComms {
47 to_pc: to_pc_prod,
48 to_mcu: to_mcu_cons,
49 },
50 InterfaceComms {
51 to_pc: to_pc_cons,
52 to_mcu: to_mcu_prod,
53 },
54 )
55 }
56 }
57
58 pub struct WorkerComms<const N: usize> {
60 pub to_pc: Producer<'static, Result<ToPc, IcdError>, N>,
61 pub to_mcu: Consumer<'static, ToMcu, N>,
62 }
63
64 impl<const N: usize> crate::WorkerIo for WorkerComms<N> {
65 type Error = ();
66
67 fn send(&mut self, msg: Result<ToPc, IcdError>) -> Result<(), Self::Error> {
68 self.to_pc.enqueue(msg).map_err(drop)
69 }
70
71 fn receive(&mut self) -> Option<ToMcu> {
72 self.to_mcu.dequeue()
73 }
74 }
75
76 pub struct InterfaceComms<const N: usize> {
78 pub to_pc: Consumer<'static, Result<ToPc, IcdError>, N>,
79 pub to_mcu: Producer<'static, ToMcu, N>,
80 }
81}
82
83pub trait WorkerIo {
85 type Error;
86
87 fn send(&mut self, msg: Result<ToPc, IcdError>) -> Result<(), Self::Error>;
89
90 fn receive(&mut self) -> Option<ToMcu>;
92}
93
94pub struct Worker<IO, I2C, SPI, UART>
100where
101 IO: WorkerIo,
102 I2C: i2c::Write + i2c::Read + i2c::WriteRead,
103 SPI: spi::Write<u8> + spi::Transfer<u8>,
104 UART: serial::Write<u8> + serial::Read<u8>,
105{
106 pub io: IO,
107 pub i2c: I2C,
108 pub spi: SPI,
109 pub uart: UART,
110 uart_rx: heapless::Deque<u8, 64>,
111}
112
113impl<IO, I2C, SPI, UART> Worker<IO, I2C, SPI, UART>
114where
115 IO: WorkerIo,
116 I2C: i2c::Write + i2c::Read + i2c::WriteRead,
117 SPI: spi::Write<u8> + spi::Transfer<u8>,
118 UART: serial::Write<u8> + serial::Read<u8>,
119{
120 pub fn new(io: IO, i2c: I2C, spi: SPI, uart: UART) -> Self {
121 Worker {
122 io,
123 i2c,
124 spi,
125 uart,
126 uart_rx: heapless::Deque::new(),
127 }
128 }
129 pub fn step(&mut self) -> Result<(), Error> {
131 while let Ok(data_read) = serial::Read::<u8>::read(&mut self.uart) {
132 self.uart_rx.push_back(data_read).ok();
133 }
134 while let Some(data) = self.io.receive() {
135 let resp = match data {
136 ToMcu::I2c(i2c) => self.process_i2c(i2c),
137 ToMcu::Spi(spi) => self.process_spi(spi),
138 ToMcu::Uart(uart) => self.process_uart(uart),
139 ToMcu::Ping => {
140 defmt::info!("Received Ping! Responding...");
141 Ok(ToPc::Pong)
142 }
143 };
144 self.io.send(resp.map_err(drop)).map_err(|_| Error::Io)?;
145 }
146 Ok(())
147 }
148
149 fn process_i2c(&mut self, i2c_cmd: ToMcuI2c) -> Result<ToPc, Error> {
150 match i2c_cmd {
151 ToMcuI2c::Write { addr, output } => {
152 match i2c::Write::write(&mut self.i2c, addr, &output) {
154 Ok(_) => Ok(ToPc::I2c(ToPcI2c::WriteComplete { addr })),
155 Err(_) => Err(Error::I2c),
156 }
157 }
158 ToMcuI2c::Read { addr, to_read } => {
159 let mut buf = [0u8; 64];
160 let to_read_usize = to_read as usize;
161
162 if to_read_usize > buf.len() {
163 return Err(Error::I2c);
164 }
165 let buf_slice = &mut buf[..to_read_usize];
166
167 match i2c::Read::read(&mut self.i2c, addr, buf_slice) {
168 Ok(_) => Ok(ToPc::I2c(ToPcI2c::Read {
169 addr,
170 data_read: buf_slice.iter().cloned().collect(),
171 })),
172 Err(_) => Err(Error::I2c),
173 }
174 }
175 ToMcuI2c::WriteThenRead {
176 addr,
177 output,
178 to_read,
179 } => {
180 let mut buf = [0u8; 64];
181 let to_read_usize = to_read as usize;
182
183 if to_read_usize > buf.len() {
184 return Err(Error::I2c);
185 }
186 let buf_slice = &mut buf[..to_read_usize];
187
188 match i2c::WriteRead::write_read(&mut self.i2c, addr, &output, buf_slice) {
189 Ok(_) => Ok(ToPc::I2c(ToPcI2c::WriteThenRead {
190 addr,
191 data_read: buf_slice.iter().cloned().collect(),
192 })),
193 Err(_) => Err(Error::I2c),
194 }
195 }
196 }
197 }
198
199 fn process_spi(&mut self, spi_cmd: ToMcuSpi) -> Result<ToPc, Error> {
200 match spi_cmd {
201 ToMcuSpi::Write { output } => match spi::Write::write(&mut self.spi, &output) {
202 Ok(_) => Ok(ToPc::Spi(ToPcSpi::WriteComplete)),
203 Err(_) => Err(Error::Spi),
204 },
205
206 ToMcuSpi::Transfer { output } => {
207 let mut buf = [0u8; 64];
208
209 if output.len() > buf.len() {
210 return Err(Error::Spi);
211 }
212 let buf_slice = &mut buf[..output.len()];
213 buf_slice.copy_from_slice(&output);
214
215 match spi::Transfer::transfer(&mut self.spi, buf_slice) {
216 Ok(_) => Ok(ToPc::Spi(ToPcSpi::Transfer {
217 data_read: buf_slice.iter().cloned().collect(),
218 })),
219 Err(_) => Err(Error::Spi),
220 }
221 }
222 }
223 }
224
225 fn process_uart(&mut self, uart_cmd: ToMcuUart) -> Result<ToPc, Error> {
226 match uart_cmd {
227 ToMcuUart::Write { output } => {
228 for &b in output.iter() {
229 nb::block!(serial::Write::<u8>::write(&mut self.uart, b))
230 .map_err(|_| Error::Uart)?;
231 }
232 Ok(ToPc::Uart(ToPcUart::WriteComplete))
233 }
234 ToMcuUart::Flush => {
235 nb::block!(serial::Write::<u8>::flush(&mut self.uart)).map_err(|_| Error::Uart)?;
236 Ok(ToPc::Uart(ToPcUart::WriteComplete))
237 }
238 ToMcuUart::Read => {
239 let response = ToPc::Uart(ToPcUart::Read {
240 data_read: self.uart_rx.clone().into_iter().collect(),
241 });
242 self.uart_rx.clear();
243 Ok(response)
244 }
245 }
246 }
247}