Skip to content

Commit

Permalink
Add trait and impl of blocking transports
Browse files Browse the repository at this point in the history
  • Loading branch information
lulf committed May 10, 2024
1 parent 29b51a3 commit db427d5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 38 deletions.
10 changes: 5 additions & 5 deletions src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use core::future::Future;

use crate::controller::{CmdError, ControllerCmdAsync, ControllerCmdSync, ErrorType};
use crate::param::param;
use crate::{FixedSizeValue, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
use crate::controller::{ControllerCmdAsync, ControllerCmdSync};
use crate::{param, FixedSizeValue, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
use embedded_io::ErrorType;

pub mod controller_baseband;
pub mod info;
Expand Down Expand Up @@ -112,7 +112,7 @@ pub trait AsyncCmd: Cmd {
fn exec<C: ControllerCmdAsync<Self>>(
&self,
controller: &C,
) -> impl Future<Output = Result<(), Error<<C as Controller>::Error>>> {
) -> impl Future<Output = Result<(), Error<<C as ErrorType>::Error>>> {
controller.exec(self)
}
}
Expand Down Expand Up @@ -155,7 +155,7 @@ pub trait SyncCmd: Cmd {
fn exec<C: ControllerCmdSync<Self>>(
&self,
controller: &C,
) -> impl Future<Output = Result<Self::Return, Error<<C as Controller>::Error>>> {
) -> impl Future<Output = Result<Self::Return, Error<<C as ErrorType>::Error>>> {
controller.exec(self)
}
}
Expand Down
29 changes: 1 addition & 28 deletions src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cmd::controller_baseband::Reset;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::signal::Signal;
use embassy_sync::waitqueue::AtomicWaker;
use embedded_io::ErrorType;
use futures_intrusive::sync::LocalSemaphore;

use crate::cmd::{Cmd, CmdReturnBuf};
Expand All @@ -19,10 +20,6 @@ use crate::{cmd, data, ControllerToHostPacket, FixedSizeValue, FromHciBytes, Hos

pub mod blocking;

pub trait ErrorType {
type Error: embedded_io::Error;
}

pub trait Controller: ErrorType {
fn write_acl_data(&self, packet: &data::AclPacket) -> impl Future<Output = Result<(), Self::Error>>;
fn write_sync_data(&self, packet: &data::SyncPacket) -> impl Future<Output = Result<(), Self::Error>>;
Expand All @@ -31,21 +28,6 @@ pub trait Controller: ErrorType {
fn read<'a>(&self, buf: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>>;
}

/// An error type for Bluetooth HCI commands.
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CmdError<E> {
Hci(param::Error),
Io(E),
}

/// An error type for try operations.
impl<E> From<param::Error> for CmdError<E> {
fn from(e: param::Error) -> Self {
Self::Hci(e)
}
}

pub trait ControllerCmdSync<C: cmd::SyncCmd + ?Sized>: Controller {
/// Note: Some implementations may require [`Controller::read()`] to be polled for this to return.
fn exec(&self, cmd: &C) -> impl Future<Output = Result<C::Return, cmd::Error<Self::Error>>>;
Expand All @@ -56,15 +38,6 @@ pub trait ControllerCmdAsync<C: cmd::AsyncCmd + ?Sized>: Controller {
fn exec(&self, cmd: &C) -> impl Future<Output = Result<(), cmd::Error<Self::Error>>>;
}

/// An external [`Controller`] with communication via [`Transport`] type `T`.
pub trait TryControllerCmdSync<C: cmd::SyncCmd + ?Sized>: TryController {
fn try_exec(&self, cmd: &C) -> Result<C::Return, TryError<CmdError<Self::Error>>>;
}

pub trait TryControllerCmdAsync<C: cmd::AsyncCmd + ?Sized>: TryController {
fn try_exec(&self, cmd: &C) -> Result<(), TryError<CmdError<Self::Error>>>;
}

/// An external Bluetooth controller with communication via [`Transport`] type `T`.
///
/// The controller state holds a number of command slots that can be used
Expand Down
53 changes: 48 additions & 5 deletions src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use core::future::Future;

use embassy_sync::blocking_mutex::raw::RawMutex;
use embassy_sync::mutex::Mutex;
use embedded_io::ReadExactError;
use embedded_io::{ErrorType, ReadExactError};

use crate::{ControllerToHostPacket, FromHciBytesError, HostToControllerPacket, ReadHci, ReadHciError, WriteHci};
use crate::{
controller::blocking::TryError, ControllerToHostPacket, FromHciBytesError, HostToControllerPacket, ReadHci,
ReadHciError, WriteHci,
};

/// A packet-oriented HCI Transport Layer
pub trait Transport {
type Error: embedded_io::Error;
pub trait Transport: embedded_io::ErrorType {
/// Read a complete HCI packet into the rx buffer
fn read<'a>(&self, rx: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>>;
/// Write a complete HCI packet from the tx buffer
Expand Down Expand Up @@ -73,14 +75,23 @@ impl<M: RawMutex, R: embedded_io_async::Read, W: embedded_io_async::Write> Seria
}
}

impl<
M: RawMutex,
R: embedded_io::ErrorType<Error = E>,
W: embedded_io::ErrorType<Error = E>,
E: embedded_io::Error,
> ErrorType for SerialTransport<M, R, W>
{
type Error = Error<E>;
}

impl<
M: RawMutex,
R: embedded_io_async::Read<Error = E>,
W: embedded_io_async::Write<Error = E>,
E: embedded_io::Error,
> Transport for SerialTransport<M, R, W>
{
type Error = Error<E>;
async fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, Self::Error> {
let mut r = self.reader.lock().await;
ControllerToHostPacket::read_hci_async(&mut *r, rx)
Expand All @@ -97,6 +108,25 @@ impl<
}
}

impl<M: RawMutex, R: embedded_io::Read<Error = E>, W: embedded_io::Write<Error = E>, E: embedded_io::Error>
blocking::Transport for SerialTransport<M, R, W>
{
fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, TryError<Self::Error>> {
let mut r = self.reader.try_lock().map_err(|_| TryError::Busy)?;
ControllerToHostPacket::read_hci(&mut *r, rx)
.map_err(Error::Read)
.map_err(TryError::Error)
}

fn write<T: HostToControllerPacket>(&self, tx: &T) -> Result<(), TryError<Self::Error>> {
let mut w = self.writer.try_lock().map_err(|_| TryError::Busy)?;
WithIndicator(tx)
.write_hci(&mut *w)
.map_err(|e| Error::Write(e))
.map_err(TryError::Error)
}
}

/// Wrapper for a [`HostToControllerPacket`] that will write the [`PacketKind`](crate::PacketKind) indicator byte before the packet itself
/// when serialized with [`WriteHci`].
///
Expand Down Expand Up @@ -127,3 +157,16 @@ impl<'a, T: HostToControllerPacket> WriteHci for WithIndicator<'a, T> {
self.0.write_hci_async(writer).await
}
}

pub mod blocking {
use super::*;
use crate::controller::blocking::TryError;

/// A packet-oriented HCI Transport Layer
pub trait Transport: embedded_io::ErrorType {
/// Read a complete HCI packet into the rx buffer
fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, TryError<Self::Error>>;
/// Write a complete HCI packet from the tx buffer
fn write<T: HostToControllerPacket>(&self, val: &T) -> Result<(), TryError<Self::Error>>;
}
}

0 comments on commit db427d5

Please sign in to comment.