use crate::l2cap::{L2CAPState, L2CAPStateTx};
use crate::link::data::{Llid, Pdu};
use crate::link::llcp::ControlPdu;
use crate::link::queue::{Consume, Consumer, Producer};
use crate::{bytes::ToBytes, config::*, utils::HexSlice, Error};
pub struct Responder<C: Config> {
tx: ConfProducer<C>,
rx: Option<ConfConsumer<C>>,
l2cap: L2CAPState<C::ChannelMapper>,
}
impl<C: Config> Responder<C> {
pub fn new(
tx: ConfProducer<C>,
rx: ConfConsumer<C>,
l2cap: L2CAPState<C::ChannelMapper>,
) -> Self {
Self {
tx,
rx: Some(rx),
l2cap,
}
}
pub fn has_work(&mut self) -> bool {
self.with_rx(|rx, _| rx.has_data())
}
pub fn process_one(&mut self) -> Result<(), Error> {
self.with_rx(|rx, this| {
rx.consume_pdu_with(|_, pdu| match pdu {
Pdu::Control { data } => {
let pdu = data.read();
info!("<- LL Control PDU: {:?}", pdu);
let response = match pdu {
ControlPdu::FeatureReq { .. } | ControlPdu::VersionInd { .. } => {
unreachable!("LLCPDU not handled by LL");
}
_ => ControlPdu::UnknownRsp {
unknown_type: pdu.opcode(),
},
};
info!("-> Response: {:?}", response);
Consume::on_success(this.tx.produce_with(response.encoded_size(), |writer| {
response.to_bytes(writer)?;
Ok(Llid::Control)
}))
}
Pdu::DataStart { message } => {
info!("L2start: {:?}", HexSlice(message));
this.l2cap().process_start(message)
}
Pdu::DataCont { message } => {
info!("L2cont {:?}", HexSlice(message));
this.l2cap().process_cont(message)
}
})
})
}
pub fn l2cap(&mut self) -> L2CAPStateTx<'_, C::ChannelMapper, ConfProducer<C>> {
self.l2cap.tx(&mut self.tx)
}
fn with_rx<R>(&mut self, f: impl FnOnce(&mut ConfConsumer<C>, &mut Self) -> R) -> R {
let mut rx = self.rx.take().unwrap();
let result = f(&mut rx, self);
self.rx = Some(rx);
result
}
}