blob: ca48df9bb03b350f39313302706ff0d5844ff7ae [file] [log] [blame]
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::convert::{TryFrom, TryInto};
use std::future::Future;
use std::pin::Pin;
use std::rc::{Rc, Weak};
use std::task::{Context, Poll};
use thiserror::Error;
use crate::ffi::LinkManagerOps;
use crate::future::noop_waker;
use crate::packets::{hci, lmp};
use crate::procedure;
use hci::Packet as _;
use lmp::Packet as _;
/// Number of hci command packets used
/// in Command Complete and Command Status
#[allow(non_upper_case_globals)]
pub const num_hci_command_packets: u8 = 1;
struct Link {
peer: Cell<hci::Address>,
// Only store one HCI packet as our Num_HCI_Command_Packets
// is always 1
hci: Cell<Option<hci::CommandPacket>>,
lmp: RefCell<VecDeque<lmp::PacketPacket>>,
}
impl Default for Link {
fn default() -> Self {
Link {
peer: Cell::new(hci::EMPTY_ADDRESS),
hci: Default::default(),
lmp: Default::default(),
}
}
}
impl Link {
fn ingest_lmp(&self, packet: lmp::PacketPacket) {
self.lmp.borrow_mut().push_back(packet);
}
fn ingest_hci(&self, command: hci::CommandPacket) {
assert!(self.hci.replace(Some(command)).is_none(), "HCI flow control violation");
}
fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
let command = self.hci.take();
if let Some(command) = command.clone().and_then(|c| c.try_into().ok()) {
Poll::Ready(command)
} else {
self.hci.set(command);
Poll::Pending
}
}
fn poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P> {
let mut queue = self.lmp.borrow_mut();
let packet = queue.front().and_then(|packet| packet.clone().try_into().ok());
if let Some(packet) = packet {
queue.pop_front();
Poll::Ready(packet)
} else {
Poll::Pending
}
}
fn reset(&self) {
self.peer.set(hci::EMPTY_ADDRESS);
self.hci.set(None);
self.lmp.borrow_mut().clear();
}
}
#[derive(Error, Debug)]
pub enum LinkManagerError {
#[error("Unknown peer")]
UnknownPeer,
#[error("Unhandled HCI packet")]
UnhandledHciPacket,
#[error("Maximum number of links reached")]
MaxNumberOfLink,
}
/// Max number of Bluetooth Peers
pub const MAX_PEER_NUMBER: usize = 7;
pub struct LinkManager {
ops: LinkManagerOps,
links: [Link; MAX_PEER_NUMBER],
procedures: RefCell<[Option<Pin<Box<dyn Future<Output = ()>>>>; MAX_PEER_NUMBER]>,
}
impl LinkManager {
pub fn new(ops: LinkManagerOps) -> Self {
Self { ops, links: Default::default(), procedures: Default::default() }
}
fn get_link(&self, peer: hci::Address) -> Option<&Link> {
self.links.iter().find(|link| link.peer.get() == peer)
}
pub fn ingest_lmp(
&self,
from: hci::Address,
packet: lmp::PacketPacket,
) -> Result<(), LinkManagerError> {
if let Some(link) = self.get_link(from) {
link.ingest_lmp(packet);
};
Ok(())
}
pub fn ingest_hci(&self, command: hci::CommandPacket) -> Result<(), LinkManagerError> {
// Try to find the peer address from the command arguments
let peer = hci::command_connection_handle(&command)
.map(|handle| self.ops.get_address(handle))
.or_else(|| hci::command_remote_device_address(&command));
if let Some(peer) = peer {
if let Some(link) = self.get_link(peer) {
link.ingest_hci(command);
};
Ok(())
} else {
Err(LinkManagerError::UnhandledHciPacket)
}
}
pub fn add_link(self: &Rc<Self>, peer: hci::Address) -> Result<(), LinkManagerError> {
let index = self.links.iter().position(|link| link.peer.get().is_empty());
if let Some(index) = index {
self.links[index].peer.set(peer);
let context = LinkContext { index: index as u8, manager: Rc::downgrade(self) };
self.procedures.borrow_mut()[index] = Some(Box::pin(procedure::run(context)));
Ok(())
} else {
Err(LinkManagerError::UnhandledHciPacket)
}
}
pub fn remove_link(&self, peer: hci::Address) -> Result<(), LinkManagerError> {
let index = self.links.iter().position(|link| link.peer.get() == peer);
if let Some(index) = index {
self.links[index].reset();
self.procedures.borrow_mut()[index] = None;
Ok(())
} else {
Err(LinkManagerError::UnknownPeer)
}
}
pub fn tick(&self) {
let waker = noop_waker();
for procedures in self.procedures.borrow_mut().iter_mut().filter_map(Option::as_mut) {
let _ = procedures.as_mut().poll(&mut Context::from_waker(&waker));
}
}
fn link(&self, idx: u8) -> &Link {
&self.links[idx as usize]
}
}
struct LinkContext {
index: u8,
manager: Weak<LinkManager>,
}
impl procedure::Context for LinkContext {
fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
if let Some(manager) = self.manager.upgrade() {
manager.link(self.index).poll_hci_command()
} else {
Poll::Pending
}
}
fn poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P> {
if let Some(manager) = self.manager.upgrade() {
manager.link(self.index).poll_lmp_packet()
} else {
Poll::Pending
}
}
fn send_hci_event<E: Into<hci::EventPacket>>(&self, event: E) {
if let Some(manager) = self.manager.upgrade() {
manager.ops.send_hci_event(&event.into().to_vec())
}
}
fn send_lmp_packet<P: Into<lmp::PacketPacket>>(&self, packet: P) {
if let Some(manager) = self.manager.upgrade() {
manager.ops.send_lmp_packet(self.peer_address(), &packet.into().to_vec())
}
}
fn peer_address(&self) -> hci::Address {
if let Some(manager) = self.manager.upgrade() {
manager.link(self.index).peer.get()
} else {
hci::EMPTY_ADDRESS
}
}
fn peer_handle(&self) -> u16 {
if let Some(manager) = self.manager.upgrade() {
manager.ops.get_handle(self.peer_address())
} else {
0
}
}
fn extended_features(&self, features_page: u8) -> u64 {
if let Some(manager) = self.manager.upgrade() {
manager.ops.extended_features(features_page)
} else {
0
}
}
}