Function bluer::gatt::local::characteristic_control
source · pub fn characteristic_control(
) -> (CharacteristicControl, CharacteristicControlHandle)
Available on crate feature
bluetoothd
only.Expand description
Creates a CharacteristicControl and its associated CharacteristicControlHandle.
Keep the CharacteristicControl and store the CharacteristicControlHandle in Characteristic::control_handle.
Examples found in repository?
examples/gatt_echo_server.rs (line 40)
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
async fn main() -> bluer::Result<()> {
env_logger::init();
let session = bluer::Session::new().await?;
let adapter = session.default_adapter().await?;
adapter.set_powered(true).await?;
println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
let le_advertisement = Advertisement {
service_uuids: vec![SERVICE_UUID].into_iter().collect(),
discoverable: Some(true),
local_name: Some("gatt_echo_server".to_string()),
..Default::default()
};
let adv_handle = adapter.advertise(le_advertisement).await?;
println!("Serving GATT echo service on Bluetooth adapter {}", adapter.name());
let (char_control, char_handle) = characteristic_control();
let app = Application {
services: vec![Service {
uuid: SERVICE_UUID,
primary: true,
characteristics: vec![Characteristic {
uuid: CHARACTERISTIC_UUID,
write: Some(CharacteristicWrite {
write_without_response: true,
method: CharacteristicWriteMethod::Io,
..Default::default()
}),
notify: Some(CharacteristicNotify {
notify: true,
method: CharacteristicNotifyMethod::Io,
..Default::default()
}),
control_handle: char_handle,
..Default::default()
}],
..Default::default()
}],
..Default::default()
};
let app_handle = adapter.serve_gatt_application(app).await?;
println!("Echo service ready. Press enter to quit.");
let stdin = BufReader::new(tokio::io::stdin());
let mut lines = stdin.lines();
let mut read_buf = Vec::new();
let mut reader_opt: Option<CharacteristicReader> = None;
let mut writer_opt: Option<CharacteristicWriter> = None;
pin_mut!(char_control);
loop {
tokio::select! {
_ = lines.next_line() => break,
evt = char_control.next() => {
match evt {
Some(CharacteristicControlEvent::Write(req)) => {
println!("Accepting write request event with MTU {}", req.mtu());
read_buf = vec![0; req.mtu()];
reader_opt = Some(req.accept()?);
},
Some(CharacteristicControlEvent::Notify(notifier)) => {
println!("Accepting notify request event with MTU {}", notifier.mtu());
writer_opt = Some(notifier);
},
None => break,
}
},
read_res = async {
match &mut reader_opt {
Some(reader) if writer_opt.is_some() => reader.read(&mut read_buf).await,
_ => future::pending().await,
}
} => {
match read_res {
Ok(0) => {
println!("Read stream ended");
reader_opt = None;
}
Ok(n) => {
let value = read_buf[..n].to_vec();
println!("Echoing {} bytes: {:x?} ... {:x?}", value.len(), &value[0..4.min(value.len())], &value[value.len().saturating_sub(4) ..]);
if value.len() < 512 {
println!();
}
if let Err(err) = writer_opt.as_mut().unwrap().write_all(&value).await {
println!("Write failed: {}", &err);
writer_opt = None;
}
}
Err(err) => {
println!("Read stream error: {}", &err);
reader_opt = None;
}
}
}
}
}
println!("Removing service and advertisement");
drop(app_handle);
drop(adv_handle);
sleep(Duration::from_secs(1)).await;
Ok(())
}
More examples
examples/gatt_server_io.rs (line 44)
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
async fn main() -> bluer::Result<()> {
env_logger::init();
let session = bluer::Session::new().await?;
let adapter = session.default_adapter().await?;
adapter.set_powered(true).await?;
println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
let mut manufacturer_data = BTreeMap::new();
manufacturer_data.insert(MANUFACTURER_ID, vec![0x21, 0x22, 0x23, 0x24]);
let le_advertisement = Advertisement {
service_uuids: vec![SERVICE_UUID].into_iter().collect(),
manufacturer_data,
discoverable: Some(true),
local_name: Some("gatt_server".to_string()),
..Default::default()
};
let adv_handle = adapter.advertise(le_advertisement).await?;
println!("Serving GATT service on Bluetooth adapter {}", adapter.name());
let (service_control, service_handle) = service_control();
let (char_control, char_handle) = characteristic_control();
let app = Application {
services: vec![Service {
uuid: SERVICE_UUID,
primary: true,
characteristics: vec![Characteristic {
uuid: CHARACTERISTIC_UUID,
write: Some(CharacteristicWrite {
write: true,
write_without_response: true,
method: CharacteristicWriteMethod::Io,
..Default::default()
}),
notify: Some(CharacteristicNotify {
notify: true,
method: CharacteristicNotifyMethod::Io,
..Default::default()
}),
control_handle: char_handle,
..Default::default()
}],
control_handle: service_handle,
..Default::default()
}],
..Default::default()
};
let app_handle = adapter.serve_gatt_application(app).await?;
println!("Service handle is 0x{:x}", service_control.handle()?);
println!("Characteristic handle is 0x{:x}", char_control.handle()?);
println!("Service ready. Press enter to quit.");
let stdin = BufReader::new(tokio::io::stdin());
let mut lines = stdin.lines();
let mut value: Vec<u8> = vec![0x10, 0x01, 0x01, 0x10];
let mut read_buf = Vec::new();
let mut reader_opt: Option<CharacteristicReader> = None;
let mut writer_opt: Option<CharacteristicWriter> = None;
let mut interval = interval(Duration::from_secs(1));
pin_mut!(char_control);
loop {
tokio::select! {
_ = lines.next_line() => break,
evt = char_control.next() => {
match evt {
Some(CharacteristicControlEvent::Write(req)) => {
println!("Accepting write event with MTU {} from {}", req.mtu(), req.device_address());
read_buf = vec![0; req.mtu()];
reader_opt = Some(req.accept()?);
},
Some(CharacteristicControlEvent::Notify(notifier)) => {
println!("Accepting notify request event with MTU {} from {}", notifier.mtu(), notifier.device_address());
writer_opt = Some(notifier);
},
None => break,
}
}
_ = interval.tick() => {
println!("Decrementing each element by one");
for v in &mut *value {
*v = v.saturating_sub(1);
}
println!("Value is {:x?}", &value);
if let Some(writer) = writer_opt.as_mut() {
println!("Notifying with value {:x?}", &value);
if let Err(err) = writer.write(&value).await {
println!("Notification stream error: {}", &err);
writer_opt = None;
}
}
}
read_res = async {
match &mut reader_opt {
Some(reader) => reader.read(&mut read_buf).await,
None => future::pending().await,
}
} => {
match read_res {
Ok(0) => {
println!("Write stream ended");
reader_opt = None;
}
Ok(n) => {
value = read_buf[0..n].to_vec();
println!("Write request with {} bytes: {:x?}", n, &value);
}
Err(err) => {
println!("Write stream error: {}", &err);
reader_opt = None;
}
}
}
}
}
println!("Removing service and advertisement");
drop(app_handle);
drop(adv_handle);
sleep(Duration::from_secs(1)).await;
Ok(())
}