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};
19use crate::attribute_server::{AttributeServer, DynamicAttributeServer};
20use crate::connection::Connection;
21#[cfg(feature = "security")]
22use crate::connection::SecurityLevel;
23use crate::cursor::{ReadCursor, WriteCursor};
24use crate::pdu::Pdu;
25use crate::prelude::ConnectionEvent;
26#[cfg(feature = "security")]
27use crate::security_manager::PassKey;
28use crate::types::gatt_traits::{AsGatt, FromGatt, FromGattError};
29use crate::types::l2cap::L2capHeader;
30#[cfg(feature = "security")]
31use crate::BondInformation;
32use crate::{config, BleHostError, Error, PacketPool, Stack};
33
34pub enum GattConnectionEvent<'stack, 'server, P: PacketPool> {
36 Disconnected {
38 reason: Status,
40 },
41 PhyUpdated {
43 tx_phy: PhyKind,
45 rx_phy: PhyKind,
47 },
48 ConnectionParamsUpdated {
50 conn_interval: Duration,
52 peripheral_latency: u16,
54 supervision_timeout: Duration,
56 },
57 RequestConnectionParams {
59 min_connection_interval: Duration,
61 max_connection_interval: Duration,
63 max_latency: u16,
65 supervision_timeout: Duration,
67 },
68 DataLengthUpdated {
70 max_tx_octets: u16,
72 max_tx_time: u16,
74 max_rx_octets: u16,
76 max_rx_time: u16,
78 },
79 Gatt {
81 event: GattEvent<'stack, 'server, P>,
83 },
84
85 #[cfg(feature = "security")]
86 PassKeyDisplay(PassKey),
88 #[cfg(feature = "security")]
89 PassKeyConfirm(PassKey),
91 #[cfg(feature = "security")]
92 PassKeyInput,
94 #[cfg(feature = "security")]
95 PairingComplete {
97 security_level: SecurityLevel,
99 bond: Option<BondInformation>,
101 },
102 #[cfg(feature = "security")]
103 PairingFailed(Error),
105}
106
107pub struct GattConnection<'stack, 'server, P: PacketPool> {
109 connection: Connection<'stack, P>,
110 pub(crate) server: &'server dyn DynamicAttributeServer<P>,
111}
112
113impl<P: PacketPool> Drop for GattConnection<'_, '_, P> {
114 fn drop(&mut self) {
115 trace!("[gatt {}] disconnecting from server", self.connection.handle().raw());
116 self.server.disconnect(&self.connection);
117 }
118}
119
120impl<'stack, 'server, P: PacketPool> GattConnection<'stack, 'server, P> {
121 pub(crate) fn try_new<'values, M: RawMutex, const AT: usize, const CT: usize, const CN: usize>(
124 connection: Connection<'stack, P>,
125 server: &'server AttributeServer<'values, M, P, AT, CT, CN>,
126 ) -> Result<Self, Error> {
127 trace!("[gatt {}] connecting to server", connection.handle().raw());
128 server.connect(&connection)?;
129 Ok(Self { connection, server })
130 }
131
132 pub fn pass_key_confirm(&self) -> Result<(), Error> {
134 self.connection.pass_key_confirm()
135 }
136
137 pub fn pass_key_cancel(&self) -> Result<(), Error> {
139 self.connection.pass_key_cancel()
140 }
141
142 pub fn pass_key_input(&self, pass_key: u32) -> Result<(), Error> {
144 self.connection.pass_key_input(pass_key)
145 }
146
147 pub async fn next(&self) -> GattConnectionEvent<'stack, 'server, P> {
151 match select(self.connection.next(), self.connection.next_gatt()).await {
152 Either::First(event) => match event {
153 ConnectionEvent::Disconnected { reason } => GattConnectionEvent::Disconnected { reason },
154 ConnectionEvent::ConnectionParamsUpdated {
155 conn_interval,
156 peripheral_latency,
157 supervision_timeout,
158 } => GattConnectionEvent::ConnectionParamsUpdated {
159 conn_interval,
160 peripheral_latency,
161 supervision_timeout,
162 },
163 ConnectionEvent::RequestConnectionParams {
164 min_connection_interval,
165 max_connection_interval,
166 max_latency,
167 supervision_timeout,
168 } => GattConnectionEvent::RequestConnectionParams {
169 min_connection_interval,
170 max_connection_interval,
171 max_latency,
172 supervision_timeout,
173 },
174 ConnectionEvent::PhyUpdated { tx_phy, rx_phy } => GattConnectionEvent::PhyUpdated { tx_phy, rx_phy },
175 ConnectionEvent::DataLengthUpdated {
176 max_tx_octets,
177 max_tx_time,
178 max_rx_octets,
179 max_rx_time,
180 } => GattConnectionEvent::DataLengthUpdated {
181 max_tx_octets,
182 max_tx_time,
183 max_rx_octets,
184 max_rx_time,
185 },
186
187 #[cfg(feature = "security")]
188 ConnectionEvent::PassKeyDisplay(key) => GattConnectionEvent::PassKeyDisplay(key),
189
190 #[cfg(feature = "security")]
191 ConnectionEvent::PassKeyConfirm(key) => GattConnectionEvent::PassKeyConfirm(key),
192
193 #[cfg(feature = "security")]
194 ConnectionEvent::PassKeyInput => GattConnectionEvent::PassKeyInput,
195
196 #[cfg(feature = "security")]
197 ConnectionEvent::PairingComplete { security_level, bond } => {
198 GattConnectionEvent::PairingComplete { security_level, bond }
199 }
200
201 #[cfg(feature = "security")]
202 ConnectionEvent::PairingFailed(err) => GattConnectionEvent::PairingFailed(err),
203 },
204 Either::Second(data) => GattConnectionEvent::Gatt {
205 event: GattEvent::new(GattData::new(data, self.connection.clone()), self.server),
206 },
207 }
208 }
209
210 pub fn raw(&self) -> &Connection<'stack, P> {
212 &self.connection
213 }
214}
215
216pub struct GattData<'stack, P: PacketPool> {
218 pdu: Option<Pdu<P::Packet>>,
219 connection: Connection<'stack, P>,
220}
221
222impl<'stack, P: PacketPool> GattData<'stack, P> {
223 pub(crate) const fn new(pdu: Pdu<P::Packet>, connection: Connection<'stack, P>) -> Self {
224 Self {
225 pdu: Some(pdu),
226 connection,
227 }
228 }
229
230 pub fn handle(&self) -> Option<u16> {
234 match self.incoming() {
235 AttClient::Request(AttReq::Write { handle, .. }) => Some(handle),
236 AttClient::Command(AttCmd::Write { handle, .. }) => Some(handle),
237 AttClient::Request(AttReq::Read { handle }) => Some(handle),
238 AttClient::Request(AttReq::ReadBlob { handle, .. }) => Some(handle),
239 _ => None,
240 }
241 }
242
243 pub fn incoming(&self) -> AttClient<'_> {
245 let att = unwrap!(Att::decode(self.pdu.as_ref().unwrap().as_ref()));
249 let Att::Client(client) = att else {
250 unreachable!("Expected Att::Client, got {:?}", att)
251 };
252
253 client
254 }
255
256 pub async fn reply(self, rsp: AttRsp<'_>) -> Result<(), Error> {
258 let pdu = send(&self.connection, AttServer::Response(rsp))?;
259 self.connection.send(pdu).await;
260 Ok(())
261 }
262
263 pub async fn send_unsolicited(connection: &Connection<'_, P>, uns: AttUns<'_>) -> Result<(), Error> {
265 let pdu = send(connection, AttServer::Unsolicited(uns))?;
266 connection.send(pdu).await;
267 Ok(())
268 }
269}
270
271pub enum GattEvent<'stack, 'server, P: PacketPool> {
273 Read(ReadEvent<'stack, 'server, P>),
275 Write(WriteEvent<'stack, 'server, P>),
277 Other(OtherEvent<'stack, 'server, P>),
279}
280
281impl<'stack, 'server, P: PacketPool> GattEvent<'stack, 'server, P> {
282 pub fn new(data: GattData<'stack, P>, server: &'server dyn DynamicAttributeServer<P>) -> Self {
284 let att = data.incoming();
285 match att {
286 AttClient::Request(AttReq::Write { .. }) | AttClient::Command(AttCmd::Write { .. }) => {
287 GattEvent::Write(WriteEvent { data, server })
288 }
289 AttClient::Request(AttReq::Read { .. }) | AttClient::Request(AttReq::ReadBlob { .. }) => {
290 GattEvent::Read(ReadEvent { data, server })
291 }
292 _ => GattEvent::Other(OtherEvent { data, server }),
293 }
294 }
295
296 pub fn accept(self) -> Result<Reply<'stack, P>, Error> {
298 match self {
299 Self::Read(e) => e.accept(),
300 Self::Write(e) => e.accept(),
301 Self::Other(e) => e.accept(),
302 }
303 }
304
305 pub fn reject(self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
307 match self {
308 Self::Read(e) => e.reject(err),
309 Self::Write(e) => e.reject(err),
310 Self::Other(e) => e.reject(err),
311 }
312 }
313
314 pub fn payload(&self) -> &GattData<'stack, P> {
316 match self {
317 Self::Read(e) => e.payload(),
318 Self::Write(e) => e.payload(),
319 Self::Other(e) => e.payload(),
320 }
321 }
322
323 pub fn into_payload(self) -> GattData<'stack, P> {
330 match self {
331 Self::Read(e) => e.into_payload(),
332 Self::Write(e) => e.into_payload(),
333 Self::Other(e) => e.into_payload(),
334 }
335 }
336}
337
338pub struct ReadEvent<'stack, 'server, P: PacketPool> {
340 data: GattData<'stack, P>,
341 server: &'server dyn DynamicAttributeServer<P>,
342}
343
344impl<'stack, P: PacketPool> ReadEvent<'stack, '_, P> {
345 pub fn handle(&self) -> u16 {
347 unwrap!(self.data.handle())
350 }
351
352 pub fn accept(mut self) -> Result<Reply<'stack, P>, Error> {
356 process(&mut self.data, self.server, Ok(()))
357 }
358
359 pub fn reject(mut self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
361 process(&mut self.data, self.server, Err(err))
362 }
363
364 pub fn payload(&self) -> &GattData<'stack, P> {
366 &self.data
367 }
368
369 pub fn into_payload(mut self) -> GattData<'stack, P> {
376 GattData {
377 pdu: self.data.pdu.take(),
378 connection: self.data.connection.clone(),
379 }
380 }
381}
382
383impl<P: PacketPool> Drop for ReadEvent<'_, '_, P> {
384 fn drop(&mut self) {
385 let _ = process(&mut self.data, self.server, Ok(()));
386 }
387}
388
389pub struct WriteEvent<'stack, 'server, P: PacketPool> {
391 data: GattData<'stack, P>,
392 server: &'server dyn DynamicAttributeServer<P>,
393}
394
395impl<'stack, P: PacketPool> WriteEvent<'stack, '_, P> {
396 pub fn handle(&self) -> u16 {
398 unwrap!(self.data.handle())
401 }
402
403 pub fn data(&self) -> &[u8] {
405 &self.data.pdu.as_ref().unwrap().as_ref()[3..]
407 }
408
409 pub fn value<T: FromGatt>(&self, _c: &Characteristic<T>) -> Result<T, FromGattError> {
411 T::from_gatt(self.data())
412 }
413
414 pub fn accept(mut self) -> Result<Reply<'stack, P>, Error> {
418 process(&mut self.data, self.server, Ok(()))
419 }
420
421 pub fn reject(mut self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
423 process(&mut self.data, self.server, Err(err))
424 }
425
426 pub fn payload(&self) -> &GattData<'stack, P> {
428 &self.data
429 }
430
431 pub fn into_payload(mut self) -> GattData<'stack, P> {
438 GattData {
439 pdu: self.data.pdu.take(),
440 connection: self.data.connection.clone(),
441 }
442 }
443}
444
445impl<P: PacketPool> Drop for WriteEvent<'_, '_, P> {
446 fn drop(&mut self) {
447 let _ = process(&mut self.data, self.server, Ok(()));
448 }
449}
450
451pub struct OtherEvent<'stack, 'server, P: PacketPool> {
453 data: GattData<'stack, P>,
454 server: &'server dyn DynamicAttributeServer<P>,
455}
456
457impl<'stack, P: PacketPool> OtherEvent<'stack, '_, P> {
458 pub fn accept(mut self) -> Result<Reply<'stack, P>, Error> {
462 process(&mut self.data, self.server, Ok(()))
463 }
464
465 pub fn reject(mut self, err: AttErrorCode) -> Result<Reply<'stack, P>, Error> {
467 process(&mut self.data, self.server, Err(err))
468 }
469
470 pub fn payload(&self) -> &GattData<'stack, P> {
472 &self.data
473 }
474
475 pub fn into_payload(mut self) -> GattData<'stack, P> {
482 GattData {
483 pdu: self.data.pdu.take(),
484 connection: self.data.connection.clone(),
485 }
486 }
487}
488
489impl<P: PacketPool> Drop for OtherEvent<'_, '_, P> {
490 fn drop(&mut self) {
491 let _ = process(&mut self.data, self.server, Ok(()));
492 }
493}
494
495fn process<'stack, P>(
496 data: &mut GattData<'stack, P>,
497 server: &dyn DynamicAttributeServer<P>,
498 result: Result<(), AttErrorCode>,
499) -> Result<Reply<'stack, P>, Error>
500where
501 P: PacketPool,
502{
503 if let Some(pdu) = data.pdu.take() {
504 let res = match result {
505 Ok(_) => process_accept(&pdu, &data.connection, server),
506 Err(code) => process_reject(&pdu, &data.connection, code),
507 };
508 res
509 } else {
510 Ok(Reply::new(data.connection.clone(), None))
511 }
512}
513
514fn process_accept<'stack, P>(
515 pdu: &Pdu<P::Packet>,
516 connection: &Connection<'stack, P>,
517 server: &dyn DynamicAttributeServer<P>,
518) -> Result<Reply<'stack, P>, Error>
519where
520 P: PacketPool,
521{
522 let att = unwrap!(Att::decode(pdu.as_ref()));
525 let Att::Client(att) = att else {
526 unreachable!("Expected Att::Client, got {:?}", att)
527 };
528 let mut tx = P::allocate().ok_or(Error::OutOfMemory)?;
529 let mut w = WriteCursor::new(tx.as_mut());
530 let (mut header, mut data) = w.split(4)?;
531 if let Some(written) = server.process(connection, &att, data.write_buf())? {
532 let mtu = connection.get_att_mtu();
533 data.commit(written)?;
534 data.truncate(mtu as usize);
535 header.write(data.len() as u16)?;
536 header.write(4_u16)?;
537 let len = header.len() + data.len();
538 let pdu = Pdu::new(tx, len);
539 Ok(Reply::new(connection.clone(), Some(pdu)))
540 } else {
541 Ok(Reply::new(connection.clone(), None))
542 }
543}
544
545fn process_reject<'stack, P: PacketPool>(
546 pdu: &Pdu<P::Packet>,
547 connection: &Connection<'stack, P>,
548 code: AttErrorCode,
549) -> Result<Reply<'stack, P>, Error> {
550 let att = unwrap!(Att::decode(pdu.as_ref()));
553 let Att::Client(att) = att else {
554 unreachable!("Expected Att::Client, got {:?}", att)
555 };
556 let handle = match att {
557 AttClient::Request(AttReq::Write { handle, .. }) => handle,
558 AttClient::Command(AttCmd::Write { handle, .. }) => handle,
559 AttClient::Request(AttReq::Read { handle }) => handle,
560 AttClient::Request(AttReq::ReadBlob { handle, .. }) => handle,
561 _ => 0, };
563 let request = pdu.as_ref()[0];
565 let rsp = AttRsp::Error { request, handle, code };
566 let pdu = send(connection, AttServer::Response(rsp))?;
567 Ok(Reply::new(connection.clone(), Some(pdu)))
568}
569
570fn send<'stack, P: PacketPool>(conn: &Connection<'stack, P>, att: AttServer<'_>) -> Result<Pdu<P::Packet>, Error> {
571 let mut tx = P::allocate().ok_or(Error::OutOfMemory)?;
572 let mut w = WriteCursor::new(tx.as_mut());
573 let (mut header, mut data) = w.split(4)?;
574 data.write(Att::Server(att))?;
575
576 let mtu = conn.get_att_mtu();
577 data.truncate(mtu as usize);
578 header.write(data.len() as u16)?;
579 header.write(4_u16)?;
580 let len = header.len() + data.len();
581 Ok(Pdu::new(tx, len))
582}
583
584pub struct Reply<'stack, P: PacketPool> {
589 connection: Connection<'stack, P>,
590 pdu: Option<Pdu<P::Packet>>,
591}
592
593impl<'stack, P: PacketPool> Reply<'stack, P> {
594 fn new(connection: Connection<'stack, P>, pdu: Option<Pdu<P::Packet>>) -> Self {
595 Self { connection, pdu }
596 }
597
598 pub fn try_send(mut self) -> Result<(), Error> {
602 if let Some(pdu) = self.pdu.take() {
603 self.connection.try_send(pdu)
604 } else {
605 Ok(())
606 }
607 }
608
609 pub async fn send(mut self) {
611 if let Some(pdu) = self.pdu.take() {
612 self.connection.send(pdu).await
613 }
614 }
615}
616
617impl<P: PacketPool> Drop for Reply<'_, P> {
618 fn drop(&mut self) {
619 if let Some(pdu) = self.pdu.take() {
620 if self.connection.try_send(pdu).is_err() {
621 warn!("[gatt] error sending reply (outbound buffer full)");
622 }
623 }
624 }
625}
626
627pub struct NotificationListener<'lst, const MTU: usize> {
629 handle: u16,
630 listener: pubsub::DynSubscriber<'lst, Notification<MTU>>,
631}
632
633impl<'lst, const MTU: usize> NotificationListener<'lst, MTU> {
634 #[allow(clippy::should_implement_trait)]
635 pub async fn next(&mut self) -> Notification<MTU> {
637 loop {
638 if let WaitResult::Message(m) = self.listener.next_message().await {
639 if m.handle == self.handle {
640 return m;
641 }
642 }
643 }
644 }
645}
646
647const MAX_NOTIF: usize = config::GATT_CLIENT_NOTIFICATION_MAX_SUBSCRIBERS;
648const NOTIF_QSIZE: usize = config::GATT_CLIENT_NOTIFICATION_QUEUE_SIZE;
649
650pub struct GattClient<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> {
652 known_services: RefCell<Vec<ServiceHandle, MAX_SERVICES>>,
653 rx: DynamicReceiver<'reference, (ConnHandle, Pdu<P::Packet>)>,
654 stack: &'reference Stack<'reference, T, P>,
655 connection: Connection<'reference, P>,
656 response_channel: Channel<NoopRawMutex, (ConnHandle, Pdu<P::Packet>), 1>,
657
658 notifications: PubSubChannel<NoopRawMutex, Notification<512>, NOTIF_QSIZE, MAX_NOTIF, 1>,
660}
661
662#[derive(Debug, PartialEq, Clone)]
664#[cfg_attr(feature = "defmt", derive(defmt::Format))]
665pub struct Notification<const MTU: usize> {
666 handle: u16,
667 data: [u8; MTU],
668 len: usize,
669}
670
671impl<const MTU: usize> AsRef<[u8]> for Notification<MTU> {
672 fn as_ref(&self) -> &[u8] {
673 &self.data[..self.len]
674 }
675}
676
677#[cfg_attr(feature = "defmt", derive(defmt::Format))]
679#[derive(Debug, PartialEq, Clone)]
680pub struct ServiceHandle {
681 start: u16,
682 end: u16,
683 uuid: Uuid,
684}
685
686pub(crate) struct Response<P> {
687 pdu: Pdu<P>,
688 handle: ConnHandle,
689}
690
691pub(crate) trait Client<'d, E, P: PacketPool> {
693 fn request(&self, req: AttReq<'_>) -> impl Future<Output = Result<Response<P::Packet>, BleHostError<E>>>;
695 fn command(&self, cmd: AttCmd<'_>) -> impl Future<Output = Result<(), BleHostError<E>>>;
696}
697
698impl<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> Client<'reference, T::Error, P>
699 for GattClient<'reference, T, P, MAX_SERVICES>
700{
701 async fn request(&self, req: AttReq<'_>) -> Result<Response<P::Packet>, BleHostError<T::Error>> {
702 let data = Att::Client(AttClient::Request(req));
703
704 self.send_att_data(data).await?;
705
706 let (h, pdu) = self.response_channel.receive().await;
707
708 assert_eq!(h, self.connection.handle());
709 Ok(Response { handle: h, pdu })
710 }
711
712 async fn command(&self, cmd: AttCmd<'_>) -> Result<(), BleHostError<T::Error>> {
713 let data = Att::Client(AttClient::Command(cmd));
714
715 self.send_att_data(data).await?;
716
717 Ok(())
718 }
719}
720
721impl<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> GattClient<'reference, T, P, MAX_SERVICES> {
722 async fn send_att_data(&self, data: Att<'_>) -> Result<(), BleHostError<T::Error>> {
723 let header = L2capHeader {
724 channel: crate::types::l2cap::L2CAP_CID_ATT,
725 length: data.size() as u16,
726 };
727
728 let mut buf = P::allocate().ok_or(Error::OutOfMemory)?;
729 let mut w = WriteCursor::new(buf.as_mut());
730 w.write_hci(&header)?;
731 w.write(data)?;
732 let len = w.len();
733
734 self.connection.send(Pdu::new(buf, len)).await;
735 Ok(())
736 }
737}
738
739impl<'reference, C: Controller, P: PacketPool, const MAX_SERVICES: usize> GattClient<'reference, C, P, MAX_SERVICES> {
740 pub async fn new(
742 stack: &'reference Stack<'reference, C, P>,
743 connection: &Connection<'reference, P>,
744 ) -> Result<GattClient<'reference, C, P, MAX_SERVICES>, BleHostError<C::Error>> {
745 let l2cap = L2capHeader { channel: 4, length: 3 };
746 let mut buf = P::allocate().ok_or(Error::OutOfMemory)?;
747 let mut w = WriteCursor::new(buf.as_mut());
748 w.write_hci(&l2cap)?;
749 w.write(att::Att::Client(att::AttClient::Request(att::AttReq::ExchangeMtu {
750 mtu: P::MTU as u16 - 4,
751 })))?;
752
753 let len = w.len();
754 connection.send(Pdu::new(buf, len)).await;
755 Ok(Self {
756 known_services: RefCell::new(heapless::Vec::new()),
757 rx: stack.host.att_client.receiver().into(),
758 stack,
759 connection: connection.clone(),
760
761 response_channel: Channel::new(),
762
763 notifications: PubSubChannel::new(),
764 })
765 }
766
767 pub async fn services_by_uuid(
769 &self,
770 uuid: &Uuid,
771 ) -> Result<Vec<ServiceHandle, MAX_SERVICES>, BleHostError<C::Error>> {
772 let mut start: u16 = 0x0001;
773 let mut result = Vec::new();
774
775 loop {
776 let data = att::AttReq::FindByTypeValue {
777 start_handle: start,
778 end_handle: 0xffff,
779 att_type: PRIMARY_SERVICE.into(),
780 att_value: uuid.as_raw(),
781 };
782
783 let response = self.request(data).await?;
784 let res = Self::response(response.pdu.as_ref())?;
785 match res {
786 AttRsp::Error { request, handle, code } => {
787 if code == att::AttErrorCode::ATTRIBUTE_NOT_FOUND {
788 break;
789 }
790 return Err(Error::Att(code).into());
791 }
792 AttRsp::FindByTypeValue { mut it } => {
793 let mut end: u16 = 0;
794 while let Some(res) = it.next() {
795 let (handle, e) = res?;
796 end = e;
797 let svc = ServiceHandle {
798 start: handle,
799 end,
800 uuid: uuid.clone(),
801 };
802 result.push(svc.clone()).map_err(|_| Error::InsufficientSpace)?;
803 self.known_services
804 .borrow_mut()
805 .push(svc)
806 .map_err(|_| Error::InsufficientSpace)?;
807 }
808 if end == 0xFFFF {
809 break;
810 }
811 start = end + 1;
812 }
813 res => {
814 trace!("[gatt client] response: {:?}", res);
815 return Err(Error::UnexpectedGattResponse.into());
816 }
817 }
818 }
819
820 Ok(result)
821 }
822
823 pub async fn characteristic_by_uuid<T: AsGatt>(
825 &self,
826 service: &ServiceHandle,
827 uuid: &Uuid,
828 ) -> Result<Characteristic<T>, BleHostError<C::Error>> {
829 let mut start: u16 = service.start;
830 let mut found_indicate_or_notify_uuid = Option::None;
831
832 loop {
833 let data = att::AttReq::ReadByType {
834 start,
835 end: service.end,
836 attribute_type: CHARACTERISTIC.into(),
837 };
838 let response = self.request(data).await?;
839
840 match Self::response(response.pdu.as_ref())? {
841 AttRsp::ReadByType { mut it } => {
842 while let Some(Ok((handle, item))) = it.next() {
843 let expected_items_len = 5;
844 let item_len = item.len();
845
846 if item_len < expected_items_len {
847 return Err(Error::MalformedCharacteristicDeclaration {
848 expected: expected_items_len,
849 actual: item_len,
850 }
851 .into());
852 }
853 if let AttributeData::Declaration {
854 props,
855 handle,
856 uuid: decl_uuid,
857 } = AttributeData::decode_declaration(item)?
858 {
859 if let Some(start_handle) = found_indicate_or_notify_uuid {
860 return Ok(Characteristic {
861 handle: start_handle,
862 cccd_handle: Some(self.get_characteristic_cccd(start_handle, handle).await?),
863 phantom: PhantomData,
864 });
865 }
866
867 if *uuid == decl_uuid {
868 if !props.any(&[CharacteristicProp::Indicate, CharacteristicProp::Notify]) {
871 return Ok(Characteristic {
872 handle,
873 cccd_handle: None,
874 phantom: PhantomData,
875 });
876 }
877 found_indicate_or_notify_uuid = Some(handle);
878 }
879
880 if handle == 0xFFFF {
881 return Err(Error::NotFound.into());
882 }
883 start = handle + 1;
884 } else {
885 return Err(Error::InvalidCharacteristicDeclarationData.into());
886 }
887 }
888 }
889 AttRsp::Error { request, handle, code } => match code {
890 att::AttErrorCode::ATTRIBUTE_NOT_FOUND => match found_indicate_or_notify_uuid {
891 Some(handle) => {
892 return Ok(Characteristic {
893 handle,
894 cccd_handle: Some(self.get_characteristic_cccd(handle, service.end).await?),
895 phantom: PhantomData,
896 });
897 }
898 None => return Err(Error::NotFound.into()),
899 },
900 _ => return Err(Error::Att(code).into()),
901 },
902 _ => return Err(Error::UnexpectedGattResponse.into()),
903 }
904 }
905 }
906
907 async fn get_characteristic_cccd(
908 &self,
909 char_start_handle: u16,
910 char_end_handle: u16,
911 ) -> Result<u16, BleHostError<C::Error>> {
912 let mut start_handle = char_start_handle;
913
914 while start_handle <= char_end_handle {
915 let data = att::AttReq::FindInformation {
916 start_handle,
917 end_handle: char_end_handle,
918 };
919
920 let response = self.request(data).await?;
921
922 match Self::response(response.pdu.as_ref())? {
923 AttRsp::FindInformation { mut it } => {
924 while let Some(Ok((handle, uuid))) = it.next() {
925 if uuid == CLIENT_CHARACTERISTIC_CONFIGURATION.into() {
926 return Ok(handle);
927 }
928 start_handle = handle + 1;
929 }
930 }
931 AttRsp::Error { request, handle, code } => return Err(Error::Att(code).into()),
932 _ => return Err(Error::UnexpectedGattResponse.into()),
933 }
934 }
935 Err(Error::NotFound.into())
936 }
937
938 pub async fn read_characteristic<T: AsGatt>(
942 &self,
943 characteristic: &Characteristic<T>,
944 dest: &mut [u8],
945 ) -> Result<usize, BleHostError<C::Error>> {
946 let data = att::AttReq::Read {
947 handle: characteristic.handle,
948 };
949
950 let response = self.request(data).await?;
951
952 match Self::response(response.pdu.as_ref())? {
953 AttRsp::Read { data } => {
954 let to_copy = data.len().min(dest.len());
955 dest[..to_copy].copy_from_slice(&data[..to_copy]);
956 Ok(to_copy)
957 }
958 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
959 _ => Err(Error::UnexpectedGattResponse.into()),
960 }
961 }
962
963 pub async fn read_characteristic_by_uuid(
967 &self,
968 service: &ServiceHandle,
969 uuid: &Uuid,
970 dest: &mut [u8],
971 ) -> Result<usize, BleHostError<C::Error>> {
972 let data = att::AttReq::ReadByType {
973 start: service.start,
974 end: service.end,
975 attribute_type: uuid.clone(),
976 };
977
978 let response = self.request(data).await?;
979
980 match Self::response(response.pdu.as_ref())? {
981 AttRsp::ReadByType { mut it } => {
982 let mut to_copy = 0;
983 if let Some(item) = it.next() {
984 let (_handle, data) = item?;
985 to_copy = data.len().min(dest.len());
986 dest[..to_copy].copy_from_slice(&data[..to_copy]);
987 }
988 Ok(to_copy)
989 }
990 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
991 _ => Err(Error::UnexpectedGattResponse.into()),
992 }
993 }
994
995 pub async fn write_characteristic<T: FromGatt>(
997 &self,
998 handle: &Characteristic<T>,
999 buf: &[u8],
1000 ) -> Result<(), BleHostError<C::Error>> {
1001 let data = att::AttReq::Write {
1002 handle: handle.handle,
1003 data: buf,
1004 };
1005
1006 let response = self.request(data).await?;
1007 match Self::response(response.pdu.as_ref())? {
1008 AttRsp::Write => Ok(()),
1009 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1010 _ => Err(Error::UnexpectedGattResponse.into()),
1011 }
1012 }
1013
1014 pub async fn write_characteristic_without_response<T: FromGatt>(
1016 &self,
1017 handle: &Characteristic<T>,
1018 buf: &[u8],
1019 ) -> Result<(), BleHostError<C::Error>> {
1020 let data = att::AttCmd::Write {
1021 handle: handle.handle,
1022 data: buf,
1023 };
1024
1025 self.command(data).await?;
1026
1027 Ok(())
1028 }
1029
1030 pub async fn subscribe<T: AsGatt>(
1034 &self,
1035 characteristic: &Characteristic<T>,
1036 indication: bool,
1037 ) -> Result<NotificationListener<'_, 512>, BleHostError<C::Error>> {
1038 let properties = u16::to_le_bytes(if indication { 0x02 } else { 0x01 });
1039
1040 let data = att::AttReq::Write {
1041 handle: characteristic.cccd_handle.ok_or(Error::NotSupported)?,
1042 data: &properties,
1043 };
1044
1045 let response = self.request(data).await?;
1047
1048 match Self::response(response.pdu.as_ref())? {
1049 AttRsp::Write => match self.notifications.dyn_subscriber() {
1050 Ok(listener) => Ok(NotificationListener {
1051 listener,
1052 handle: characteristic.handle,
1053 }),
1054 Err(embassy_sync::pubsub::Error::MaximumSubscribersReached) => {
1055 Err(Error::GattSubscriberLimitReached.into())
1056 }
1057 Err(_) => Err(Error::Other.into()),
1058 },
1059 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1060 _ => Err(Error::UnexpectedGattResponse.into()),
1061 }
1062 }
1063
1064 pub async fn unsubscribe<T: AsGatt>(
1066 &self,
1067 characteristic: &Characteristic<T>,
1068 ) -> Result<(), BleHostError<C::Error>> {
1069 let properties = u16::to_le_bytes(0);
1070 let data = att::AttReq::Write {
1071 handle: characteristic.cccd_handle.ok_or(Error::NotSupported)?,
1072 data: &[0, 0],
1073 };
1074
1075 let response = self.request(data).await?;
1077
1078 match Self::response(response.pdu.as_ref())? {
1079 AttRsp::Write => Ok(()),
1080 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1081 _ => Err(Error::UnexpectedGattResponse.into()),
1082 }
1083 }
1084
1085 async fn handle_notification_packet(&self, data: &[u8]) -> Result<(), BleHostError<C::Error>> {
1087 let mut r = ReadCursor::new(data);
1088 let value_handle: u16 = r.read()?;
1089 let value_attr = r.remaining();
1090
1091 let handle = value_handle;
1092
1093 let mut data = [0u8; 512];
1095 let to_copy = data.len().min(value_attr.len());
1096 data[..to_copy].copy_from_slice(&value_attr[..to_copy]);
1097 let n = Notification {
1098 handle,
1099 data,
1100 len: to_copy,
1101 };
1102 self.notifications.immediate_publisher().publish_immediate(n);
1103 Ok(())
1104 }
1105
1106 pub async fn task(&self) -> Result<(), BleHostError<C::Error>> {
1108 loop {
1109 let (handle, pdu) = self.rx.receive().await;
1110 let data = pdu.as_ref();
1111 if pdu.as_ref()[0] == ATT_HANDLE_VALUE_NTF {
1113 self.handle_notification_packet(&pdu.as_ref()[1..]).await?;
1114 } else {
1115 self.response_channel.send((handle, pdu)).await;
1116 }
1117 }
1118 }
1119
1120 fn response<'a>(data: &'a [u8]) -> Result<AttRsp<'a>, BleHostError<C::Error>> {
1121 let att = Att::decode(data)?;
1122 match att {
1123 Att::Server(AttServer::Response(rsp)) => Ok(rsp),
1124 _ => Err(Error::UnexpectedGattResponse.into()),
1125 }
1126 }
1127}