gatt_echo_server/
gatt_echo_server.rs1use bluer::{
4 adv::Advertisement,
5 gatt::{
6 local::{
7 characteristic_control, Application, Characteristic, CharacteristicControlEvent,
8 CharacteristicNotify, CharacteristicNotifyMethod, CharacteristicWrite, CharacteristicWriteMethod,
9 Service,
10 },
11 CharacteristicReader, CharacteristicWriter,
12 },
13};
14use futures::{future, pin_mut, StreamExt};
15use std::time::Duration;
16use tokio::{
17 io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader},
18 time::sleep,
19};
20
21include!("gatt_echo.inc");
22
23#[tokio::main]
24async fn main() -> bluer::Result<()> {
25 env_logger::init();
26 let session = bluer::Session::new().await?;
27 let adapter = session.default_adapter().await?;
28 adapter.set_powered(true).await?;
29
30 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
31 let le_advertisement = Advertisement {
32 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
33 discoverable: Some(true),
34 local_name: Some("gatt_echo_server".to_string()),
35 ..Default::default()
36 };
37 let adv_handle = adapter.advertise(le_advertisement).await?;
38
39 println!("Serving GATT echo service on Bluetooth adapter {}", adapter.name());
40 let (char_control, char_handle) = characteristic_control();
41 let app = Application {
42 services: vec![Service {
43 uuid: SERVICE_UUID,
44 primary: true,
45 characteristics: vec![Characteristic {
46 uuid: CHARACTERISTIC_UUID,
47 write: Some(CharacteristicWrite {
48 write_without_response: true,
49 method: CharacteristicWriteMethod::Io,
50 ..Default::default()
51 }),
52 notify: Some(CharacteristicNotify {
53 notify: true,
54 method: CharacteristicNotifyMethod::Io,
55 ..Default::default()
56 }),
57 control_handle: char_handle,
58 ..Default::default()
59 }],
60 ..Default::default()
61 }],
62 ..Default::default()
63 };
64 let app_handle = adapter.serve_gatt_application(app).await?;
65
66 println!("Echo service ready. Press enter to quit.");
67 let stdin = BufReader::new(tokio::io::stdin());
68 let mut lines = stdin.lines();
69
70 let mut read_buf = Vec::new();
71 let mut reader_opt: Option<CharacteristicReader> = None;
72 let mut writer_opt: Option<CharacteristicWriter> = None;
73 pin_mut!(char_control);
74
75 loop {
76 tokio::select! {
77 _ = lines.next_line() => break,
78 evt = char_control.next() => {
79 match evt {
80 Some(CharacteristicControlEvent::Write(req)) => {
81 println!("Accepting write request event with MTU {}", req.mtu());
82 read_buf = vec![0; req.mtu()];
83 reader_opt = Some(req.accept()?);
84 },
85 Some(CharacteristicControlEvent::Notify(notifier)) => {
86 println!("Accepting notify request event with MTU {}", notifier.mtu());
87 writer_opt = Some(notifier);
88 },
89 None => break,
90 }
91 },
92 read_res = async {
93 match &mut reader_opt {
94 Some(reader) if writer_opt.is_some() => reader.read(&mut read_buf).await,
95 _ => future::pending().await,
96 }
97 } => {
98 match read_res {
99 Ok(0) => {
100 println!("Read stream ended");
101 reader_opt = None;
102 }
103 Ok(n) => {
104 let value = read_buf[..n].to_vec();
105 println!("Echoing {} bytes: {:x?} ... {:x?}", value.len(), &value[0..4.min(value.len())], &value[value.len().saturating_sub(4) ..]);
106 if value.len() < 512 {
107 println!();
108 }
109 if let Err(err) = writer_opt.as_mut().unwrap().write_all(&value).await {
110 println!("Write failed: {}", &err);
111 writer_opt = None;
112 }
113 }
114 Err(err) => {
115 println!("Read stream error: {}", &err);
116 reader_opt = None;
117 }
118 }
119 }
120 }
121 }
122
123 println!("Removing service and advertisement");
124 drop(app_handle);
125 drop(adv_handle);
126 sleep(Duration::from_secs(1)).await;
127
128 Ok(())
129}