Skip to content
This repository has been archived by the owner on Dec 27, 2023. It is now read-only.

SpiBus -> SpiDevice #35

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 40 additions & 132 deletions src/interface.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use defmt::trace;
use embedded_hal_async::spi::SpiBus;
use embedded_hal_async::spi::{Operation, SpiDevice};

use crate::mod_params::RadioError;
use crate::mod_params::RadioError::*;
use crate::mod_params::RadioError::{self, SPI};
use crate::mod_traits::InterfaceVariant;

pub(crate) struct SpiInterface<SPI, IV> {
Expand All @@ -12,168 +11,77 @@ pub(crate) struct SpiInterface<SPI, IV> {

impl<SPI, IV> SpiInterface<SPI, IV>
where
SPI: SpiBus<u8>,
SPI: SpiDevice<u8>,
IV: InterfaceVariant,
{
pub fn new(spi: SPI, iv: IV) -> Self {
Self { spi, iv }
}

// Write one or more buffers to the radio.
pub async fn write(&mut self, write_buffers: &[&[u8]], is_sleep_command: bool) -> Result<(), RadioError> {
self.iv.set_nss_low().await?;
for buffer in write_buffers {
let write_result = self.spi.write(buffer).await.map_err(|_| SPI);
let flush_result = self.spi.flush().await.map_err(|_| SPI);
if write_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
write_result?;
} else if flush_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
flush_result?;
}
}
self.iv.set_nss_high().await?;
// Write a buffer to the radio.
pub async fn write(&mut self, write_buffer: &[u8], is_sleep_command: bool) -> Result<(), RadioError> {
self.spi.write(write_buffer).await.map_err(|_| SPI)?;

if !is_sleep_command {
self.iv.wait_on_busy().await?;
}

match write_buffers.len() {
1 => trace!("write: 0x{:x}", write_buffers[0]),
2 => trace!("write: 0x{:x} 0x{:x}", write_buffers[0], write_buffers[1]),
3 => trace!(
"write: 0x{:x} 0x{:x} 0x{:x}",
write_buffers[0],
write_buffers[1],
write_buffers[2]
),
_ => trace!("write: too many buffers"),
}
trace!("write: 0x{:x}", write_buffer);

Ok(())
}

// Request a read, filling the provided buffer.
pub async fn read(
// Write
pub async fn write_with_payload(
&mut self,
write_buffers: &[&[u8]],
read_buffer: &mut [u8],
read_length: Option<u8>,
write_buffer: &[u8],
payload: &[u8],
is_sleep_command: bool,
) -> Result<(), RadioError> {
let mut input = [0u8];

self.iv.set_nss_low().await?;
for buffer in write_buffers {
let write_result = self.spi.write(buffer).await.map_err(|_| SPI);
let flush_result = self.spi.flush().await.map_err(|_| SPI);
if write_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
write_result?;
} else if flush_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
flush_result?;
}
let mut ops = [Operation::Write(write_buffer), Operation::Write(payload)];
self.spi.transaction(&mut ops).await.map_err(|_| SPI)?;

if !is_sleep_command {
self.iv.wait_on_busy().await?;
}

let number_to_read = match read_length {
Some(len) => len as usize,
None => read_buffer.len(),
};

#[allow(clippy::needless_range_loop)]
for i in 0..number_to_read {
let transfer_result = self.spi.transfer(&mut input, &[0x00]).await.map_err(|_| SPI);
let flush_result = self.spi.flush().await.map_err(|_| SPI);
if transfer_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
transfer_result?;
} else if flush_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
flush_result?;
}
read_buffer[i] = input[0];
trace!("write: 0x{:x}", write_buffer);

Ok(())
}

// Request a read, filling the provided buffer.
pub async fn read(&mut self, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), RadioError> {
{
let mut ops = [Operation::Write(write_buffer), Operation::Read(read_buffer)];

self.spi.transaction(&mut ops).await.map_err(|_| SPI)?;
}
self.iv.set_nss_high().await?;

self.iv.wait_on_busy().await?;

match write_buffers.len() {
1 => trace!("write: 0x{:x}", write_buffers[0]),
2 => trace!("write: 0x{:x} 0x{:x}", write_buffers[0], write_buffers[1]),
3 => trace!(
"write: 0x{:x} 0x{:x} 0x{:x}",
write_buffers[0],
write_buffers[1],
write_buffers[2]
),
_ => trace!("write: too many buffers"),
}
trace!("read {}: 0x{:x}", number_to_read, read_buffer);
trace!("write: 0x{:x}", write_buffer);
trace!("read {}: 0x{:x}", read_buffer.len(), read_buffer);

Ok(())
}

// Request a read with status, filling the provided buffer and returning the status.
pub async fn read_with_status(
&mut self,
write_buffers: &[&[u8]],
read_buffer: &mut [u8],
) -> Result<u8, RadioError> {
pub async fn read_with_status(&mut self, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<u8, RadioError> {
let mut status = [0u8];
let mut input = [0u8];

self.iv.set_nss_low().await?;
for buffer in write_buffers {
let write_result = self.spi.write(buffer).await.map_err(|_| SPI);
let flush_result = self.spi.flush().await.map_err(|_| SPI);
if write_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
write_result?;
} else if flush_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
flush_result?;
}
{
let mut ops = [
Operation::Write(write_buffer),
Operation::Read(&mut status),
Operation::Read(read_buffer),
];

self.spi.transaction(&mut ops).await.map_err(|_| SPI)?;
}

let transfer_result = self.spi.transfer(&mut status, &[0x00]).await.map_err(|_| SPI);
let flush_result = self.spi.flush().await.map_err(|_| SPI);
if transfer_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
transfer_result?;
} else if flush_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
flush_result?;
}

#[allow(clippy::needless_range_loop)]
for i in 0..read_buffer.len() {
let transfer_result = self.spi.transfer(&mut input, &[0x00]).await.map_err(|_| SPI);
let flush_result = self.spi.flush().await.map_err(|_| SPI);
if transfer_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
transfer_result?;
} else if flush_result != Ok(()) {
let _err = self.iv.set_nss_high().await;
flush_result?;
}
read_buffer[i] = input[0];
}
self.iv.set_nss_high().await?;

self.iv.wait_on_busy().await?;

match write_buffers.len() {
1 => trace!("write: 0x{:x}", write_buffers[0]),
2 => trace!("write: 0x{:x} 0x{:x}", write_buffers[0], write_buffers[1]),
3 => trace!(
"write: 0x{:x} 0x{:x} 0x{:x}",
write_buffers[0],
write_buffers[1],
write_buffers[2]
),
_ => trace!("write: too many buffers"),
}
trace!("write: 0x{:x}", write_buffer);
trace!(
"read {} status 0x{:x}: 0x{:x}",
read_buffer.len(),
Expand Down
1 change: 0 additions & 1 deletion src/mod_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ pub use lora_modulation::{Bandwidth, CodingRate, SpreadingFactor};
#[allow(dead_code, missing_docs)]
pub enum RadioError {
SPI,
NSS,
Reset,
RfSwitchRx,
RfSwitchTx,
Expand Down
4 changes: 0 additions & 4 deletions src/mod_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ use crate::mod_params::*;
pub trait InterfaceVariant {
/// Set the LoRa board type
fn set_board_type(&mut self, board_type: BoardType);
/// Select the LoRa chip for an operation
async fn set_nss_low(&mut self) -> Result<(), RadioError>;
/// De-select the LoRa chip after an operation
async fn set_nss_high(&mut self) -> Result<(), RadioError>;
/// Reset the LoRa chip
async fn reset(&mut self, delay: &mut impl DelayUs) -> Result<(), RadioError>;
/// Wait for the LoRa chip to become available for an operation
Expand Down
Loading