use bt_hci::{FixedSizeValue, WriteHci};
pub(crate) const L2CAP_CID_ATT: u16 = 0x0004;
pub(crate) const L2CAP_CID_LE_U_SIGNAL: u16 = 0x0005;
pub(crate) const L2CAP_CID_LE_U_SECURITY_MANAGER: u16 = 0x0006;
pub(crate) const L2CAP_CID_DYN_START: u16 = 0x0040;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct L2capHeader {
pub length: u16,
pub channel: u16,
}
unsafe impl FixedSizeValue for L2capHeader {
fn is_valid(data: &[u8]) -> bool {
true
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct L2capSignalHeader {
pub code: L2capSignalCode,
pub identifier: u8,
pub length: u16,
}
unsafe impl FixedSizeValue for L2capSignalHeader {
fn is_valid(data: &[u8]) -> bool {
true
}
}
#[cfg(not(feature = "defmt"))]
pub trait L2capSignal: WriteHci + FixedSizeValue + core::fmt::Debug {
fn channel() -> u16 {
L2CAP_CID_LE_U_SIGNAL
}
fn code() -> L2capSignalCode;
}
#[cfg(feature = "defmt")]
pub trait L2capSignal: WriteHci + FixedSizeValue + defmt::Format {
fn channel() -> u16 {
L2CAP_CID_LE_U_SIGNAL
}
fn code() -> L2capSignalCode;
}
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct L2capSignalCode(pub u8);
unsafe impl FixedSizeValue for L2capSignalCode {
fn is_valid(_data: &[u8]) -> bool {
true
}
}
impl core::fmt::Debug for L2capSignalCode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
Self::COMMAND_REJECT_RES => write!(f, "CommandRejectRes"),
Self::CONNECTION_REQ => write!(f, "ConnectionReq"),
Self::CONNECTION_RES => write!(f, "ConnectionRes"),
Self::CONFIGURATION_REQ => write!(f, "ConfigurationReq"),
Self::CONFIGURATION_RES => write!(f, "ConfigurationRes"),
Self::DISCONNECTION_REQ => write!(f, "DisconnectionReq"),
Self::DISCONNECTION_RES => write!(f, "DisconnectionRes"),
Self::ECHO_REQ => write!(f, "EchoReq"),
Self::ECHO_RES => write!(f, "EchoRes"),
Self::INFORMATION_REQ => write!(f, "InformationReq"),
Self::INFORMATION_RES => write!(f, "InformationRes"),
Self::CONN_PARAM_UPDATE_REQ => write!(f, "ConnParamUpdateReq"),
Self::CONN_PARAM_UPDATE_RES => write!(f, "ConnParamUpdateRes"),
Self::LE_CREDIT_CONN_REQ => write!(f, "LeCreditConnReq"),
Self::LE_CREDIT_CONN_RES => write!(f, "LeCreditConnRes"),
Self::LE_CREDIT_FLOW_IND => write!(f, "LeCreditFlowInd"),
Self::CREDIT_CONN_REQ => write!(f, "CreditConnReq"),
Self::CREDIT_CONN_RES => write!(f, "CreditConnRes"),
Self::CREDIT_CONN_RECONFIG_REQ => write!(f, "CreditConnReconfigReq"),
Self::CREDIT_CONN_RECONFIG_RES => write!(f, "CreditConnReconfigRes"),
_ => write!(f, "Unknown(0x{:02x})", self.0),
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for L2capSignalCode {
fn format(&self, f: defmt::Formatter<'_>) {
match *self {
Self::COMMAND_REJECT_RES => defmt::write!(f, "CommandRejectRes"),
Self::CONNECTION_REQ => defmt::write!(f, "ConnectionReq"),
Self::CONNECTION_RES => defmt::write!(f, "ConnectionRes"),
Self::CONFIGURATION_REQ => defmt::write!(f, "ConfigurationReq"),
Self::CONFIGURATION_RES => defmt::write!(f, "ConfigurationRes"),
Self::DISCONNECTION_REQ => defmt::write!(f, "DisconnectionReq"),
Self::DISCONNECTION_RES => defmt::write!(f, "DisconnectionRes"),
Self::ECHO_REQ => defmt::write!(f, "EchoReq"),
Self::ECHO_RES => defmt::write!(f, "EchoRes"),
Self::INFORMATION_REQ => defmt::write!(f, "InformationReq"),
Self::INFORMATION_RES => defmt::write!(f, "InformationRes"),
Self::CONN_PARAM_UPDATE_REQ => defmt::write!(f, "ConnParamUpdateReq"),
Self::CONN_PARAM_UPDATE_RES => defmt::write!(f, "ConnParamUpdateRes"),
Self::LE_CREDIT_CONN_REQ => defmt::write!(f, "LeCreditConnReq"),
Self::LE_CREDIT_CONN_RES => defmt::write!(f, "LeCreditConnRes"),
Self::LE_CREDIT_FLOW_IND => defmt::write!(f, "LeCreditFlowInd"),
Self::CREDIT_CONN_REQ => defmt::write!(f, "CreditConnReq"),
Self::CREDIT_CONN_RES => defmt::write!(f, "CreditConnRes"),
Self::CREDIT_CONN_RECONFIG_REQ => defmt::write!(f, "CreditConnReconfigReq"),
Self::CREDIT_CONN_RECONFIG_RES => defmt::write!(f, "CreditConnReconfigRes"),
_ => defmt::write!(f, "Unknown(0x{:02x})", self.0),
}
}
}
impl From<u8> for L2capSignalCode {
fn from(val: u8) -> Self {
Self(val)
}
}
#[allow(non_upper_case_globals)]
impl L2capSignalCode {
pub const COMMAND_REJECT_RES: Self = Self(0x01);
pub const CONNECTION_REQ: Self = Self(0x02);
pub const CONNECTION_RES: Self = Self(0x03);
pub const CONFIGURATION_REQ: Self = Self(0x04);
pub const CONFIGURATION_RES: Self = Self(0x05);
pub const DISCONNECTION_REQ: Self = Self(0x06);
pub const DISCONNECTION_RES: Self = Self(0x07);
pub const ECHO_REQ: Self = Self(0x08);
pub const ECHO_RES: Self = Self(0x09);
pub const INFORMATION_REQ: Self = Self(0x0A);
pub const INFORMATION_RES: Self = Self(0x0B);
pub const CONN_PARAM_UPDATE_REQ: Self = Self(0x12);
pub const CONN_PARAM_UPDATE_RES: Self = Self(0x13);
pub const LE_CREDIT_CONN_REQ: Self = Self(0x14);
pub const LE_CREDIT_CONN_RES: Self = Self(0x15);
pub const LE_CREDIT_FLOW_IND: Self = Self(0x16);
pub const CREDIT_CONN_REQ: Self = Self(0x17);
pub const CREDIT_CONN_RES: Self = Self(0x18);
pub const CREDIT_CONN_RECONFIG_REQ: Self = Self(0x19);
pub const CREDIT_CONN_RECONFIG_RES: Self = Self(0x1A);
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct LeCreditConnReq {
pub spsm: u16,
pub scid: u16,
pub mtu: u16,
pub mps: u16,
pub credits: u16,
}
unsafe impl FixedSizeValue for LeCreditConnReq {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for LeCreditConnReq {
fn code() -> L2capSignalCode {
L2capSignalCode::LE_CREDIT_CONN_REQ
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum LeCreditConnResultCode {
Success = 0x0000,
SpsmNotSupported = 0x0002,
NoResources = 0x0004,
InsufficientAuthentication = 0x0005,
InsufficientAuthorization = 0x0006,
EncryptionKeyTooShort = 0x0007,
InsufficientEncryption = 0x0008,
InvalidSourceId = 0x0009,
ScidAlreadyAllocated = 0x000A,
UnacceptableParameters = 0x000B,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct LeCreditConnRes {
pub dcid: u16,
pub mtu: u16,
pub mps: u16,
pub credits: u16,
pub result: LeCreditConnResultCode,
}
impl LeCreditConnRes {
pub const fn reject(result: LeCreditConnResultCode) -> Self {
Self {
dcid: 0,
mtu: 0,
mps: 0,
credits: 0,
result,
}
}
}
impl L2capSignal for LeCreditConnRes {
fn code() -> L2capSignalCode {
L2capSignalCode::LE_CREDIT_CONN_RES
}
}
unsafe impl FixedSizeValue for LeCreditConnRes {
fn is_valid(data: &[u8]) -> bool {
true
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct LeCreditFlowInd {
pub cid: u16,
pub credits: u16,
}
unsafe impl FixedSizeValue for LeCreditFlowInd {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for LeCreditFlowInd {
fn code() -> L2capSignalCode {
L2capSignalCode::LE_CREDIT_FLOW_IND
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct CommandRejectRes {
pub reason: u16,
}
unsafe impl FixedSizeValue for CommandRejectRes {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for CommandRejectRes {
fn code() -> L2capSignalCode {
L2capSignalCode::COMMAND_REJECT_RES
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct DisconnectionReq {
pub dcid: u16,
pub scid: u16,
}
unsafe impl FixedSizeValue for DisconnectionReq {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for DisconnectionReq {
fn code() -> L2capSignalCode {
L2capSignalCode::DISCONNECTION_REQ
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct DisconnectionRes {
pub dcid: u16,
pub scid: u16,
}
unsafe impl FixedSizeValue for DisconnectionRes {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for DisconnectionRes {
fn code() -> L2capSignalCode {
L2capSignalCode::DISCONNECTION_RES
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ConnParamUpdateReq {
pub interval_min: u16,
pub interval_max: u16,
pub latency: u16,
pub timeout: u16,
}
unsafe impl FixedSizeValue for ConnParamUpdateReq {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for ConnParamUpdateReq {
fn code() -> L2capSignalCode {
L2capSignalCode::CONN_PARAM_UPDATE_REQ
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ConnParamUpdateRes {
pub result: u16,
}
unsafe impl FixedSizeValue for ConnParamUpdateRes {
fn is_valid(data: &[u8]) -> bool {
true
}
}
impl L2capSignal for ConnParamUpdateRes {
fn code() -> L2capSignalCode {
L2capSignalCode::CONN_PARAM_UPDATE_RES
}
}