Removed the active/inactive concept, and changed bus to use blocking traits to allow users to use shared-bus
This commit is contained in:
parent
55097322a0
commit
ca8268ab31
13 changed files with 127 additions and 239 deletions
|
|
@ -1,50 +1,43 @@
|
|||
#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]
|
||||
|
||||
use core::fmt;
|
||||
use embedded_hal::blocking::spi::{Transfer, Write};
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_hal::spi::FullDuplex;
|
||||
|
||||
use crate::bus::{ActiveBus, Bus};
|
||||
use crate::bus::Bus;
|
||||
|
||||
const WRITE_MODE_MASK: u8 = 0b00000_1_00;
|
||||
|
||||
pub struct FourWire<ChipSelect: OutputPin> {
|
||||
cs: ChipSelect,
|
||||
}
|
||||
|
||||
impl<ChipSelect: OutputPin> FourWire<ChipSelect> {
|
||||
pub fn new(cs: ChipSelect) -> Self {
|
||||
Self { cs }
|
||||
}
|
||||
pub fn release(self) -> ChipSelect {
|
||||
self.cs
|
||||
}
|
||||
}
|
||||
|
||||
impl<ChipSelect: OutputPin> Bus for FourWire<ChipSelect> {}
|
||||
|
||||
impl<ChipSelect: OutputPin> FourWire<ChipSelect> {
|
||||
pub fn activate<Spi: FullDuplex<u8>>(self, spi: Spi) -> ActiveFourWire<Spi, ChipSelect> {
|
||||
ActiveFourWire { cs: self.cs, spi }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ActiveFourWire<Spi: FullDuplex<u8>, ChipSelect: OutputPin> {
|
||||
pub struct FourWire<Spi: Transfer<u8> + Write<u8>, ChipSelect: OutputPin> {
|
||||
cs: ChipSelect,
|
||||
spi: Spi,
|
||||
}
|
||||
|
||||
impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveBus for ActiveFourWire<Spi, ChipSelect> {
|
||||
type Error = FourWireError<Spi::Error, ChipSelect::Error>;
|
||||
impl<Spi: Transfer<u8> + Write<u8>, ChipSelect: OutputPin> FourWire<Spi, ChipSelect> {
|
||||
pub fn new(spi: Spi, cs: ChipSelect) -> Self {
|
||||
Self { spi, cs }
|
||||
}
|
||||
|
||||
pub fn release(self) -> (Spi, ChipSelect) {
|
||||
(self.spi, self.cs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Spi: Transfer<u8> + Write<u8>, ChipSelect: OutputPin> Bus for FourWire<Spi, ChipSelect> {
|
||||
type Error =
|
||||
FourWireError<<Spi as Transfer<u8>>::Error, <Spi as Write<u8>>::Error, ChipSelect::Error>;
|
||||
fn read_frame(&mut self, block: u8, address: u16, data: &mut [u8]) -> Result<(), Self::Error> {
|
||||
let address_phase = address.to_be_bytes();
|
||||
let control_phase = block << 3;
|
||||
let data_phase = data;
|
||||
self.cs.set_low().map_err(FourWireError::ChipSelectError)?;
|
||||
Self::write_bytes(&mut self.spi, &address_phase)
|
||||
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
|
||||
.and_then(|_| Self::read_bytes(&mut self.spi, data_phase))
|
||||
.map_err(FourWireError::SpiError)?;
|
||||
self.spi
|
||||
.write(&address_phase)
|
||||
.and_then(|_| self.spi.write(&[control_phase]))
|
||||
.map_err(FourWireError::WriteError)?;
|
||||
self.spi
|
||||
.transfer(data_phase)
|
||||
.map_err(FourWireError::TransferError)?;
|
||||
self.cs.set_high().map_err(FourWireError::ChipSelectError)?;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -54,37 +47,40 @@ impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveBus for ActiveFourWire<Sp
|
|||
let control_phase = block << 3 | WRITE_MODE_MASK;
|
||||
let data_phase = data;
|
||||
self.cs.set_low().map_err(FourWireError::ChipSelectError)?;
|
||||
Self::write_bytes(&mut self.spi, &address_phase)
|
||||
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
|
||||
.and_then(|_| Self::write_bytes(&mut self.spi, data_phase))
|
||||
.map_err(FourWireError::SpiError)?;
|
||||
self.spi
|
||||
.write(&address_phase)
|
||||
.and_then(|_| self.spi.write(&[control_phase]))
|
||||
.and_then(|_| self.spi.write(data_phase))
|
||||
.map_err(FourWireError::WriteError)?;
|
||||
self.cs.set_high().map_err(FourWireError::ChipSelectError)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveFourWire<Spi, ChipSelect> {
|
||||
pub fn deactivate(self) -> (FourWire<ChipSelect>, Spi) {
|
||||
(FourWire::new(self.cs), self.spi)
|
||||
}
|
||||
}
|
||||
|
||||
// Must use map_err, ambiguity prevents From from being implemented
|
||||
#[repr(u8)]
|
||||
pub enum FourWireError<SpiError, ChipSelectError> {
|
||||
SpiError(SpiError),
|
||||
pub enum FourWireError<TransferError, WriteError, ChipSelectError> {
|
||||
TransferError(TransferError),
|
||||
WriteError(WriteError),
|
||||
ChipSelectError(ChipSelectError),
|
||||
}
|
||||
|
||||
impl<SpiError, ChipSelectError> fmt::Debug for FourWireError<SpiError, ChipSelectError> {
|
||||
impl<TransferError, WriteError, ChipSelectError> fmt::Debug
|
||||
for FourWireError<TransferError, WriteError, ChipSelectError>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"FourWireError::{}",
|
||||
match self {
|
||||
Self::SpiError(_) => "SpiError",
|
||||
Self::TransferError(_) => "TransferError",
|
||||
Self::WriteError(_) => "WriteError",
|
||||
Self::ChipSelectError(_) => "ChipSelectError",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Improved error rendering could be done with specialization.
|
||||
// https://github.com/rust-lang/rust/issues/31844
|
||||
|
|
|
|||
|
|
@ -1,38 +1,15 @@
|
|||
use core::fmt::Debug;
|
||||
use embedded_hal::spi::FullDuplex;
|
||||
|
||||
mod four_wire;
|
||||
mod three_wire;
|
||||
|
||||
pub use self::four_wire::ActiveFourWire;
|
||||
pub use self::four_wire::FourWire;
|
||||
pub use self::three_wire::ActiveThreeWire;
|
||||
pub use self::three_wire::ThreeWire;
|
||||
|
||||
pub trait Bus {}
|
||||
|
||||
pub trait ActiveBus {
|
||||
pub trait Bus {
|
||||
type Error: Debug;
|
||||
|
||||
fn read_frame(&mut self, block: u8, address: u16, data: &mut [u8]) -> Result<(), Self::Error>;
|
||||
|
||||
fn write_frame(&mut self, block: u8, address: u16, data: &[u8]) -> Result<(), Self::Error>;
|
||||
|
||||
fn read_bytes<Spi: FullDuplex<u8>>(spi: &mut Spi, bytes: &mut [u8]) -> Result<(), Spi::Error> {
|
||||
for byte in bytes.iter_mut() {
|
||||
*byte = Self::transfer_byte(spi, *byte)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes<Spi: FullDuplex<u8>>(spi: &mut Spi, bytes: &[u8]) -> Result<(), Spi::Error> {
|
||||
for byte in bytes.iter() {
|
||||
Self::transfer_byte(spi, *byte)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer_byte<Spi: FullDuplex<u8>>(spi: &mut Spi, byte: u8) -> Result<u8, Spi::Error> {
|
||||
block!(spi.send(byte)).and_then(|_| block!(spi.read()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]
|
||||
|
||||
use core::fmt;
|
||||
use embedded_hal::spi::FullDuplex;
|
||||
use embedded_hal::blocking::spi::{Transfer, Write};
|
||||
|
||||
use crate::bus::{ActiveBus, Bus};
|
||||
use crate::bus::Bus;
|
||||
|
||||
const WRITE_MODE_MASK: u8 = 0b00000_1_0;
|
||||
|
||||
|
|
@ -11,34 +11,22 @@ const FIXED_DATA_LENGTH_MODE_1: u8 = 0b000000_01;
|
|||
const FIXED_DATA_LENGTH_MODE_2: u8 = 0b000000_10;
|
||||
const FIXED_DATA_LENGTH_MODE_4: u8 = 0b000000_11;
|
||||
|
||||
pub struct ThreeWire {}
|
||||
|
||||
impl ThreeWire {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ThreeWire {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Bus for ThreeWire {}
|
||||
|
||||
impl ThreeWire {
|
||||
pub fn activate<Spi: FullDuplex<u8>>(self, spi: Spi) -> ActiveThreeWire<Spi> {
|
||||
ActiveThreeWire { spi }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ActiveThreeWire<Spi: FullDuplex<u8>> {
|
||||
pub struct ThreeWire<Spi: Transfer<u8> + Write<u8>> {
|
||||
spi: Spi,
|
||||
}
|
||||
|
||||
impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
|
||||
type Error = ThreeWireError<Spi::Error>;
|
||||
impl<Spi: Transfer<u8> + Write<u8>> ThreeWire<Spi> {
|
||||
pub fn new(spi: Spi) -> Self {
|
||||
Self { spi }
|
||||
}
|
||||
|
||||
pub fn release(self) -> Spi {
|
||||
self.spi
|
||||
}
|
||||
}
|
||||
|
||||
impl<Spi: Transfer<u8> + Write<u8>> Bus for ThreeWire<Spi> {
|
||||
type Error = ThreeWireError<<Spi as Transfer<u8>>::Error, <Spi as Write<u8>>::Error>;
|
||||
|
||||
/// Transfers a frame with an arbitrary data length in FDM
|
||||
///
|
||||
|
|
@ -74,20 +62,20 @@ impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
|
|||
}
|
||||
|
||||
let address_phase = address.to_be_bytes();
|
||||
Self::write_bytes(&mut self.spi, &address_phase)
|
||||
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
|
||||
.and_then(|_| {
|
||||
Self::read_bytes(
|
||||
&mut self.spi,
|
||||
&mut data_phase[..last_length_written as usize],
|
||||
)
|
||||
})?;
|
||||
self.spi
|
||||
.write(&address_phase)
|
||||
.and_then(|_| self.spi.write(&[control_phase]))
|
||||
.map_err(ThreeWireError::WriteError)?;
|
||||
self.spi
|
||||
.transfer(&mut data_phase[..last_length_written as usize])
|
||||
.map_err(ThreeWireError::TransferError)?;
|
||||
|
||||
address += last_length_written;
|
||||
data_phase = &mut data_phase[last_length_written as usize..];
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_frame(&mut self, block: u8, mut address: u16, data: &[u8]) -> Result<(), Self::Error> {
|
||||
let mut control_phase = block << 3 | WRITE_MODE_MASK;
|
||||
|
||||
|
|
@ -106,11 +94,11 @@ impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
|
|||
}
|
||||
|
||||
let address_phase = address.to_be_bytes();
|
||||
Self::write_bytes(&mut self.spi, &address_phase)
|
||||
.and_then(|_| Self::transfer_byte(&mut self.spi, control_phase))
|
||||
.and_then(|_| {
|
||||
Self::write_bytes(&mut self.spi, &data_phase[..last_length_written as usize])
|
||||
})?;
|
||||
self.spi
|
||||
.write(&address_phase)
|
||||
.and_then(|_| self.spi.write(&[control_phase]))
|
||||
.and_then(|_| self.spi.write(&data_phase[..last_length_written as usize]))
|
||||
.map_err(ThreeWireError::WriteError)?;
|
||||
|
||||
address += last_length_written;
|
||||
data_phase = &data_phase[last_length_written as usize..];
|
||||
|
|
@ -119,29 +107,20 @@ impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Spi: FullDuplex<u8>> ActiveThreeWire<Spi> {
|
||||
pub fn deactivate(self) -> (ThreeWire, Spi) {
|
||||
(ThreeWire::new(), self.spi)
|
||||
}
|
||||
// Must use map_err, ambiguity prevents From from being implemented
|
||||
pub enum ThreeWireError<TransferError, WriteError> {
|
||||
TransferError(TransferError),
|
||||
WriteError(WriteError),
|
||||
}
|
||||
|
||||
pub enum ThreeWireError<SpiError> {
|
||||
SpiError(SpiError),
|
||||
}
|
||||
|
||||
impl<SpiError> From<SpiError> for ThreeWireError<SpiError> {
|
||||
fn from(error: SpiError) -> ThreeWireError<SpiError> {
|
||||
ThreeWireError::SpiError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<SpiError> fmt::Debug for ThreeWireError<SpiError> {
|
||||
impl<TransferError, WriteError> fmt::Debug for ThreeWireError<TransferError, WriteError> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ThreeWireError::{}",
|
||||
match self {
|
||||
Self::SpiError(_) => "SpiError",
|
||||
Self::TransferError(_) => "TransferError",
|
||||
Self::WriteError(_) => "WriteError",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue