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;
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 = assemble(&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 = assemble(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 = assemble(connection, AttServer::Response(rsp))?;
567 Ok(Reply::new(connection.clone(), Some(pdu)))
568}
569
570pub(crate) fn assemble<'stack, P: PacketPool>(
571 conn: &Connection<'stack, P>,
572 att: AttServer<'_>,
573) -> Result<Pdu<P::Packet>, Error> {
574 let mut tx = P::allocate().ok_or(Error::OutOfMemory)?;
575 let mut w = WriteCursor::new(tx.as_mut());
576 let (mut header, mut data) = w.split(4)?;
577 data.write(Att::Server(att))?;
578
579 let mtu = conn.get_att_mtu();
580 data.truncate(mtu as usize);
581 header.write(data.len() as u16)?;
582 header.write(4_u16)?;
583 let len = header.len() + data.len();
584 Ok(Pdu::new(tx, len))
585}
586
587pub struct Reply<'stack, P: PacketPool> {
592 connection: Connection<'stack, P>,
593 pdu: Option<Pdu<P::Packet>>,
594}
595
596impl<'stack, P: PacketPool> Reply<'stack, P> {
597 fn new(connection: Connection<'stack, P>, pdu: Option<Pdu<P::Packet>>) -> Self {
598 Self { connection, pdu }
599 }
600
601 pub fn try_send(mut self) -> Result<(), Error> {
605 if let Some(pdu) = self.pdu.take() {
606 self.connection.try_send(pdu)
607 } else {
608 Ok(())
609 }
610 }
611
612 pub async fn send(mut self) {
614 if let Some(pdu) = self.pdu.take() {
615 self.connection.send(pdu).await
616 }
617 }
618}
619
620impl<P: PacketPool> Drop for Reply<'_, P> {
621 fn drop(&mut self) {
622 if let Some(pdu) = self.pdu.take() {
623 if self.connection.try_send(pdu).is_err() {
624 warn!("[gatt] error sending reply (outbound buffer full)");
625 }
626 }
627 }
628}
629
630pub struct NotificationListener<'lst, const MTU: usize> {
632 handle: u16,
633 listener: pubsub::DynSubscriber<'lst, Notification<MTU>>,
634}
635
636impl<'lst, const MTU: usize> NotificationListener<'lst, MTU> {
637 #[allow(clippy::should_implement_trait)]
638 pub async fn next(&mut self) -> Notification<MTU> {
640 loop {
641 if let WaitResult::Message(m) = self.listener.next_message().await {
642 if m.handle == self.handle {
643 return m;
644 }
645 }
646 }
647 }
648}
649
650const MAX_NOTIF: usize = config::GATT_CLIENT_NOTIFICATION_MAX_SUBSCRIBERS;
651const NOTIF_QSIZE: usize = config::GATT_CLIENT_NOTIFICATION_QUEUE_SIZE;
652
653pub struct GattClient<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> {
655 known_services: RefCell<Vec<ServiceHandle, MAX_SERVICES>>,
656 stack: &'reference Stack<'reference, T, P>,
657 connection: Connection<'reference, P>,
658 response_channel: Channel<NoopRawMutex, (ConnHandle, Pdu<P::Packet>), 1>,
659
660 notifications: PubSubChannel<NoopRawMutex, Notification<512>, NOTIF_QSIZE, MAX_NOTIF, 1>,
662}
663
664#[derive(Debug, PartialEq, Clone)]
666#[cfg_attr(feature = "defmt", derive(defmt::Format))]
667pub struct Notification<const MTU: usize> {
668 handle: u16,
669 data: [u8; MTU],
670 len: usize,
671}
672
673impl<const MTU: usize> AsRef<[u8]> for Notification<MTU> {
674 fn as_ref(&self) -> &[u8] {
675 &self.data[..self.len]
676 }
677}
678
679#[cfg_attr(feature = "defmt", derive(defmt::Format))]
681#[derive(Debug, PartialEq, Clone)]
682pub struct ServiceHandle {
683 start: u16,
684 end: u16,
685 uuid: Uuid,
686}
687
688pub(crate) struct Response<P> {
689 pdu: Pdu<P>,
690 handle: ConnHandle,
691}
692
693pub(crate) trait Client<'d, E, P: PacketPool> {
695 fn request(&self, req: AttReq<'_>) -> impl Future<Output = Result<Response<P::Packet>, BleHostError<E>>>;
697 fn command(&self, cmd: AttCmd<'_>) -> impl Future<Output = Result<(), BleHostError<E>>>;
698}
699
700impl<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> Client<'reference, T::Error, P>
701 for GattClient<'reference, T, P, MAX_SERVICES>
702{
703 async fn request(&self, req: AttReq<'_>) -> Result<Response<P::Packet>, BleHostError<T::Error>> {
704 let data = Att::Client(AttClient::Request(req));
705
706 self.send_att_data(data).await?;
707
708 let (h, pdu) = self.response_channel.receive().await;
709
710 assert_eq!(h, self.connection.handle());
711 Ok(Response { handle: h, pdu })
712 }
713
714 async fn command(&self, cmd: AttCmd<'_>) -> Result<(), BleHostError<T::Error>> {
715 let data = Att::Client(AttClient::Command(cmd));
716
717 self.send_att_data(data).await?;
718
719 Ok(())
720 }
721}
722
723impl<'reference, T: Controller, P: PacketPool, const MAX_SERVICES: usize> GattClient<'reference, T, P, MAX_SERVICES> {
724 async fn send_att_data(&self, data: Att<'_>) -> Result<(), BleHostError<T::Error>> {
725 let header = L2capHeader {
726 channel: crate::types::l2cap::L2CAP_CID_ATT,
727 length: data.size() as u16,
728 };
729
730 let mut buf = P::allocate().ok_or(Error::OutOfMemory)?;
731 let mut w = WriteCursor::new(buf.as_mut());
732 w.write_hci(&header)?;
733 w.write(data)?;
734 let len = w.len();
735
736 self.connection.send(Pdu::new(buf, len)).await;
737 Ok(())
738 }
739}
740
741impl<'reference, C: Controller, P: PacketPool, const MAX_SERVICES: usize> GattClient<'reference, C, P, MAX_SERVICES> {
742 pub async fn new(
744 stack: &'reference Stack<'reference, C, P>,
745 connection: &Connection<'reference, P>,
746 ) -> Result<GattClient<'reference, C, P, MAX_SERVICES>, BleHostError<C::Error>> {
747 let l2cap = L2capHeader { channel: 4, length: 3 };
748 let mut buf = P::allocate().ok_or(Error::OutOfMemory)?;
749 let mut w = WriteCursor::new(buf.as_mut());
750 w.write_hci(&l2cap)?;
751 w.write(att::Att::Client(att::AttClient::Request(att::AttReq::ExchangeMtu {
752 mtu: P::MTU as u16 - 4,
753 })))?;
754
755 let len = w.len();
756 connection.send(Pdu::new(buf, len)).await;
757 Ok(Self {
758 known_services: RefCell::new(heapless::Vec::new()),
759 stack,
760 connection: connection.clone(),
761
762 response_channel: Channel::new(),
763
764 notifications: PubSubChannel::new(),
765 })
766 }
767
768 pub async fn services_by_uuid(
770 &self,
771 uuid: &Uuid,
772 ) -> Result<Vec<ServiceHandle, MAX_SERVICES>, BleHostError<C::Error>> {
773 let mut start: u16 = 0x0001;
774 let mut result = Vec::new();
775
776 loop {
777 let data = att::AttReq::FindByTypeValue {
778 start_handle: start,
779 end_handle: 0xffff,
780 att_type: PRIMARY_SERVICE.into(),
781 att_value: uuid.as_raw(),
782 };
783
784 let response = self.request(data).await?;
785 let res = Self::response(response.pdu.as_ref())?;
786 match res {
787 AttRsp::Error { request, handle, code } => {
788 if code == att::AttErrorCode::ATTRIBUTE_NOT_FOUND {
789 break;
790 }
791 return Err(Error::Att(code).into());
792 }
793 AttRsp::FindByTypeValue { mut it } => {
794 let mut end: u16 = 0;
795 while let Some(res) = it.next() {
796 let (handle, e) = res?;
797 end = e;
798 let svc = ServiceHandle {
799 start: handle,
800 end,
801 uuid: uuid.clone(),
802 };
803 result.push(svc.clone()).map_err(|_| Error::InsufficientSpace)?;
804 self.known_services
805 .borrow_mut()
806 .push(svc)
807 .map_err(|_| Error::InsufficientSpace)?;
808 }
809 if end == 0xFFFF {
810 break;
811 }
812 start = end + 1;
813 }
814 res => {
815 trace!("[gatt client] response: {:?}", res);
816 return Err(Error::UnexpectedGattResponse.into());
817 }
818 }
819 }
820
821 Ok(result)
822 }
823
824 pub async fn characteristic_by_uuid<T: AsGatt>(
826 &self,
827 service: &ServiceHandle,
828 uuid: &Uuid,
829 ) -> Result<Characteristic<T>, BleHostError<C::Error>> {
830 let mut start: u16 = service.start;
831 let mut found_indicate_or_notify_uuid = Option::None;
832
833 loop {
834 let data = att::AttReq::ReadByType {
835 start,
836 end: service.end,
837 attribute_type: CHARACTERISTIC.into(),
838 };
839 let response = self.request(data).await?;
840
841 match Self::response(response.pdu.as_ref())? {
842 AttRsp::ReadByType { mut it } => {
843 while let Some(Ok((handle, item))) = it.next() {
844 let expected_items_len = 5;
845 let item_len = item.len();
846
847 if item_len < expected_items_len {
848 return Err(Error::MalformedCharacteristicDeclaration {
849 expected: expected_items_len,
850 actual: item_len,
851 }
852 .into());
853 }
854 if let AttributeData::Declaration {
855 props,
856 handle,
857 uuid: decl_uuid,
858 } = AttributeData::decode_declaration(item)?
859 {
860 if let Some(start_handle) = found_indicate_or_notify_uuid {
861 return Ok(Characteristic {
862 handle: start_handle,
863 cccd_handle: Some(self.get_characteristic_cccd(start_handle, handle).await?),
864 phantom: PhantomData,
865 });
866 }
867
868 if *uuid == decl_uuid {
869 if !props.any(&[CharacteristicProp::Indicate, CharacteristicProp::Notify]) {
872 return Ok(Characteristic {
873 handle,
874 cccd_handle: None,
875 phantom: PhantomData,
876 });
877 }
878 found_indicate_or_notify_uuid = Some(handle);
879 }
880
881 if handle == 0xFFFF {
882 return Err(Error::NotFound.into());
883 }
884 start = handle + 1;
885 } else {
886 return Err(Error::InvalidCharacteristicDeclarationData.into());
887 }
888 }
889 }
890 AttRsp::Error { request, handle, code } => match code {
891 att::AttErrorCode::ATTRIBUTE_NOT_FOUND => match found_indicate_or_notify_uuid {
892 Some(handle) => {
893 return Ok(Characteristic {
894 handle,
895 cccd_handle: Some(self.get_characteristic_cccd(handle, service.end).await?),
896 phantom: PhantomData,
897 });
898 }
899 None => return Err(Error::NotFound.into()),
900 },
901 _ => return Err(Error::Att(code).into()),
902 },
903 _ => return Err(Error::UnexpectedGattResponse.into()),
904 }
905 }
906 }
907
908 async fn get_characteristic_cccd(
909 &self,
910 char_start_handle: u16,
911 char_end_handle: u16,
912 ) -> Result<u16, BleHostError<C::Error>> {
913 let mut start_handle = char_start_handle;
914
915 while start_handle <= char_end_handle {
916 let data = att::AttReq::FindInformation {
917 start_handle,
918 end_handle: char_end_handle,
919 };
920
921 let response = self.request(data).await?;
922
923 match Self::response(response.pdu.as_ref())? {
924 AttRsp::FindInformation { mut it } => {
925 while let Some(Ok((handle, uuid))) = it.next() {
926 if uuid == CLIENT_CHARACTERISTIC_CONFIGURATION.into() {
927 return Ok(handle);
928 }
929 start_handle = handle + 1;
930 }
931 }
932 AttRsp::Error { request, handle, code } => return Err(Error::Att(code).into()),
933 _ => return Err(Error::UnexpectedGattResponse.into()),
934 }
935 }
936 Err(Error::NotFound.into())
937 }
938
939 pub async fn read_characteristic<T: AsGatt>(
943 &self,
944 characteristic: &Characteristic<T>,
945 dest: &mut [u8],
946 ) -> Result<usize, BleHostError<C::Error>> {
947 let response = self
948 .request(att::AttReq::Read {
949 handle: characteristic.handle,
950 })
951 .await?;
952
953 match Self::response(response.pdu.as_ref())? {
954 AttRsp::Read { data } => {
955 let to_copy = data.len().min(dest.len());
956 dest[..to_copy].copy_from_slice(&data[..to_copy]);
957 Ok(to_copy)
958 }
959 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
960 _ => Err(Error::UnexpectedGattResponse.into()),
961 }
962 }
963
964 pub async fn read_characteristic_long<T: AsGatt>(
969 &self,
970 characteristic: &Characteristic<T>,
971 dest: &mut [u8],
972 ) -> Result<usize, BleHostError<C::Error>> {
973 let first_read_len = self.read_characteristic(characteristic, dest).await?;
975 let att_mtu = self.connection.att_mtu() as usize;
976
977 if first_read_len != att_mtu - 1 {
978 return Ok(first_read_len);
980 }
981
982 let mut offset = first_read_len;
984 loop {
985 let response = self
986 .request(att::AttReq::ReadBlob {
987 handle: characteristic.handle,
988 offset: offset as u16,
989 })
990 .await?;
991
992 match Self::response(response.pdu.as_ref())? {
993 AttRsp::ReadBlob { data } => {
994 debug!("[read_characteristic_long] Blob read returned {} bytes", data.len());
995 if data.is_empty() {
996 break; }
998
999 let blob_read_len = data.len();
1000
1001 let len_to_copy = blob_read_len.min(dest.len() - offset);
1004 dest[offset..offset + len_to_copy].copy_from_slice(&data[..len_to_copy]);
1005 offset += len_to_copy;
1006
1007 if blob_read_len < att_mtu - 1 || len_to_copy < blob_read_len {
1010 break;
1011 }
1012 }
1013 AttRsp::Error { code, .. } if code == att::AttErrorCode::INVALID_OFFSET => {
1014 trace!("[read_characteristic_long] Got INVALID_OFFSET, no more data");
1015 break; }
1017 AttRsp::Error { code, .. } if code == att::AttErrorCode::ATTRIBUTE_NOT_LONG => {
1018 trace!("[read_characteristic_long] read_handle_long] Attribute not long, no blob reads needed");
1019 break; }
1021 AttRsp::Error { code, .. } => {
1022 trace!("[read_characteristic] Got error: {:?}", code);
1023 return Err(Error::Att(code).into());
1024 }
1025 _ => return Err(Error::UnexpectedGattResponse.into()),
1026 }
1027 }
1028 Ok(offset)
1029 }
1030
1031 pub async fn read_characteristic_by_uuid(
1035 &self,
1036 service: &ServiceHandle,
1037 uuid: &Uuid,
1038 dest: &mut [u8],
1039 ) -> Result<usize, BleHostError<C::Error>> {
1040 let data = att::AttReq::ReadByType {
1041 start: service.start,
1042 end: service.end,
1043 attribute_type: uuid.clone(),
1044 };
1045
1046 let response = self.request(data).await?;
1047
1048 match Self::response(response.pdu.as_ref())? {
1049 AttRsp::ReadByType { mut it } => {
1050 let mut to_copy = 0;
1051 if let Some(item) = it.next() {
1052 let (_handle, data) = item?;
1053 to_copy = data.len().min(dest.len());
1054 dest[..to_copy].copy_from_slice(&data[..to_copy]);
1055 }
1056 Ok(to_copy)
1057 }
1058 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1059 _ => Err(Error::UnexpectedGattResponse.into()),
1060 }
1061 }
1062
1063 pub async fn write_characteristic<T: FromGatt>(
1065 &self,
1066 handle: &Characteristic<T>,
1067 buf: &[u8],
1068 ) -> Result<(), BleHostError<C::Error>> {
1069 let data = att::AttReq::Write {
1070 handle: handle.handle,
1071 data: buf,
1072 };
1073
1074 let response = self.request(data).await?;
1075 match Self::response(response.pdu.as_ref())? {
1076 AttRsp::Write => Ok(()),
1077 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1078 _ => Err(Error::UnexpectedGattResponse.into()),
1079 }
1080 }
1081
1082 pub async fn write_characteristic_without_response<T: FromGatt>(
1084 &self,
1085 handle: &Characteristic<T>,
1086 buf: &[u8],
1087 ) -> Result<(), BleHostError<C::Error>> {
1088 let data = att::AttCmd::Write {
1089 handle: handle.handle,
1090 data: buf,
1091 };
1092
1093 self.command(data).await?;
1094
1095 Ok(())
1096 }
1097
1098 pub async fn subscribe<T: AsGatt>(
1102 &self,
1103 characteristic: &Characteristic<T>,
1104 indication: bool,
1105 ) -> Result<NotificationListener<'_, 512>, BleHostError<C::Error>> {
1106 let properties = u16::to_le_bytes(if indication { 0x02 } else { 0x01 });
1107
1108 let data = att::AttReq::Write {
1109 handle: characteristic.cccd_handle.ok_or(Error::NotSupported)?,
1110 data: &properties,
1111 };
1112
1113 let response = self.request(data).await?;
1115
1116 match Self::response(response.pdu.as_ref())? {
1117 AttRsp::Write => match self.notifications.dyn_subscriber() {
1118 Ok(listener) => Ok(NotificationListener {
1119 listener,
1120 handle: characteristic.handle,
1121 }),
1122 Err(embassy_sync::pubsub::Error::MaximumSubscribersReached) => {
1123 Err(Error::GattSubscriberLimitReached.into())
1124 }
1125 Err(_) => Err(Error::Other.into()),
1126 },
1127 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1128 _ => Err(Error::UnexpectedGattResponse.into()),
1129 }
1130 }
1131
1132 pub async fn unsubscribe<T: AsGatt>(
1134 &self,
1135 characteristic: &Characteristic<T>,
1136 ) -> Result<(), BleHostError<C::Error>> {
1137 let properties = u16::to_le_bytes(0);
1138 let data = att::AttReq::Write {
1139 handle: characteristic.cccd_handle.ok_or(Error::NotSupported)?,
1140 data: &[0, 0],
1141 };
1142
1143 let response = self.request(data).await?;
1145
1146 match Self::response(response.pdu.as_ref())? {
1147 AttRsp::Write => Ok(()),
1148 AttRsp::Error { request, handle, code } => Err(Error::Att(code).into()),
1149 _ => Err(Error::UnexpectedGattResponse.into()),
1150 }
1151 }
1152
1153 async fn handle_notification_packet(&self, data: &[u8]) -> Result<(), BleHostError<C::Error>> {
1155 let mut r = ReadCursor::new(data);
1156 let value_handle: u16 = r.read()?;
1157 let value_attr = r.remaining();
1158
1159 let handle = value_handle;
1160
1161 let mut data = [0u8; 512];
1163 let to_copy = data.len().min(value_attr.len());
1164 data[..to_copy].copy_from_slice(&value_attr[..to_copy]);
1165 let n = Notification {
1166 handle,
1167 data,
1168 len: to_copy,
1169 };
1170 self.notifications.immediate_publisher().publish_immediate(n);
1171 Ok(())
1172 }
1173
1174 pub async fn task(&self) -> Result<(), BleHostError<C::Error>> {
1176 loop {
1177 let handle = self.connection.handle();
1178 let pdu = self.connection.next_gatt_client().await;
1179 let data = pdu.as_ref();
1180 if pdu.as_ref()[0] == ATT_HANDLE_VALUE_NTF {
1182 self.handle_notification_packet(&pdu.as_ref()[1..]).await?;
1183 } else {
1184 self.response_channel.send((handle, pdu)).await;
1185 }
1186 }
1187 }
1188
1189 fn response<'a>(data: &'a [u8]) -> Result<AttRsp<'a>, BleHostError<C::Error>> {
1190 let att = Att::decode(data)?;
1191 match att {
1192 Att::Server(AttServer::Response(rsp)) => Ok(rsp),
1193 _ => Err(Error::UnexpectedGattResponse.into()),
1194 }
1195 }
1196}