1 use async_trait::async_trait; 2 use bitflags::bitflags; 3 4 use crate::{ 5 core::uuid::Uuid, 6 gatt::ids::AttHandle, 7 packets::{ 8 AttAttributeDataChild, AttAttributeDataView, AttErrorCode, AttHandleBuilder, AttHandleView, 9 }, 10 }; 11 12 impl From<AttHandleView<'_>> for AttHandle { from(value: AttHandleView) -> Self13 fn from(value: AttHandleView) -> Self { 14 AttHandle(value.get_handle()) 15 } 16 } 17 18 impl From<AttHandle> for AttHandleBuilder { from(value: AttHandle) -> Self19 fn from(value: AttHandle) -> Self { 20 AttHandleBuilder { handle: value.0 } 21 } 22 } 23 24 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 25 pub struct AttAttribute { 26 pub handle: AttHandle, 27 pub type_: Uuid, 28 pub permissions: AttPermissions, 29 } 30 31 bitflags! { 32 /// The attribute properties supported by the current GATT server implementation 33 /// Unimplemented properties will default to false. 34 /// 35 /// These values are from Core Spec 5.3 Vol 3G 3.3.1.1 Characteristic Properties, 36 /// and also match what Android uses in JNI. 37 pub struct AttPermissions : u8 { 38 /// Attribute can be read using READ_REQ 39 const READABLE = 0x02; 40 /// Attribute can be written to using WRITE_CMD 41 const WRITABLE_WITHOUT_RESPONSE = 0x04; 42 /// Attribute can be written to using WRITE_REQ 43 const WRITABLE_WITH_RESPONSE = 0x08; 44 /// Attribute value may be sent using indications 45 const INDICATE = 0x20; 46 } 47 } 48 49 impl AttPermissions { 50 /// Attribute can be read using READ_REQ readable(&self) -> bool51 pub fn readable(&self) -> bool { 52 self.contains(AttPermissions::READABLE) 53 } 54 /// Attribute can be written to using WRITE_REQ writable_with_response(&self) -> bool55 pub fn writable_with_response(&self) -> bool { 56 self.contains(AttPermissions::WRITABLE_WITH_RESPONSE) 57 } 58 /// Attribute can be written to using WRITE_CMD writable_without_response(&self) -> bool59 pub fn writable_without_response(&self) -> bool { 60 self.contains(AttPermissions::WRITABLE_WITHOUT_RESPONSE) 61 } 62 /// Attribute value may be sent using indications indicate(&self) -> bool63 pub fn indicate(&self) -> bool { 64 self.contains(AttPermissions::INDICATE) 65 } 66 } 67 68 #[async_trait(?Send)] 69 pub trait AttDatabase { 70 /// Read an attribute by handle read_attribute( &self, handle: AttHandle, ) -> Result<AttAttributeDataChild, AttErrorCode>71 async fn read_attribute( 72 &self, 73 handle: AttHandle, 74 ) -> Result<AttAttributeDataChild, AttErrorCode>; 75 76 /// Write to an attribute by handle write_attribute( &self, handle: AttHandle, data: AttAttributeDataView<'_>, ) -> Result<(), AttErrorCode>77 async fn write_attribute( 78 &self, 79 handle: AttHandle, 80 data: AttAttributeDataView<'_>, 81 ) -> Result<(), AttErrorCode>; 82 83 /// Write to an attribute by handle write_no_response_attribute(&self, handle: AttHandle, data: AttAttributeDataView<'_>)84 fn write_no_response_attribute(&self, handle: AttHandle, data: AttAttributeDataView<'_>); 85 86 /// List all the attributes in this database. 87 /// 88 /// Expected to return them in sorted order. list_attributes(&self) -> Vec<AttAttribute>89 fn list_attributes(&self) -> Vec<AttAttribute>; 90 91 /// Produce an implementation of StableAttDatabase snapshot(&self) -> SnapshottedAttDatabase<'_> where Self: Sized,92 fn snapshot(&self) -> SnapshottedAttDatabase<'_> 93 where 94 Self: Sized, 95 { 96 SnapshottedAttDatabase { attributes: self.list_attributes(), backing: self } 97 } 98 } 99 100 /// Marker trait indicating that the backing attribute list of this 101 /// database is guaranteed to remain unchanged across async points. 102 /// 103 /// Useful if we want to call list_attributes() multiple times, rather than 104 /// caching its result the first time. 105 pub trait StableAttDatabase: AttDatabase { find_attribute(&self, handle: AttHandle) -> Option<AttAttribute>106 fn find_attribute(&self, handle: AttHandle) -> Option<AttAttribute> { 107 self.list_attributes().into_iter().find(|attr| attr.handle == handle) 108 } 109 } 110 111 /// A snapshot of an AttDatabase implementing StableAttDatabase. 112 pub struct SnapshottedAttDatabase<'a> { 113 attributes: Vec<AttAttribute>, 114 backing: &'a (dyn AttDatabase), 115 } 116 117 #[async_trait(?Send)] 118 impl AttDatabase for SnapshottedAttDatabase<'_> { read_attribute( &self, handle: AttHandle, ) -> Result<AttAttributeDataChild, AttErrorCode>119 async fn read_attribute( 120 &self, 121 handle: AttHandle, 122 ) -> Result<AttAttributeDataChild, AttErrorCode> { 123 self.backing.read_attribute(handle).await 124 } 125 write_attribute( &self, handle: AttHandle, data: AttAttributeDataView<'_>, ) -> Result<(), AttErrorCode>126 async fn write_attribute( 127 &self, 128 handle: AttHandle, 129 data: AttAttributeDataView<'_>, 130 ) -> Result<(), AttErrorCode> { 131 self.backing.write_attribute(handle, data).await 132 } 133 write_no_response_attribute(&self, handle: AttHandle, data: AttAttributeDataView<'_>)134 fn write_no_response_attribute(&self, handle: AttHandle, data: AttAttributeDataView<'_>) { 135 self.backing.write_no_response_attribute(handle, data); 136 } 137 list_attributes(&self) -> Vec<AttAttribute>138 fn list_attributes(&self) -> Vec<AttAttribute> { 139 self.attributes.clone() 140 } 141 } 142 143 impl StableAttDatabase for SnapshottedAttDatabase<'_> {} 144