bt_hci/
transport.rs

1//! HCI transport layers [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface.html)
2
3use core::future::Future;
4
5use embassy_sync::blocking_mutex::raw::RawMutex;
6use embassy_sync::mutex::Mutex;
7use embedded_io::{ErrorType, ReadExactError};
8
9use crate::controller::blocking::TryError;
10use crate::{ControllerToHostPacket, FromHciBytesError, HostToControllerPacket, ReadHci, ReadHciError, WriteHci};
11
12/// A packet-oriented HCI Transport Layer
13pub trait Transport: embedded_io::ErrorType {
14    /// Read a complete HCI packet into the rx buffer
15    fn read<'a>(&self, rx: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>>;
16    /// Write a complete HCI packet from the tx buffer
17    fn write<T: HostToControllerPacket>(&self, val: &T) -> impl Future<Output = Result<(), Self::Error>>;
18}
19
20/// HCI transport layer for a split serial bus using the UART transport layer protocol [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/uart-transport-layer.html)
21pub struct SerialTransport<M: RawMutex, R, W> {
22    reader: Mutex<M, R>,
23    writer: Mutex<M, W>,
24}
25
26/// Error type for HCI transport layer communication errors.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum Error<E: embedded_io::Error> {
30    /// Error reading HCI data.
31    Read(ReadHciError<E>),
32    /// Error writing data.
33    Write(E),
34}
35
36impl<E: embedded_io::Error> embedded_io::Error for Error<E> {
37    fn kind(&self) -> embedded_io::ErrorKind {
38        match self {
39            Self::Read(e) => e.kind(),
40            Self::Write(e) => e.kind(),
41        }
42    }
43}
44
45impl<E: embedded_io::Error> From<E> for Error<E> {
46    fn from(e: E) -> Self {
47        Self::Write(e)
48    }
49}
50
51impl<E: embedded_io::Error> From<ReadHciError<E>> for Error<E> {
52    fn from(e: ReadHciError<E>) -> Self {
53        Self::Read(e)
54    }
55}
56
57impl<E: embedded_io::Error> From<ReadExactError<E>> for Error<E> {
58    fn from(e: ReadExactError<E>) -> Self {
59        Self::Read(e.into())
60    }
61}
62
63impl<E: embedded_io::Error> From<FromHciBytesError> for Error<E> {
64    fn from(e: FromHciBytesError) -> Self {
65        Self::Read(e.into())
66    }
67}
68
69impl<M: RawMutex, R: embedded_io_async::Read, W: embedded_io_async::Write> SerialTransport<M, R, W> {
70    /// Create a new instance.
71    pub fn new(reader: R, writer: W) -> Self {
72        Self {
73            reader: Mutex::new(reader),
74            writer: Mutex::new(writer),
75        }
76    }
77}
78
79impl<
80        M: RawMutex,
81        R: embedded_io::ErrorType<Error = E>,
82        W: embedded_io::ErrorType<Error = E>,
83        E: embedded_io::Error,
84    > ErrorType for SerialTransport<M, R, W>
85{
86    type Error = Error<E>;
87}
88
89impl<
90        M: RawMutex,
91        R: embedded_io_async::Read<Error = E>,
92        W: embedded_io_async::Write<Error = E>,
93        E: embedded_io::Error,
94    > Transport for SerialTransport<M, R, W>
95{
96    async fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, Self::Error> {
97        let mut r = self.reader.lock().await;
98        ControllerToHostPacket::read_hci_async(&mut *r, rx)
99            .await
100            .map_err(Error::Read)
101    }
102
103    async fn write<T: HostToControllerPacket>(&self, tx: &T) -> Result<(), Self::Error> {
104        let mut w = self.writer.lock().await;
105        WithIndicator(tx)
106            .write_hci_async(&mut *w)
107            .await
108            .map_err(|e| Error::Write(e))
109    }
110}
111
112impl<M: RawMutex, R: embedded_io::Read<Error = E>, W: embedded_io::Write<Error = E>, E: embedded_io::Error>
113    blocking::Transport for SerialTransport<M, R, W>
114{
115    fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, TryError<Self::Error>> {
116        let mut r = self.reader.try_lock().map_err(|_| TryError::Busy)?;
117        ControllerToHostPacket::read_hci(&mut *r, rx)
118            .map_err(Error::Read)
119            .map_err(TryError::Error)
120    }
121
122    fn write<T: HostToControllerPacket>(&self, tx: &T) -> Result<(), TryError<Self::Error>> {
123        let mut w = self.writer.try_lock().map_err(|_| TryError::Busy)?;
124        WithIndicator(tx)
125            .write_hci(&mut *w)
126            .map_err(|e| Error::Write(e))
127            .map_err(TryError::Error)
128    }
129}
130
131/// Wrapper for a [`HostToControllerPacket`] that will write the [`PacketKind`](crate::PacketKind) indicator byte before the packet itself
132/// when serialized with [`WriteHci`].
133///
134/// This is used for transports where all packets are sent over a common channel, such as the UART transport.
135pub struct WithIndicator<'a, T: HostToControllerPacket>(&'a T);
136
137impl<'a, T: HostToControllerPacket> WithIndicator<'a, T> {
138    /// Create a new instance.
139    pub fn new(pkt: &'a T) -> Self {
140        Self(pkt)
141    }
142}
143
144impl<T: HostToControllerPacket> WriteHci for WithIndicator<'_, T> {
145    #[inline(always)]
146    fn size(&self) -> usize {
147        1 + self.0.size()
148    }
149
150    #[inline(always)]
151    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
152        T::KIND.write_hci(&mut writer)?;
153        self.0.write_hci(writer)
154    }
155
156    #[inline(always)]
157    async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
158        T::KIND.write_hci_async(&mut writer).await?;
159        self.0.write_hci_async(writer).await
160    }
161}
162
163pub mod blocking {
164    //! Blocking transport trait.
165    use super::*;
166    use crate::controller::blocking::TryError;
167
168    /// A packet-oriented HCI Transport Layer
169    pub trait Transport: embedded_io::ErrorType {
170        /// Read a complete HCI packet into the rx buffer
171        fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, TryError<Self::Error>>;
172        /// Write a complete HCI packet from the tx buffer
173        fn write<T: HostToControllerPacket>(&self, val: &T) -> Result<(), TryError<Self::Error>>;
174    }
175}