1use core::cell::RefCell;
3use core::future::Future;
4use core::marker::PhantomData;
5
6use bt_hci::controller::Controller;
7use bt_hci::param::{ConnHandle, PhyKind, Status};
8use bt_hci::uuid::declarations::{CHARACTERISTIC, PRIMARY_SERVICE};
9use bt_hci::uuid::descriptors::CLIENT_CHARACTERISTIC_CONFIGURATION;
10use embassy_futures::select::{select, Either};
11use embassy_sync::blocking_mutex::raw::{NoopRawMutex, RawMutex};
12use embassy_sync::channel::{Channel, DynamicReceiver};
13use embassy_sync::pubsub::{self, PubSubChannel, WaitResult};
14use embassy_time::Duration;
15use heapless::Vec;
16
17use crate::att::{self, Att, AttClient, AttCmd, AttErrorCode, AttReq, AttRsp, AttServer, AttUns, ATT_HANDLE_VALUE_NTF};
18use crate::attribute::{AttributeData, Characteristic, CharacteristicProp, Uuid, CCCD};
19use crate::attribute_server::{AttributeServer, DynamicAttributeServer};
20use crate::connection::Connection;
21use crate::cursor::{ReadCursor, WriteCursor};
22use crate::pdu::Pdu;
23use crate::prelude::ConnectionEvent;
24#[cfg(feature = "security")]
25use crate::security_manager::BondInformation;
26use crate::types::gatt_traits::{AsGatt, FromGatt, FromGattError};
27use crate::types::l2cap::L2capHeader;
28use crate::{config, BleHostError, Error, PacketPool, Stack};
29
30pub enum GattConnectionEvent<'stack, 'server, P: PacketPool> {
32 Disconnected {
34 reason: Status,
36 },
37 PhyUpdated {
39 tx_phy: PhyKind,
41 rx_phy: PhyKind,
43 },
44 ConnectionParamsUpdated {
46 conn_interval: Duration,
48 peripheral_latency: u16,
50 supervision_timeout: Duration,
52 },
53 #[cfg(feature = "security")]
54 Bonded {
56 bond_info: BondInformation,
58 },
59 Gatt {
61 event: GattEvent<'stack, 'server, P>,
63 },
64}
65
66pub struct GattConnection<'stack, 'server, P: PacketPool> {
68 connection: Connection<'stack, P>,
69 pub(crate) server: &'server dyn DynamicAttributeServer<P>,
70}
71
72impl<P: PacketPool> Drop for GattConnection<'_, '_, P> {
73 fn drop(&mut self) {
74 trace!("[gatt {}] disconnecting from server", self.connection.handle().raw());
75 self.server.disconnect(&self.connection);
76 }
77}
78
79impl<'stack, 'server, P: PacketPool> GattConnection<'stack, 'server, P> {
80 pub(crate) fn try_new<'values, M: RawMutex, const AT: usize, const CT: usize, const CN: usize>(
83 connection: Connection<'stack, P>,
84 server: &'server AttributeServer<'values, M, P, AT, CT, CN>,
85 ) -> Result<Self, Error> {
86 trace!("[gatt {}] connecting to server", connection.handle().raw());
87 server.connect(&connection)?;
88 Ok(Self { connection, server })
89 }
90
91 pub async fn next(&self) -> GattConnectionEvent<'stack, 'server, P> {
95 match select(self.connection.next(), self.connection.next_gatt()).await {
96 Either::First(event) => match event {
97 ConnectionEvent::Disconnected { reason } => GattConnectionEvent::Disconnected { reason },
98 ConnectionEvent::ConnectionParamsUpdated {
99 conn_interval,
100 peripheral_latency,
101 supervision_timeout,
102 } => GattConnectionEvent::ConnectionParamsUpdated {
103 conn_interval,
104 peripheral_latency,
105 supervision_timeout,
106 },
107 ConnectionEvent::PhyUpdated { tx_phy, rx_phy } => GattConnectionEvent::PhyUpdated { tx_phy, rx_phy },
108 #[cfg(feature = "security")]
109 ConnectionEvent::Bonded { bond_info } => {
110 if let Err(e) = self.server.update_identity(bond_info.identity) {
112 error!("Failed to update identity in att server: {:?}", e);
113 }
114 GattConnectionEvent::Bonded { bond_info }
115 }
116 },
117 Either::Second(data) => GattConnectionEvent::Gatt {
118 event: GattEvent::new(GattData::new(data, self.connection.clone()), self.server),
119 },
120 }
121 }
122
123 pub fn raw(&self) -> &Connection<'stack, P> {
125 &self.connection
126 }
127}
128
129pub struct GattData<'stack, P: PacketPool> {
131 pdu: Option<Pdu<P::Packet>>,
132 connection: Connection<'stack, P>,
133}
134
135impl<'stack, P: PacketPool> GattData<'stack, P> {
136 pub(crate) const fn new(pdu: Pdu<P::Packet>, connection: Connection<'stack, P>) -> Self {
137 Self {
138 pdu: Some(pdu),
139 connection,
140 }
141 }
142
143 pub fn handle(&self) -> Option<u16> {
147 match self.incoming() {
148 AttClient::Request(AttReq::Write { handle, .. }) => Some(handle),
149 AttClient::Command(AttCmd::Write { handle, .. }) => Some(handle),
150 AttClient::Request(AttReq::Read { handle }) => Some(handle),
151 AttClient::Request(AttReq::ReadBlob { handle, .. }) => Some(handle),
152 _ => None,
153 }
154 }
155
156 pub fn incoming(&self) -> AttClient<'_> {
158 let att = unwrap!(Att::decode(self.pdu.as_ref().unwrap().as_ref()));
162 let Att::Client(client) = att else {
163 unreachable!("Expected Att::Client, got {:?}", att)
164 };
165
166 client
167 }
168
169 pub async fn reply(self, rsp: AttRsp<'_>) -> Result<(), Error> {
171 let pdu = send(&self.connection, AttServer::Response(rsp))?;
172 self.connection.send(pdu).await;
173 Ok(())
174 }
175
176 pub async fn send_unsolicited(connection: &Connection<'_, P>, uns: AttUns<'_>) -> Result<(), Error> {
178 let pdu = send(connection, AttServer::Unsolicited(uns))?;
179 connection.send(pdu).await;
180 Ok(())
181 }
182}
183
184pub enum GattEvent<'stack, 'server, P: PacketPool> {
186 Read(ReadEvent<'stack, 'server, P>),
188 Write(WriteEvent<'stack, 'server, P>),
190 Other(OtherEvent<'stack, 'server, P>),
192}
193
194impl<'stack, 'server, P: PacketPool> GattEvent<'stack, 'server, P> {
195 pub fn new(data: GattData<'stack, P>, server: &'server dyn DynamicAttributeServer<P>) -> Self {
197 let att = data.incoming();
198 match att {
199 AttClient::Request(AttReq::Write { .. }) | AttClient::Command(AttCmd::Write { .. }) => {
200 GattEvent::Write(WriteEvent { data, server })
201 }
202 AttClient::Request(AttReq::Read { .. }) | AttClient::Request(AttReq::ReadBlob { .. }) => {
203 GattEvent::Read(ReadEvent { data, server })
204 }
205 _ => GattEvent::Other(OtherEvent { data, server }),
206 }
207 }
208
209 pub fn accept(self) -> Result<Reply<'stack, P>, Error> {
211 match self {
212 Self::Read(e) => e.accept(),
213 Self::Write(e) => e.accept(),
214 Self::Other(e) => e.accept(),
215 }
216 }
217
218 pub fn reject(self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
220 match self {
221 Self::Read(e) => e.reject(err),
222 Self::Write(e) => e.reject(err),
223 Self::Other(e) => e.reject(err),
224 }
225 }
226
227 pub fn payload(&self) -> &GattData<'stack, P> {
229 match self {
230 Self::Read(e) => e.payload(),
231 Self::Write(e) => e.payload(),
232 Self::Other(e) => e.payload(),
233 }
234 }
235
236 pub fn into_payload(self) -> GattData<'stack, P> {
243 match self {
244 Self::Read(e) => e.into_payload(),
245 Self::Write(e) => e.into_payload(),
246 Self::Other(e) => e.into_payload(),
247 }
248 }
249}
250
251pub struct ReadEvent<'stack, 'server, P: PacketPool> {
253 data: GattData<'stack, P>,
254 server: &'server dyn DynamicAttributeServer<P>,
255}
256
257impl<'stack, P: PacketPool> ReadEvent<'stack, '_, P> {
258 pub fn handle(&self) -> u16 {
260 unwrap!(self.data.handle())
263 }
264
265 pub fn accept(mut self) -> Result<Reply<'stack, P>, Error> {
269 process(&mut self.data, self.server, Ok(()))
270 }
271
272 pub fn reject(mut self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
274 process(&mut self.data, self.server, Err(err))
275 }
276
277 pub fn payload(&self) -> &GattData<'stack, P> {
279 &self.data
280 }
281
282 pub fn into_payload(mut self) -> GattData<'stack, P> {
289 GattData {
290 pdu: self.data.pdu.take(),
291 connection: self.data.connection.clone(),
292 }
293 }
294}
295
296impl<P: PacketPool> Drop for ReadEvent<'_, '_, P> {
297 fn drop(&mut self) {
298 let _ = process(&mut self.data, self.server, Ok(()));
299 }
300}
301
302pub struct WriteEvent<'stack, 'server, P: PacketPool> {
304 data: GattData<'stack, P>,
305 server: &'server dyn DynamicAttributeServer<P>,
306}
307
308impl<'stack, P: PacketPool> WriteEvent<'stack, '_, P> {
309 pub fn handle(&self) -> u16 {
311 unwrap!(self.data.handle())
314 }
315
316 pub fn data(&self) -> &[u8] {
318 &self.data.pdu.as_ref().unwrap().as_ref()[3..]
320 }
321
322 pub fn value<T: FromGatt>(&self, _c: &Characteristic<T>) -> Result<T, FromGattError> {
324 T::from_gatt(self.data())
325 }
326
327 pub fn accept(mut self) -> Result<Reply<'stack, P>, Error> {
331 process(&mut self.data, self.server, Ok(()))
332 }
333
334 pub fn reject(mut self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
336 process(&mut self.data, self.server, Err(err))
337 }
338
339 pub fn payload(&self) -> &GattData<'stack, P> {
341 &self.data
342 }
343
344 pub fn into_payload(mut self) -> GattData<'stack, P> {
351 GattData {
352 pdu: self.data.pdu.take(),
353 connection: self.data.connection.clone(),
354 }
355 }
356}
357
358impl<P: PacketPool> Drop for WriteEvent<'_, '_, P> {
359 fn drop(&mut self) {
360 let _ = process(&mut self.data, self.server, Ok(()));
361 }
362}
363
364pub struct OtherEvent<'stack, 'server, P: PacketPool> {
366 data: GattData<'stack, P>,
367 server: &'server dyn DynamicAttributeServer<P>,
368}
369
370impl<'stack, P: PacketPool> OtherEvent<'stack, '_, P> {
371 pub fn accept(mut self) -> Result<Reply<'stack, P>, Error> {
375 process(&mut self.data, self.server, Ok(()))
376 }
377
378 pub fn reject(mut self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
380 process(&mut self.data, self.server, Err(err))
381 }
382
383 pub fn payload(&self) -> &GattData<'stack, P> {
385 &self.data
386 }
387
388 pub fn into_payload(mut self) -> GattData<'stack, P> {
395 GattData {
396 pdu: self.data.pdu.take(),
397 connection: self.data.connection.clone(),
398 }
399 }
400}
401
402impl<P: PacketPool> Drop for OtherEvent<'_, '_, P> {
403 fn drop(&mut self) {
404 let _ = process(&mut self.data, self.server, Ok(()));
405 }
406}
407
408fn process<'stack, P>(
409 data: &mut GattData<'stack, P>,
410 server: &dyn DynamicAttributeServer<P>,
411 result: Result<(), AttErrorCode>,
412) -> Result<Reply<'stack, P>, Error>
413where
414 P: PacketPool,
415{
416 if let Some(pdu) = data.pdu.take() {
417 let res = match result {
418 Ok(_) => process_accept(&pdu, &data.connection, server),
419 Err(code) => process_reject(&pdu, &data.connection, code),
420 };
421 res
422 } else {
423 Ok(Reply::new(data.connection.clone(), None))
424 }
425}
426
427fn process_accept<'stack, P>(
428 pdu: &Pdu<P::Packet>,
429 connection: &Connection<'stack, P>,
430 server: &dyn DynamicAttributeServer<P>,
431) -> Result<Reply<'stack, P>, Error>
432where
433 P: PacketPool,
434{
435 let att = unwrap!(Att::decode(pdu.as_ref()));
438 let Att::Client(att) = att else {
439 unreachable!("Expected Att::Client, got {:?}", att)
440 };
441 let mut tx = P::allocate().ok_or(Error::OutOfMemory)?;
442 let mut w = WriteCursor::new(tx.as_mut());
443 let (mut header, mut data) = w.split(4)?;
444 if let Some(written) = server.process(connection, &att, data.write_buf())? {
445 let mtu = connection.get_att_mtu();
446 data.commit(written)?;
447 data.truncate(mtu as usize);
448 header.write(data.len() as u16)?;
449 header.write(4_u16)?;
450 let len = header.len() + data.len();
451 let pdu = Pdu::new(tx, len);
452 Ok(Reply::new(connection.clone(), Some(pdu)))
453 } else {
454 Ok(Reply::new(connection.clone(), None))
455 }
456}
457
458fn process_reject<'stack, P: PacketPool>(
459 pdu: &Pdu<P::Packet>,
460 connection: &Connection<'stack, P>,
461 code: AttErrorCode,
462) -> Result<Reply<'stack, P>, Error> {
463 let att = unwrap!(Att::decode(pdu.as_ref()));
466 let Att::Client(att) = att else {
467 unreachable!("Expected Att::Client, got {:?}", att)
468 };
469 let handle = match att {
470 AttClient::Request(AttReq::Write { handle, .. }) => handle,
471 AttClient::Command(AttCmd::Write { handle, .. }) => handle,
472 AttClient::Request(AttReq::Read { handle }) => handle,
473 AttClient::Request(AttReq::ReadBlob { handle, .. }) => handle,
474 _ => 0, };
476 let request = pdu.as_ref()[0];
478 let rsp = AttRsp::Error { request, handle, code };
479 let pdu = send(connection, AttServer::Response(rsp))?;
480 Ok(Reply::new(connection.clone(), Some(pdu)))
481}
482
483fn send<'stack, P: PacketPool>(conn: &Connection<'stack, P>, att: AttServer<'_>) -> Result<Pdu<P::Packet>, Error> {
484 let mut tx = P::allocate().ok_or(Error::OutOfMemory)?;
485 let mut w = WriteCursor::new(tx.as_mut());
486 let (mut header, mut data) = w.split(4)?;
487 data.write(Att::Server(att))?;
488
489 let mtu = conn.get_att_mtu();
490 data.truncate(mtu as usize);
491 header.write(data.len() as u16)?;
492 header.write(4_u16)?;
493 let len = header.len() + data.len();
494 Ok(Pdu::new(tx, len))
495}
496
497pub struct Reply<'stack, P: PacketPool> {
502 connection: Connection<'stack, P>,
503 pdu: Option<Pdu<P::Packet>>,
504}
505
506impl<'stack, P: PacketPool> Reply<'stack, P> {
507 fn new(connection: Connection<'stack, P>, pdu: Option<Pdu<P::Packet>>) -> Self {
508 Self { connection, pdu }
509 }
510
511 pub fn try_send(mut self) -> Result<(), Error> {
515 if let Some(pdu) = self.pdu.take() {
516 self.connection.try_send(pdu)
517 } else {
518 Ok(())
519 }
520 }
521
522 pub async fn send(mut self) {
524 if let Some(pdu) = self.pdu.take() {
525 self.connection.send(pdu).await
526 }
527 }
528}
529
530impl<P: PacketPool> Drop for Reply<'_, P> {
531 fn drop(&mut self) {
532 if let Some(pdu) = self.pdu.take() {
533 if self.connection.try_send(pdu).is_err() {
534 warn!("[gatt] error sending reply (outbound buffer full)");
535 }
536 }
537 }
538}
539
540pub struct NotificationListener<'lst, const MTU: usize> {
542 handle: u16,
543 listener: pubsub::DynSubscriber<'lst, Notification<MTU>>,
544}
545
546impl<'lst, const MTU: usize> NotificationListener<'lst, MTU> {
547 #[allow(clippy::should_implement_trait)]
548 pub async fn next(&mut self) -> Notification<MTU> {
550 loop {
551 if let WaitResult::Message(m) = self.listener.next_message().await {
552 if m.handle == self.handle {
553 return m;
554 }
555 }
556 }
557 }
558}
559
560const MAX_NOTIF: usize = config::GATT_CLIENT_NOTIFICATION_MAX_SUBSCRIBERS;
561const NOTIF_QSIZE: usize = config::GATT_CLIENT_NOTIFICATION_QUEUE_SIZE;
562
563pub struct GattClient<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> {
565 known_services: RefCell<Vec<ServiceHandle, MAX_SERVICES>>,
566 rx: DynamicReceiver<'reference, (ConnHandle, Pdu<P::Packet>)>,
567 stack: &'reference Stack<'reference, T, P>,
568 connection: Connection<'reference, P>,
569 response_channel: Channel<NoopRawMutex, (ConnHandle, Pdu<P::Packet>), 1>,
570
571 notifications: PubSubChannel<NoopRawMutex, Notification<512>, NOTIF_QSIZE, MAX_NOTIF, 1>,
573}
574
575#[derive(Debug, PartialEq, Clone)]
577#[cfg_attr(feature = "defmt", derive(defmt::Format))]
578pub struct Notification<const MTU: usize> {
579 handle: u16,
580 data: [u8; MTU],
581 len: usize,
582}
583
584impl<const MTU: usize> AsRef<[u8]> for Notification<MTU> {
585 fn as_ref(&self) -> &[u8] {
586 &self.data[..self.len]
587 }
588}
589
590#[cfg_attr(feature = "defmt", derive(defmt::Format))]
592#[derive(Debug, PartialEq, Clone)]
593pub struct ServiceHandle {
594 start: u16,
595 end: u16,
596 uuid: Uuid,
597}
598
599pub(crate) struct Response<P> {
600 pdu: Pdu<P>,
601 handle: ConnHandle,
602}
603
604pub(crate) trait Client<'d, E, P: PacketPool> {
606 fn request(&self, req: AttReq<'_>) -> impl Future<Output = Result<Response<P::Packet>, BleHostError<E>>>;
608 fn command(&self, cmd: AttCmd<'_>) -> impl Future<Output = Result<(), BleHostError<E>>>;
609}
610
611impl<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> Client<'reference, T::Error, P>
612 for GattClient<'reference, T, P, MAX_SERVICES>
613{
614 async fn request(&self, req: AttReq<'_>) -> Result<Response<P::Packet>, BleHostError<T::Error>> {
615 let data = Att::Client(AttClient::Request(req));
616
617 self.send_att_data(data).await?;
618
619 let (h, pdu) = self.response_channel.receive().await;
620
621 assert_eq!(h, self.connection.handle());
622 Ok(Response { handle: h, pdu })
623 }
624
625 async fn command(&self, cmd: AttCmd<'_>) -> Result<(), BleHostError<T::Error>> {
626 let data = Att::Client(AttClient::Command(cmd));
627
628 self.send_att_data(data).await?;
629
630 Ok(())
631 }
632}
633
634impl<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> GattClient<'reference, T, P, MAX_SERVICES> {
635 async fn send_att_data(&self, data: Att<'_>) -> Result<(), BleHostError<T::Error>> {
636 let header = L2capHeader {
637 channel: crate::types::l2cap::L2CAP_CID_ATT,
638 length: data.size() as u16,
639 };
640
641 let mut buf = P::allocate().ok_or(Error::OutOfMemory)?;
642 let mut w = WriteCursor::new(buf.as_mut());
643 w.write_hci(&header)?;
644 w.write(data)?;
645 let len = w.len();
646
647 self.connection.send(Pdu::new(buf, len)).await;
648 Ok(())
649 }
650}
651
652impl<'reference, C: Controller, P: PacketPool, const MAX_SERVICES: usize> GattClient<'reference, C, P, MAX_SERVICES> {
653 pub async fn new(
655 stack: &'reference Stack<'reference, C, P>,
656 connection: &Connection<'reference, P>,
657 ) -> Result<GattClient<'reference, C, P, MAX_SERVICES>, BleHostError<C::Error>> {
658 let l2cap = L2capHeader { channel: 4, length: 3 };
659 let mut buf = P::allocate().ok_or(Error::OutOfMemory)?;
660 let mut w = WriteCursor::new(buf.as_mut());
661 w.write_hci(&l2cap)?;
662 w.write(att::Att::Client(att::AttClient::Request(att::AttReq::ExchangeMtu {
663 mtu: P::MTU as u16 - 4,
664 })))?;
665
666 let len = w.len();
667 connection.send(Pdu::new(buf, len)).await;
668 Ok(Self {
669 known_services: RefCell::new(heapless::Vec::new()),
670 rx: stack.host.att_client.receiver().into(),
671 stack,
672 connection: connection.clone(),
673
674 response_channel: Channel::new(),
675
676 notifications: PubSubChannel::new(),
677 })
678 }
679
680 pub async fn services_by_uuid(
682 &self,
683 uuid: &Uuid,
684 ) -> Result<Vec<ServiceHandle, MAX_SERVICES>, BleHostError<C::Error>> {
685 let mut start: u16 = 0x0001;
686 let mut result = Vec::new();
687
688 loop {
689 let data = att::AttReq::FindByTypeValue {
690 start_handle: start,
691 end_handle: 0xffff,
692 att_type: PRIMARY_SERVICE.into(),
693 att_value: uuid.as_raw(),
694 };
695
696 let response = self.request(data).await?;
697 let res = Self::response(response.pdu.as_ref())?;
698 match res {
699 AttRsp::Error { request, handle, code } => {
700 if code == att::AttErrorCode::ATTRIBUTE_NOT_FOUND {
701 break;
702 }
703 return Err(Error::Att(code).into());
704 }
705 AttRsp::FindByTypeValue { mut it } => {
706 let mut end: u16 = 0;
707 while let Some(res) = it.next() {
708 let (handle, e) = res?;
709 end = e;
710 let svc = ServiceHandle {
711 start: handle,
712 end,
713 uuid: uuid.clone(),
714 };
715 result.push(svc.clone()).map_err(|_| Error::InsufficientSpace)?;
716 self.known_services
717 .borrow_mut()
718 .push(svc)
719 .map_err(|_| Error::InsufficientSpace)?;
720 }
721 if end == 0xFFFF {
722 break;
723 }
724 start = end + 1;
725 }
726 res => {
727 trace!("[gatt client] response: {:?}", res);
728 return Err(Error::UnexpectedGattResponse.into());
729 }
730 }
731 }
732
733 Ok(result)
734 }
735
736 pub async fn characteristic_by_uuid<T: AsGatt>(
738 &self,
739 service: &ServiceHandle,
740 uuid: &Uuid,
741 ) -> Result<Characteristic<T>, BleHostError<C::Error>> {
742 let mut start: u16 = service.start;
743 loop {
744 let data = att::AttReq::ReadByType {
745 start,
746 end: service.end,
747 attribute_type: CHARACTERISTIC.into(),
748 };
749 let response = self.request(data).await?;
750
751 match Self::response(response.pdu.as_ref())? {
752 AttRsp::ReadByType { mut it } => {
753 while let Some(Ok((handle, item))) = it.next() {
754 let expected_items_len = 5;
755 let item_len = item.len();
756
757 if item_len < expected_items_len {
758 return Err(Error::MalformedCharacteristicDeclaration {
759 expected: expected_items_len,
760 actual: item_len,
761 }
762 .into());
763 }
764 if let AttributeData::Declaration {
765 props,
766 handle,
767 uuid: decl_uuid,
768 } = AttributeData::decode_declaration(item)?
769 {
770 if *uuid == decl_uuid {
771 let cccd_handle =
773 if props.any(&[CharacteristicProp::Indicate, CharacteristicProp::Notify]) {
774 Some(self.get_characteristic_cccd(handle).await?.0)
775 } else {
776 None
777 };
778
779 return Ok(Characteristic {
780 handle,
781 cccd_handle,
782 phantom: PhantomData,
783 });
784 }
785
786 if handle == 0xFFFF {
787 return Err(Error::NotFound.into());
788 }
789 start = handle + 1;
790 } else {
791 return Err(Error::InvalidCharacteristicDeclarationData.into());
792 }
793 }
794 }
795 AttRsp::Error { request, handle, code } => return Err(Error::Att(code).into()),
796 _ => {
797 return Err(Error::UnexpectedGattResponse.into());
798 }
799 }
800 }
801 }
802
803 async fn get_characteristic_cccd(&self, char_handle: u16) -> Result<(u16, CCCD), BleHostError<C::Error>> {
804 let data = att::AttReq::ReadByType {
805 start: char_handle,
806 end: char_handle + 1,
807 attribute_type: CLIENT_CHARACTERISTIC_CONFIGURATION.into(),
808 };
809
810 let response = self.request(data).await?;
811
812 match Self::response(response.pdu.as_ref())? {
813 AttRsp::ReadByType { mut it } => {
814 if let Some(Ok((handle, item))) = it.next() {
815 if item.is_empty() {
819 Ok((handle, CCCD(0)))
820 } else {
821 Ok((
822 handle,
823 CCCD(u16::from_le_bytes(
824 item.try_into()
825 .map_err(|_| Error::InvalidCccdHandleLength(item.len()))?,
826 )),
827 ))
828 }
829 } else {
830 Err(Error::NotFound.into())
831 }
832 }
833 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
834 _ => Err(Error::UnexpectedGattResponse.into()),
835 }
836 }
837
838 pub async fn read_characteristic<T: AsGatt>(
842 &self,
843 characteristic: &Characteristic<T>,
844 dest: &mut [u8],
845 ) -> Result<usize, BleHostError<C::Error>> {
846 let data = att::AttReq::Read {
847 handle: characteristic.handle,
848 };
849
850 let response = self.request(data).await?;
851
852 match Self::response(response.pdu.as_ref())? {
853 AttRsp::Read { data } => {
854 let to_copy = data.len().min(dest.len());
855 dest[..to_copy].copy_from_slice(&data[..to_copy]);
856 Ok(to_copy)
857 }
858 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
859 _ => Err(Error::UnexpectedGattResponse.into()),
860 }
861 }
862
863 pub async fn read_characteristic_by_uuid(
867 &self,
868 service: &ServiceHandle,
869 uuid: &Uuid,
870 dest: &mut [u8],
871 ) -> Result<usize, BleHostError<C::Error>> {
872 let data = att::AttReq::ReadByType {
873 start: service.start,
874 end: service.end,
875 attribute_type: uuid.clone(),
876 };
877
878 let response = self.request(data).await?;
879
880 match Self::response(response.pdu.as_ref())? {
881 AttRsp::ReadByType { mut it } => {
882 let mut to_copy = 0;
883 if let Some(item) = it.next() {
884 let (_handle, data) = item?;
885 to_copy = data.len().min(dest.len());
886 dest[..to_copy].copy_from_slice(&data[..to_copy]);
887 }
888 Ok(to_copy)
889 }
890 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
891 _ => Err(Error::UnexpectedGattResponse.into()),
892 }
893 }
894
895 pub async fn write_characteristic<T: FromGatt>(
897 &self,
898 handle: &Characteristic<T>,
899 buf: &[u8],
900 ) -> Result<(), BleHostError<C::Error>> {
901 let data = att::AttReq::Write {
902 handle: handle.handle,
903 data: buf,
904 };
905
906 let response = self.request(data).await?;
907 match Self::response(response.pdu.as_ref())? {
908 AttRsp::Write => Ok(()),
909 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
910 _ => Err(Error::UnexpectedGattResponse.into()),
911 }
912 }
913
914 pub async fn write_characteristic_without_response<T: FromGatt>(
916 &self,
917 handle: &Characteristic<T>,
918 buf: &[u8],
919 ) -> Result<(), BleHostError<C::Error>> {
920 let data = att::AttCmd::Write {
921 handle: handle.handle,
922 data: buf,
923 };
924
925 self.command(data).await?;
926
927 Ok(())
928 }
929
930 pub async fn subscribe<T: AsGatt>(
934 &self,
935 characteristic: &Characteristic<T>,
936 indication: bool,
937 ) -> Result<NotificationListener<'_, 512>, BleHostError<C::Error>> {
938 let properties = u16::to_le_bytes(if indication { 0x02 } else { 0x01 });
939
940 let data = att::AttReq::Write {
941 handle: characteristic.cccd_handle.ok_or(Error::NotSupported)?,
942 data: &properties,
943 };
944
945 let response = self.request(data).await?;
947
948 match Self::response(response.pdu.as_ref())? {
949 AttRsp::Write => match self.notifications.dyn_subscriber() {
950 Ok(listener) => Ok(NotificationListener {
951 listener,
952 handle: characteristic.handle,
953 }),
954 Err(embassy_sync::pubsub::Error::MaximumSubscribersReached) => {
955 Err(Error::GattSubscriberLimitReached.into())
956 }
957 Err(_) => Err(Error::Other.into()),
958 },
959 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
960 _ => Err(Error::UnexpectedGattResponse.into()),
961 }
962 }
963
964 pub async fn unsubscribe<T: AsGatt>(
966 &self,
967 characteristic: &Characteristic<T>,
968 ) -> Result<(), BleHostError<C::Error>> {
969 let properties = u16::to_le_bytes(0);
970 let data = att::AttReq::Write {
971 handle: characteristic.cccd_handle.ok_or(Error::NotSupported)?,
972 data: &[0, 0],
973 };
974
975 let response = self.request(data).await?;
977
978 match Self::response(response.pdu.as_ref())? {
979 AttRsp::Write => Ok(()),
980 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
981 _ => Err(Error::UnexpectedGattResponse.into()),
982 }
983 }
984
985 async fn handle_notification_packet(&self, data: &[u8]) -> Result<(), BleHostError<C::Error>> {
987 let mut r = ReadCursor::new(data);
988 let value_handle: u16 = r.read()?;
989 let value_attr = r.remaining();
990
991 let handle = value_handle;
992
993 let mut data = [0u8; 512];
995 let to_copy = data.len().min(value_attr.len());
996 data[..to_copy].copy_from_slice(&value_attr[..to_copy]);
997 let n = Notification {
998 handle,
999 data,
1000 len: to_copy,
1001 };
1002 self.notifications.immediate_publisher().publish_immediate(n);
1003 Ok(())
1004 }
1005
1006 pub async fn task(&self) -> Result<(), BleHostError<C::Error>> {
1008 loop {
1009 let (handle, pdu) = self.rx.receive().await;
1010 let data = pdu.as_ref();
1011 if pdu.as_ref()[0] == ATT_HANDLE_VALUE_NTF {
1013 self.handle_notification_packet(&pdu.as_ref()[1..]).await?;
1014 } else {
1015 self.response_channel.send((handle, pdu)).await;
1016 }
1017 }
1018 }
1019
1020 fn response<'a>(data: &'a [u8]) -> Result<AttRsp<'a>, BleHostError<C::Error>> {
1021 let att = Att::decode(data)?;
1022 match att {
1023 Att::Server(AttServer::Response(rsp)) => Ok(rsp),
1024 _ => Err(Error::UnexpectedGattResponse.into()),
1025 }
1026 }
1027}