use enumset::{EnumSet, EnumSetType};
use num_enum::TryFromPrimitive;
use crate::bt::BtUuid;
use crate::sys::*;
pub mod client;
pub mod server;
pub type GattInterface = u8;
pub type Handle = u16;
#[derive(Debug, Copy, Clone, Eq, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum GattStatus {
Ok = esp_gatt_status_t_ESP_GATT_OK,
InvalidHandle = esp_gatt_status_t_ESP_GATT_INVALID_HANDLE,
ReadNotPermitted = esp_gatt_status_t_ESP_GATT_READ_NOT_PERMIT,
WriteNotPermitted = esp_gatt_status_t_ESP_GATT_WRITE_NOT_PERMIT,
InvalidPdu = esp_gatt_status_t_ESP_GATT_INVALID_PDU,
InsufficientAuthentication = esp_gatt_status_t_ESP_GATT_INSUF_AUTHENTICATION,
ReqNotSupported = esp_gatt_status_t_ESP_GATT_REQ_NOT_SUPPORTED,
InvalidOffset = esp_gatt_status_t_ESP_GATT_INVALID_OFFSET,
InsufficientAuthorization = esp_gatt_status_t_ESP_GATT_INSUF_AUTHORIZATION,
PrepareQueueFull = esp_gatt_status_t_ESP_GATT_PREPARE_Q_FULL,
NotFound = esp_gatt_status_t_ESP_GATT_NOT_FOUND,
NotLong = esp_gatt_status_t_ESP_GATT_NOT_LONG,
InsufficientKeySize = esp_gatt_status_t_ESP_GATT_INSUF_KEY_SIZE,
InvalidAttrLen = esp_gatt_status_t_ESP_GATT_INVALID_ATTR_LEN,
ErrUnlikely = esp_gatt_status_t_ESP_GATT_ERR_UNLIKELY,
InsufficientEncryption = esp_gatt_status_t_ESP_GATT_INSUF_ENCRYPTION,
UsupportedGroupType = esp_gatt_status_t_ESP_GATT_UNSUPPORT_GRP_TYPE,
InsufficientResource = esp_gatt_status_t_ESP_GATT_INSUF_RESOURCE,
NoResources = esp_gatt_status_t_ESP_GATT_NO_RESOURCES,
InternalError = esp_gatt_status_t_ESP_GATT_INTERNAL_ERROR,
WrongState = esp_gatt_status_t_ESP_GATT_WRONG_STATE,
DbFull = esp_gatt_status_t_ESP_GATT_DB_FULL,
Busy = esp_gatt_status_t_ESP_GATT_BUSY,
Error = esp_gatt_status_t_ESP_GATT_ERROR,
CmdStarted = esp_gatt_status_t_ESP_GATT_CMD_STARTED,
IllegalParam = esp_gatt_status_t_ESP_GATT_ILLEGAL_PARAMETER,
Pending = esp_gatt_status_t_ESP_GATT_PENDING,
AuthenticationFailed = esp_gatt_status_t_ESP_GATT_AUTH_FAIL,
More = esp_gatt_status_t_ESP_GATT_MORE,
InvalidCfg = esp_gatt_status_t_ESP_GATT_INVALID_CFG,
ServiceStarted = esp_gatt_status_t_ESP_GATT_SERVICE_STARTED,
#[cfg(all(esp_idf_version_major = "4", not(esp_idf_version_full = "4.4.8")))]
EncryptedNoMitm = esp_gatt_status_t_ESP_GATT_ENCRYPED_NO_MITM,
#[cfg(any(not(esp_idf_version_major = "4"), esp_idf_version_full = "4.4.8"))]
EncryptedNoMitm = esp_gatt_status_t_ESP_GATT_ENCRYPTED_NO_MITM,
NotEncrypted = esp_gatt_status_t_ESP_GATT_NOT_ENCRYPTED,
Congested = esp_gatt_status_t_ESP_GATT_CONGESTED,
DuplicateReg = esp_gatt_status_t_ESP_GATT_DUP_REG,
AlreadyOpen = esp_gatt_status_t_ESP_GATT_ALREADY_OPEN,
Cancel = esp_gatt_status_t_ESP_GATT_CANCEL,
StackRsp = esp_gatt_status_t_ESP_GATT_STACK_RSP,
AppRsp = esp_gatt_status_t_ESP_GATT_APP_RSP,
UnknownErr = esp_gatt_status_t_ESP_GATT_UNKNOWN_ERROR,
CccCfgErr = esp_gatt_status_t_ESP_GATT_CCC_CFG_ERR,
PrcInProgress = esp_gatt_status_t_ESP_GATT_PRC_IN_PROGRESS,
OutOfRange = esp_gatt_status_t_ESP_GATT_OUT_OF_RANGE,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum GattConnReason {
Unknown = esp_gatt_conn_reason_t_ESP_GATT_CONN_UNKNOWN,
L2cFailure = esp_gatt_conn_reason_t_ESP_GATT_CONN_L2C_FAILURE,
Timeout = esp_gatt_conn_reason_t_ESP_GATT_CONN_TIMEOUT,
TerminatedByPeer = esp_gatt_conn_reason_t_ESP_GATT_CONN_TERMINATE_PEER_USER,
TerminatedByLocalHost = esp_gatt_conn_reason_t_ESP_GATT_CONN_TERMINATE_LOCAL_HOST,
FailedToEstablish = esp_gatt_conn_reason_t_ESP_GATT_CONN_FAIL_ESTABLISH,
LmpTimeout = esp_gatt_conn_reason_t_ESP_GATT_CONN_LMP_TIMEOUT,
L2capConnCancelled = esp_gatt_conn_reason_t_ESP_GATT_CONN_CONN_CANCEL,
NoConnection = esp_gatt_conn_reason_t_ESP_GATT_CONN_NONE,
}
#[derive(Clone, Debug)]
pub struct GattConnParams {
pub interval_ms: u32,
pub latency_ms: u32,
pub timeout_ms: u32,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GattId {
pub uuid: BtUuid,
pub inst_id: u8,
}
impl From<esp_gatt_id_t> for GattId {
fn from(id: esp_gatt_id_t) -> Self {
Self {
uuid: BtUuid::from(id.uuid),
inst_id: id.inst_id,
}
}
}
impl From<GattId> for esp_gatt_id_t {
fn from(id: GattId) -> Self {
Self {
uuid: id.uuid.into(),
inst_id: id.inst_id,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GattServiceId {
pub id: GattId,
pub is_primary: bool,
}
impl From<esp_gatt_srvc_id_t> for GattServiceId {
fn from(id: esp_gatt_srvc_id_t) -> Self {
Self {
id: GattId::from(id.id),
is_primary: id.is_primary,
}
}
}
impl From<GattServiceId> for esp_gatt_srvc_id_t {
fn from(id: GattServiceId) -> Self {
Self {
id: id.id.into(),
is_primary: id.is_primary,
}
}
}
#[repr(u16)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ServiceUuid {
GenericAccess = 0x1800,
GenericAttribute,
ImmediateAlert,
LinkLoss,
TxPower,
CurrentTime,
ReferenceTimeUpdate,
NextDSTChange = 0x1807,
Glucose,
HealthThermometer,
DeviceInformation,
HeartRate = 0x180D,
PhoneAlertStatus,
Battery,
BloodPressure,
AlertNotification,
HumanInterfaceDevice,
ScanParameters,
RunningSpeedAndCadence,
AutomationIO,
CyclingSpeedAndCadence,
CyclingPower = 0x1818,
LocationAndNavigation,
EnvironmentalSensing,
BodyComposition,
UserData,
WeightScale,
BondManagement,
ContinuousGlucoseMonitoring,
InternetProtocolSupport,
IndoorPositioning,
PulseOximeter,
HTTPProxy,
TransportDiscovery,
ObjectTransfer,
FitnessMachine,
MeshProvisioning,
MeshProxy,
ReconnectionConfiguration,
InsulinDelivery = 0x183A,
BinarySensor,
EmergencyConfiguration,
PhysicalActivityMonitor = 0x183E,
AudioInputControl = 0x1843,
VolumeControl,
VolumeOffsetControl,
CoordinatedSetIdentification,
DeviceTime,
MediaControl,
GenericMediaControl,
ConstantToneExtension,
TelephoneBearer,
GenericTelephoneBearer,
MicrophoneControl,
AudioStreamControl,
BroadcastAudioScan,
PublishedAudioCapabilities,
BasicAudioAnnouncement,
BroadcastAudioAnnouncement,
CommonAudio,
HearingAccess,
TMAS,
PublicBroadcastAnnouncement,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum AutoResponse {
ByApp = ESP_GATT_RSP_BY_APP as _,
ByGatt = ESP_GATT_AUTO_RSP as _,
}
#[derive(Debug, EnumSetType, TryFromPrimitive)]
#[enumset(repr = "u16")]
#[repr(u16)]
pub enum Permission {
Read = 0, ReadEncrypted = 1, ReadEncryptedMitm = 2, Unknown = 3,
Write = 4, WriteEncrypted = 5, WriteEncryptedMitm = 6, WriteSigned = 7, WriteSiognedMitm = 8, ReadAuthorization = 9, WriteAuthorization = 10, }
#[derive(Debug, EnumSetType, TryFromPrimitive)]
#[enumset(repr = "u8")]
#[repr(u8)]
pub enum Property {
Broadcast = 0, Read = 1, WriteNoResponse = 2, Write = 3, Notify = 4, Indicate = 5, Auth = 6, ExtendedProps = 7, }
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct GattCharacteristic {
pub uuid: BtUuid,
pub permissions: EnumSet<Permission>,
pub properties: EnumSet<Property>,
pub max_len: usize,
pub auto_rsp: AutoResponse,
}
impl GattCharacteristic {
pub const fn new(
uuid: BtUuid,
permissions: EnumSet<Permission>,
properties: EnumSet<Property>,
max_len: usize,
auto_rsp: AutoResponse,
) -> Self {
Self {
uuid,
permissions,
properties,
max_len,
auto_rsp,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct GattDescriptor {
pub uuid: BtUuid,
pub permissions: EnumSet<Permission>,
}
impl GattDescriptor {
pub const fn new(uuid: BtUuid, permissions: EnumSet<Permission>) -> Self {
Self { uuid, permissions }
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct GattResponse(esp_gatt_rsp_t);
impl GattResponse {
#[inline(always)]
pub const fn new() -> Self {
Self(esp_gatt_rsp_t {
attr_value: esp_gatt_value_t {
len: 0,
value: [0; ESP_GATT_MAX_ATTR_LEN as _],
handle: 0,
offset: 0,
auth_req: 0,
},
})
}
pub fn attr_handle(&mut self, handle: Handle) -> &mut Self {
self.0.attr_value.handle = handle;
self
}
pub fn auth_req(&mut self, auth_req: u8) -> &mut Self {
self.0.attr_value.auth_req = auth_req;
self
}
pub fn offset(&mut self, offset: u16) -> &mut Self {
self.0.attr_value.offset = offset;
self
}
pub fn value(&mut self, value: &[u8]) -> Result<&mut Self, EspError> {
if value.len() > 600 {
return Err(EspError::from_infallible::<{ ESP_ERR_INVALID_ARG }>());
}
self.0.attr_value.len = value.len() as u16;
unsafe { self.0.attr_value.value[..value.len()].copy_from_slice(value) };
Ok(self)
}
}
impl Default for GattResponse {
fn default() -> Self {
Self::new()
}
}
pub fn set_local_mtu(mtu: u16) -> Result<(), EspError> {
esp!(unsafe { esp_ble_gatt_set_local_mtu(mtu) })
}