Skip to main content

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> core::fmt::Display for Error<E> {
37    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38        write!(f, "{:?}", self)
39    }
40}
41
42impl<E: embedded_io::Error> core::error::Error for Error<E> {}
43
44impl<E: embedded_io::Error> embedded_io::Error for Error<E> {
45    fn kind(&self) -> embedded_io::ErrorKind {
46        match self {
47            Self::Read(e) => e.kind(),
48            Self::Write(e) => e.kind(),
49        }
50    }
51}
52
53impl<E: embedded_io::Error> From<E> for Error<E> {
54    fn from(e: E) -> Self {
55        Self::Write(e)
56    }
57}
58
59impl<E: embedded_io::Error> From<ReadHciError<E>> for Error<E> {
60    fn from(e: ReadHciError<E>) -> Self {
61        Self::Read(e)
62    }
63}
64
65impl<E: embedded_io::Error> From<ReadExactError<E>> for Error<E> {
66    fn from(e: ReadExactError<E>) -> Self {
67        Self::Read(e.into())
68    }
69}
70
71impl<E: embedded_io::Error> From<FromHciBytesError> for Error<E> {
72    fn from(e: FromHciBytesError) -> Self {
73        Self::Read(e.into())
74    }
75}
76
77impl<M: RawMutex, R: embedded_io_async::Read, W: embedded_io_async::Write> SerialTransport<M, R, W> {
78    /// Create a new instance.
79    pub fn new(reader: R, writer: W) -> Self {
80        Self {
81            reader: Mutex::new(reader),
82            writer: Mutex::new(writer),
83        }
84    }
85}
86
87impl<
88        M: RawMutex,
89        R: embedded_io::ErrorType<Error = E>,
90        W: embedded_io::ErrorType<Error = E>,
91        E: embedded_io::Error,
92    > ErrorType for SerialTransport<M, R, W>
93{
94    type Error = Error<E>;
95}
96
97impl<
98        M: RawMutex,
99        R: embedded_io_async::Read<Error = E>,
100        W: embedded_io_async::Write<Error = E>,
101        E: embedded_io::Error,
102    > Transport for SerialTransport<M, R, W>
103{
104    async fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, Self::Error> {
105        let mut r = self.reader.lock().await;
106        ControllerToHostPacket::read_hci_async(&mut *r, rx)
107            .await
108            .map_err(Error::Read)
109    }
110
111    async fn write<T: HostToControllerPacket>(&self, tx: &T) -> Result<(), Self::Error> {
112        let mut w = self.writer.lock().await;
113        WithIndicator(tx)
114            .write_hci_async(&mut *w)
115            .await
116            .map_err(|e| Error::Write(e))
117    }
118}
119
120impl<M: RawMutex, R: embedded_io::Read<Error = E>, W: embedded_io::Write<Error = E>, E: embedded_io::Error>
121    blocking::Transport for SerialTransport<M, R, W>
122{
123    fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, TryError<Self::Error>> {
124        let mut r = self.reader.try_lock().map_err(|_| TryError::Busy)?;
125        ControllerToHostPacket::read_hci(&mut *r, rx)
126            .map_err(Error::Read)
127            .map_err(TryError::Error)
128    }
129
130    fn write<T: HostToControllerPacket>(&self, tx: &T) -> Result<(), TryError<Self::Error>> {
131        let mut w = self.writer.try_lock().map_err(|_| TryError::Busy)?;
132        WithIndicator(tx)
133            .write_hci(&mut *w)
134            .map_err(|e| Error::Write(e))
135            .map_err(TryError::Error)
136    }
137}
138
139/// Wrapper for a [`HostToControllerPacket`] that will write the [`PacketKind`](crate::PacketKind) indicator byte before the packet itself
140/// when serialized with [`WriteHci`].
141///
142/// This is used for transports where all packets are sent over a common channel, such as the UART transport.
143pub struct WithIndicator<'a, T: HostToControllerPacket>(&'a T);
144
145impl<'a, T: HostToControllerPacket> WithIndicator<'a, T> {
146    /// Create a new instance.
147    pub fn new(pkt: &'a T) -> Self {
148        Self(pkt)
149    }
150}
151
152impl<T: HostToControllerPacket> WriteHci for WithIndicator<'_, T> {
153    #[inline(always)]
154    fn size(&self) -> usize {
155        1 + self.0.size()
156    }
157
158    #[inline(always)]
159    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
160        T::KIND.write_hci(&mut writer)?;
161        self.0.write_hci(writer)
162    }
163
164    #[inline(always)]
165    async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
166        T::KIND.write_hci_async(&mut writer).await?;
167        self.0.write_hci_async(writer).await
168    }
169}
170
171pub mod blocking {
172    //! Blocking transport trait.
173    use super::*;
174    use crate::controller::blocking::TryError;
175
176    /// A packet-oriented HCI Transport Layer
177    pub trait Transport: embedded_io::ErrorType {
178        /// Read a complete HCI packet into the rx buffer
179        fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, TryError<Self::Error>>;
180        /// Write a complete HCI packet from the tx buffer
181        fn write<T: HostToControllerPacket>(&self, val: &T) -> Result<(), TryError<Self::Error>>;
182    }
183}