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