Skip to content

Commit ddc9987

Browse files
committed
feat: do USB and SPI async
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
1 parent ab00bff commit ddc9987

File tree

3 files changed

+118
-68
lines changed

3 files changed

+118
-68
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

serprog/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ license = "Apache-2.0"
77
[dependencies]
88
embassy-usb.workspace = true
99
embassy-futures.workspace = true
10+
embassy-sync.workspace = true
1011
embedded-hal.workspace = true
1112
embedded-hal-async.workspace = true
1213
#log.workspace = true

serprog/src/lib.rs

Lines changed: 116 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
use core::convert::From;
44
use core::result::Result::{Err, Ok};
5+
use embassy_futures::{block_on, join::join};
6+
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
7+
use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
58
use embedded_hal::digital::OutputPin;
69
use embedded_hal_async::spi::SpiBus;
710
use num_enum::{IntoPrimitive, TryFromPrimitive};
@@ -34,7 +37,7 @@ fn le_u24_to_u32(bytes: &[u8]) -> u32 {
3437

3538
const S_ACK: u8 = 0x06;
3639
const S_NAK: u8 = 0x15;
37-
const MAX_BUFFER_SIZE: usize = 2048;
40+
const MAX_BUFFER_SIZE: usize = 16 << 20;
3841

3942
#[derive(FromBytes, IntoBytes, Unaligned, Immutable)]
4043
#[repr(C, packed)]
@@ -338,7 +341,7 @@ where
338341
}
339342
SerprogCommand::OSpiOp => {
340343
debug!("Received OSpiOp CMD");
341-
let mut sdata = [0_u8; MAX_BUFFER_SIZE + 6];
344+
let mut sdata = [0_u8; 64];
342345
self.transport
343346
.read(sdata.as_mut_slice())
344347
.await
@@ -347,75 +350,120 @@ where
347350
let op_slen = le_u24_to_u32(&sdata[0..3]) as usize;
348351
let op_rlen = le_u24_to_u32(&sdata[3..6]) as usize;
349352

350-
let mut rdata = [0_u8; MAX_BUFFER_SIZE];
353+
let mut usb_rx_spi_tx_buf = [([0u8; 64], 0); 4];
354+
let mut usb_rx_spi_tx_channel: Channel<'_, NoopRawMutex, ([u8; 64], usize)> =
355+
Channel::new(&mut usb_rx_spi_tx_buf);
356+
let (usb_rx, spi_tx) = usb_rx_spi_tx_channel.split();
357+
358+
let mut usb_tx_spi_rx_buf = [([0u8; 64], 0); 8];
359+
let mut usb_tx_spi_rx_channel: Channel<'_, NoopRawMutex, ([u8; 64], usize)> =
360+
Channel::new(&mut usb_tx_spi_rx_buf);
361+
let (spi_rx, usb_tx) = usb_tx_spi_rx_channel.split();
362+
363+
let usb_task = async |transport: &mut T,
364+
mut sender: Sender<NoopRawMutex, ([u8; 64], usize)>,
365+
sdata_size: usize,
366+
sdata_0: [u8; 64],
367+
mut receiver: Receiver<NoopRawMutex, ([u8; 64], usize)>,
368+
rdata_size: usize|
369+
-> Result<(), SerprogError> {
370+
// First block
371+
let mut data_to_read = sdata_size;
372+
{
373+
let (buf, size) = sender.send().await;
374+
let block_size = data_to_read.min(64 - 6);
375+
buf[..block_size].copy_from_slice(&sdata_0[6..6 + block_size]);
376+
*size = block_size;
377+
sender.send_done();
378+
data_to_read -= block_size;
379+
}
380+
381+
while data_to_read > 0 {
382+
let read_size = data_to_read.min(64);
383+
let (buf, size) = sender.send().await;
384+
*size = read_size;
385+
transport.read(&mut buf[..read_size]).await.map_err(|_| {
386+
SerprogError::TransportRead("Error reading OSpiOp data")
387+
})?;
388+
sender.send_done();
389+
data_to_read -= read_size;
390+
}
391+
transport
392+
.write(&[S_ACK])
393+
.await
394+
.map_err(|_| SerprogError::TransportWrite("Error writing SBustype ACK"))?;
351395

352-
let sdata = &sdata.as_slice()[6..6 + op_slen];
396+
let mut data_to_send = rdata_size;
397+
while data_to_send > 0 {
398+
let (buf, size) = receiver.receive().await;
399+
let size = *size;
400+
transport.write(&buf[..size]).await.map_err(|_| {
401+
SerprogError::TransportWrite("Error writing SPI read data")
402+
})?;
403+
receiver.receive_done();
404+
data_to_send -= size;
405+
}
406+
Ok(())
407+
};
353408

354-
debug!(
355-
"Starting SPI transfer, sdata: {:?}, rdata: {:?}",
356-
&sdata[..op_slen as usize],
357-
&rdata[..op_rlen as usize]
358-
);
409+
let spi_task = async |spi: &mut SPI,
410+
mut receiver: Receiver<NoopRawMutex, ([u8; 64], usize)>,
411+
sdata_size: usize,
412+
mut sender: Sender<NoopRawMutex, ([u8; 64], usize)>,
413+
rdata_size: usize,
414+
cs: &mut CS|
415+
-> Result<(), SerprogError> {
416+
spi.flush().await.map_err(|_| {
417+
SerprogError::SpiFlush("Error flushing SPI before transfer")
418+
})?;
419+
420+
cs.set_low()
421+
.map_err(|_| SerprogError::CsSetLow("Error setting CS low"))?;
422+
let mut data_to_write = sdata_size;
423+
while data_to_write > 0 {
424+
let (buf, size) = receiver.receive().await;
425+
data_to_write -= *size;
426+
spi.write(&buf[..*size])
427+
.await
428+
.map_err(|_| SerprogError::SpiTransfer("Error writing OSpiOp data"))?;
429+
receiver.receive_done();
430+
}
431+
let mut data_to_read = rdata_size;
432+
while data_to_read > 0 {
433+
let (buf, size) = sender.send().await;
434+
let read_size = data_to_read.min(buf.len());
435+
spi.read(&mut buf[..read_size])
436+
.await
437+
.map_err(|_| SerprogError::SpiTransfer("Error reading OSpiOp data"))?;
438+
*size = read_size;
439+
sender.send_done();
440+
data_to_read -= read_size;
441+
}
442+
cs.set_high()
443+
.map_err(|_| SerprogError::CsSetHigh("Error setting CS high"))?;
444+
debug!("OSpiOp CMD done");
445+
Ok(())
446+
};
359447

360-
// This call is blocking according to the SPI HAL
361-
self.spi
362-
.flush()
363-
.await
364-
.map_err(|_| SerprogError::SpiFlush("Error flushing SPI before transfer"))?;
365-
366-
self.cs
367-
.set_low()
368-
.map_err(|_| SerprogError::CsSetLow("Error setting CS low"))?;
369-
370-
let mut spi_op =
371-
async |spi: &mut SPI, transport: &mut T| -> Result<(), SerprogError> {
372-
match spi.write(&sdata[..op_slen as usize]).await {
373-
Ok(_) => {
374-
debug!("SPI transfer successful");
375-
debug!("Received data (rdata): {:?}", &rdata[..op_rlen as usize]);
376-
match spi.read(&mut rdata[..op_rlen as usize]).await {
377-
Ok(_) => {
378-
debug!("SPI read successful");
379-
debug!(
380-
"Received data (rdata): {:?}",
381-
&rdata[..op_rlen as usize]
382-
);
383-
transport.write(&[S_ACK]).await.map_err(|_| {
384-
SerprogError::TransportWrite("Error writing OSpiOp ACK")
385-
})?;
386-
387-
// Send the full rdata in chunks
388-
transport.write(&rdata[..op_rlen as usize]).await.map_err(
389-
|_| {
390-
SerprogError::TransportWrite(
391-
"Error writing SPI read data",
392-
)
393-
},
394-
)?;
395-
}
396-
Err(_) => {
397-
error!("SPI read error");
398-
if let Err(e) = transport.write(&[S_NAK]).await {
399-
error!("Error writing NAK: {:?}", e);
400-
}
401-
}
402-
}
403-
}
404-
Err(_) => {
405-
error!("SPI transfer error");
406-
transport.write(&[S_NAK]).await.map_err(|_| {
407-
SerprogError::TransportWrite("Error writing OSpiOp NAK")
408-
})?;
409-
Err(SerprogError::SpiTransfer("SPI transfer failed"))?;
410-
}
411-
}
412-
Ok(())
413-
};
414-
embassy_futures::block_on(spi_op(&mut self.spi, &mut self.transport))?;
415-
416-
self.cs
417-
.set_high()
418-
.map_err(|_| SerprogError::CsSetHigh("Error setting CS high"))?;
448+
let (spi_res, usb_res) = block_on(join(
449+
spi_task(
450+
&mut self.spi,
451+
spi_tx,
452+
op_slen,
453+
spi_rx,
454+
op_rlen,
455+
&mut self.cs,
456+
),
457+
usb_task(&mut self.transport, usb_rx, op_slen, sdata, usb_tx, op_rlen),
458+
));
459+
if let Err(spi_err) = spi_res {
460+
self.transport
461+
.write(&[S_NAK])
462+
.await
463+
.map_err(|_| SerprogError::TransportWrite("Failed to report SPI failed"))?;
464+
return Err(spi_err);
465+
}
466+
usb_res?;
419467

420468
Ok(())
421469
}

0 commit comments

Comments
 (0)