gatt_echo_server/
gatt_echo_server.rs

1//! Serves a Bluetooth GATT echo server.
2
3use 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}