pub struct Adapter { /* private fields */ }
bluetoothd
only.Expand description
Interface to a Bluetooth adapter.
Implementations§
Source§impl Adapter
impl Adapter
Sourcepub fn name(&self) -> &str
pub fn name(&self) -> &str
The Bluetooth adapter name.
For example hci0
.
Examples found in repository?
11async fn main() -> bluer::Result<()> {
12 env_logger::init();
13 let session = bluer::Session::new().await?;
14 let adapter = session.default_adapter().await?;
15 adapter.set_powered(true).await?;
16
17 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
18 let le_advertisement = Advertisement {
19 advertisement_type: bluer::adv::Type::Peripheral,
20 service_uuids: vec!["123e4567-e89b-12d3-a456-426614174000".parse().unwrap()].into_iter().collect(),
21 discoverable: Some(true),
22 local_name: Some("le_advertise".to_string()),
23 ..Default::default()
24 };
25 println!("{:?}", &le_advertisement);
26 let handle = adapter.advertise(le_advertisement).await?;
27
28 println!("Press enter to quit");
29 let stdin = BufReader::new(tokio::io::stdin());
30 let mut lines = stdin.lines();
31 let _ = lines.next_line().await;
32
33 println!("Removing advertisement");
34 drop(handle);
35 sleep(Duration::from_secs(1)).await;
36
37 Ok(())
38}
More examples
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20
21 let adapter_name = std::env::args().nth(1);
22 let data_type: u8 = match std::env::args().nth(2) {
23 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse AD type"),
24 None => 0xff,
25 };
26 let start_position: u8 = match std::env::args().nth(3) {
27 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse or-pattern start position"),
28 None => 0x00,
29 };
30 let filter_string: Vec<String> = std::env::args().skip(4).collect();
31 let content: Vec<u8> = if !filter_string.is_empty() {
32 filter_string.iter().map(|s| parse_u8_maybe_hex(s).expect("Failed to parse or-pattern data")).collect()
33 } else {
34 vec![0xff, 0xff]
35 };
36
37 if content.is_empty() {
38 panic!("No filter bytes provided");
39 }
40
41 let pattern = Pattern { data_type, start_position, content };
42
43 let session = bluer::Session::new().await?;
44
45 let adapter = match adapter_name {
46 Some(name) => session.adapter(&name)?,
47 None => session.default_adapter().await?,
48 };
49 println!("Running le_passive_scan on adapter {} with or-pattern {:?}", adapter.name(), pattern);
50
51 adapter.set_powered(true).await?;
52
53 let mm = adapter.monitor().await?;
54 let mut monitor_handle = mm
55 .register(Monitor {
56 monitor_type: bluer::monitor::Type::OrPatterns,
57 rssi_low_threshold: None,
58 rssi_high_threshold: None,
59 rssi_low_timeout: None,
60 rssi_high_timeout: None,
61 rssi_sampling_period: Some(RssiSamplingPeriod::First),
62 patterns: Some(vec![pattern]),
63 ..Default::default()
64 })
65 .await?;
66
67 while let Some(mevt) = &monitor_handle.next().await {
68 if let MonitorEvent::DeviceFound(devid) = mevt {
69 println!("Discovered device {:?}", devid);
70 let dev = adapter.device(devid.device)?;
71 tokio::spawn(async move {
72 let mut events = dev.events().await.unwrap();
73 while let Some(ev) = events.next().await {
74 println!("On device {:?}, received event {:?}", dev, ev);
75 }
76 });
77 }
78 }
79
80 Ok(())
81}
35async fn main() -> bluer::Result<()> {
36 let with_changes = env::args().any(|arg| arg == "--changes");
37 let all_properties = env::args().any(|arg| arg == "--all-properties");
38 let le_only = env::args().any(|arg| arg == "--le");
39 let br_edr_only = env::args().any(|arg| arg == "--bredr");
40 let filter_addr: HashSet<_> = env::args().filter_map(|arg| arg.parse::<Address>().ok()).collect();
41
42 env_logger::init();
43 let session = bluer::Session::new().await?;
44 let adapter = session.default_adapter().await?;
45 println!("Discovering devices using Bluetooth adapter {}\n", adapter.name());
46 adapter.set_powered(true).await?;
47
48 let filter = DiscoveryFilter {
49 transport: if le_only {
50 DiscoveryTransport::Le
51 } else if br_edr_only {
52 DiscoveryTransport::BrEdr
53 } else {
54 DiscoveryTransport::Auto
55 },
56 ..Default::default()
57 };
58 adapter.set_discovery_filter(filter).await?;
59 println!("Using discovery filter:\n{:#?}\n\n", adapter.discovery_filter().await);
60
61 let device_events = adapter.discover_devices().await?;
62 pin_mut!(device_events);
63
64 let mut all_change_events = SelectAll::new();
65
66 loop {
67 tokio::select! {
68 Some(device_event) = device_events.next() => {
69 match device_event {
70 AdapterEvent::DeviceAdded(addr) => {
71 if !filter_addr.is_empty() && !filter_addr.contains(&addr) {
72 continue;
73 }
74
75 println!("Device added: {addr}");
76 let res = if all_properties {
77 query_all_device_properties(&adapter, addr).await
78 } else {
79 query_device(&adapter, addr).await
80 };
81 if let Err(err) = res {
82 println!(" Error: {}", &err);
83 }
84
85 if with_changes {
86 let device = adapter.device(addr)?;
87 let change_events = device.events().await?.map(move |evt| (addr, evt));
88 all_change_events.push(change_events);
89 }
90 }
91 AdapterEvent::DeviceRemoved(addr) => {
92 println!("Device removed: {addr}");
93 }
94 _ => (),
95 }
96 println!();
97 }
98 Some((addr, DeviceEvent::PropertyChanged(property))) = all_change_events.next() => {
99 println!("Device changed: {addr}");
100 println!(" {property:?}");
101 }
102 else => break
103 }
104 }
105
106 Ok(())
107}
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20 let session = bluer::Session::new().await?;
21 let adapter = session.default_adapter().await?;
22 adapter.set_powered(true).await?;
23 let adapter_addr = adapter.address().await?;
24 let adapter_addr_type = adapter.address_type().await?;
25
26 // Advertising is necessary for device to be connectable.
27 println!(
28 "Advertising on Bluetooth adapter {} with {} address {}",
29 adapter.name(),
30 &adapter_addr_type,
31 &adapter_addr
32 );
33 let le_advertisement = Advertisement {
34 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
35 discoverable: Some(true),
36 local_name: Some("l2cap_server".to_string()),
37 ..Default::default()
38 };
39 let adv_handle = adapter.advertise(le_advertisement).await?;
40
41 let local_sa = SocketAddr::new(adapter_addr, adapter_addr_type, PSM);
42 let listener = StreamListener::bind(local_sa).await?;
43
44 println!("Listening on PSM {}. Press enter to quit.", listener.as_ref().local_addr()?.psm);
45 let stdin = BufReader::new(tokio::io::stdin());
46 let mut lines = stdin.lines();
47
48 loop {
49 println!("\nWaiting for connection...");
50
51 let (mut stream, sa) = tokio::select! {
52 l = listener.accept() => {
53 match l {
54 Ok(v) => v,
55 Err(err) => {
56 println!("Accepting connection failed: {}", &err);
57 continue;
58 }}
59 },
60 _ = lines.next_line() => break,
61 };
62 let recv_mtu = stream.as_ref().recv_mtu()?;
63
64 println!("Accepted connection from {:?} with receive MTU {} bytes", &sa, &recv_mtu);
65
66 println!("Sending hello");
67 if let Err(err) = stream.write_all(HELLO_MSG).await {
68 println!("Write failed: {}", &err);
69 continue;
70 }
71
72 let mut n = 0;
73 loop {
74 n += 1;
75
76 // Vary buffer size between MTU and smaller value to test
77 // partial reads.
78 let buf_size = if n % 5 == 0 { recv_mtu - 70 } else { recv_mtu };
79 let mut buf = vec![0; buf_size as _];
80
81 let n = match stream.read(&mut buf).await {
82 Ok(0) => {
83 println!("Stream ended");
84 break;
85 }
86 Ok(n) => n,
87 Err(err) => {
88 println!("Read failed: {}", &err);
89 continue;
90 }
91 };
92 let buf = &buf[..n];
93
94 println!("Echoing {} bytes", buf.len());
95 if let Err(err) = stream.write_all(buf).await {
96 println!("Write failed: {}", &err);
97 continue;
98 }
99 }
100 }
101
102 println!("Removing advertisement");
103 drop(adv_handle);
104 sleep(Duration::from_secs(1)).await;
105
106 Ok(())
107}
Sourcepub async fn device_addresses(&self) -> Result<Vec<Address>>
pub async fn device_addresses(&self) -> Result<Vec<Address>>
Bluetooth addresses of discovered Bluetooth devices.
Sourcepub async fn monitor(&self) -> Result<MonitorManager>
pub async fn monitor(&self) -> Result<MonitorManager>
Starts monitoring of advertisements.
Once a monitoring job is activated by BlueZ, the client can expect to get notified on the targeted advertisements no matter if there is an ongoing discovery session.
Use the returned MonitorManager
to target advertisements
and drop it to stop monitoring advertisements.
Examples found in repository?
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20
21 let adapter_name = std::env::args().nth(1);
22 let data_type: u8 = match std::env::args().nth(2) {
23 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse AD type"),
24 None => 0xff,
25 };
26 let start_position: u8 = match std::env::args().nth(3) {
27 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse or-pattern start position"),
28 None => 0x00,
29 };
30 let filter_string: Vec<String> = std::env::args().skip(4).collect();
31 let content: Vec<u8> = if !filter_string.is_empty() {
32 filter_string.iter().map(|s| parse_u8_maybe_hex(s).expect("Failed to parse or-pattern data")).collect()
33 } else {
34 vec![0xff, 0xff]
35 };
36
37 if content.is_empty() {
38 panic!("No filter bytes provided");
39 }
40
41 let pattern = Pattern { data_type, start_position, content };
42
43 let session = bluer::Session::new().await?;
44
45 let adapter = match adapter_name {
46 Some(name) => session.adapter(&name)?,
47 None => session.default_adapter().await?,
48 };
49 println!("Running le_passive_scan on adapter {} with or-pattern {:?}", adapter.name(), pattern);
50
51 adapter.set_powered(true).await?;
52
53 let mm = adapter.monitor().await?;
54 let mut monitor_handle = mm
55 .register(Monitor {
56 monitor_type: bluer::monitor::Type::OrPatterns,
57 rssi_low_threshold: None,
58 rssi_high_threshold: None,
59 rssi_low_timeout: None,
60 rssi_high_timeout: None,
61 rssi_sampling_period: Some(RssiSamplingPeriod::First),
62 patterns: Some(vec![pattern]),
63 ..Default::default()
64 })
65 .await?;
66
67 while let Some(mevt) = &monitor_handle.next().await {
68 if let MonitorEvent::DeviceFound(devid) = mevt {
69 println!("Discovered device {:?}", devid);
70 let dev = adapter.device(devid.device)?;
71 tokio::spawn(async move {
72 let mut events = dev.events().await.unwrap();
73 while let Some(ev) = events.next().await {
74 println!("On device {:?}, received event {:?}", dev, ev);
75 }
76 });
77 }
78 }
79
80 Ok(())
81}
Sourcepub fn device(&self, address: Address) -> Result<Device>
pub fn device(&self, address: Address) -> Result<Device>
Get interface to Bluetooth device of specified address.
Examples found in repository?
7async fn query_device(adapter: &Adapter, addr: Address) -> bluer::Result<()> {
8 let device = adapter.device(addr)?;
9 println!(" Address type: {}", device.address_type().await?);
10 println!(" Name: {:?}", device.name().await?);
11 println!(" Icon: {:?}", device.icon().await?);
12 println!(" Class: {:?}", device.class().await?);
13 println!(" UUIDs: {:?}", device.uuids().await?.unwrap_or_default());
14 println!(" Paired: {:?}", device.is_paired().await?);
15 println!(" Connected: {:?}", device.is_connected().await?);
16 println!(" Trusted: {:?}", device.is_trusted().await?);
17 println!(" Modalias: {:?}", device.modalias().await?);
18 println!(" RSSI: {:?}", device.rssi().await?);
19 println!(" TX power: {:?}", device.tx_power().await?);
20 println!(" Manufacturer data: {:?}", device.manufacturer_data().await?);
21 println!(" Service data: {:?}", device.service_data().await?);
22 Ok(())
23}
24
25async fn query_all_device_properties(adapter: &Adapter, addr: Address) -> bluer::Result<()> {
26 let device = adapter.device(addr)?;
27 let props = device.all_properties().await?;
28 for prop in props {
29 println!(" {:?}", &prop);
30 }
31 Ok(())
32}
33
34#[tokio::main(flavor = "current_thread")]
35async fn main() -> bluer::Result<()> {
36 let with_changes = env::args().any(|arg| arg == "--changes");
37 let all_properties = env::args().any(|arg| arg == "--all-properties");
38 let le_only = env::args().any(|arg| arg == "--le");
39 let br_edr_only = env::args().any(|arg| arg == "--bredr");
40 let filter_addr: HashSet<_> = env::args().filter_map(|arg| arg.parse::<Address>().ok()).collect();
41
42 env_logger::init();
43 let session = bluer::Session::new().await?;
44 let adapter = session.default_adapter().await?;
45 println!("Discovering devices using Bluetooth adapter {}\n", adapter.name());
46 adapter.set_powered(true).await?;
47
48 let filter = DiscoveryFilter {
49 transport: if le_only {
50 DiscoveryTransport::Le
51 } else if br_edr_only {
52 DiscoveryTransport::BrEdr
53 } else {
54 DiscoveryTransport::Auto
55 },
56 ..Default::default()
57 };
58 adapter.set_discovery_filter(filter).await?;
59 println!("Using discovery filter:\n{:#?}\n\n", adapter.discovery_filter().await);
60
61 let device_events = adapter.discover_devices().await?;
62 pin_mut!(device_events);
63
64 let mut all_change_events = SelectAll::new();
65
66 loop {
67 tokio::select! {
68 Some(device_event) = device_events.next() => {
69 match device_event {
70 AdapterEvent::DeviceAdded(addr) => {
71 if !filter_addr.is_empty() && !filter_addr.contains(&addr) {
72 continue;
73 }
74
75 println!("Device added: {addr}");
76 let res = if all_properties {
77 query_all_device_properties(&adapter, addr).await
78 } else {
79 query_device(&adapter, addr).await
80 };
81 if let Err(err) = res {
82 println!(" Error: {}", &err);
83 }
84
85 if with_changes {
86 let device = adapter.device(addr)?;
87 let change_events = device.events().await?.map(move |evt| (addr, evt));
88 all_change_events.push(change_events);
89 }
90 }
91 AdapterEvent::DeviceRemoved(addr) => {
92 println!("Device removed: {addr}");
93 }
94 _ => (),
95 }
96 println!();
97 }
98 Some((addr, DeviceEvent::PropertyChanged(property))) = all_change_events.next() => {
99 println!("Device changed: {addr}");
100 println!(" {property:?}");
101 }
102 else => break
103 }
104 }
105
106 Ok(())
107}
More examples
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20
21 let adapter_name = std::env::args().nth(1);
22 let data_type: u8 = match std::env::args().nth(2) {
23 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse AD type"),
24 None => 0xff,
25 };
26 let start_position: u8 = match std::env::args().nth(3) {
27 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse or-pattern start position"),
28 None => 0x00,
29 };
30 let filter_string: Vec<String> = std::env::args().skip(4).collect();
31 let content: Vec<u8> = if !filter_string.is_empty() {
32 filter_string.iter().map(|s| parse_u8_maybe_hex(s).expect("Failed to parse or-pattern data")).collect()
33 } else {
34 vec![0xff, 0xff]
35 };
36
37 if content.is_empty() {
38 panic!("No filter bytes provided");
39 }
40
41 let pattern = Pattern { data_type, start_position, content };
42
43 let session = bluer::Session::new().await?;
44
45 let adapter = match adapter_name {
46 Some(name) => session.adapter(&name)?,
47 None => session.default_adapter().await?,
48 };
49 println!("Running le_passive_scan on adapter {} with or-pattern {:?}", adapter.name(), pattern);
50
51 adapter.set_powered(true).await?;
52
53 let mm = adapter.monitor().await?;
54 let mut monitor_handle = mm
55 .register(Monitor {
56 monitor_type: bluer::monitor::Type::OrPatterns,
57 rssi_low_threshold: None,
58 rssi_high_threshold: None,
59 rssi_low_timeout: None,
60 rssi_high_timeout: None,
61 rssi_sampling_period: Some(RssiSamplingPeriod::First),
62 patterns: Some(vec![pattern]),
63 ..Default::default()
64 })
65 .await?;
66
67 while let Some(mevt) = &monitor_handle.next().await {
68 if let MonitorEvent::DeviceFound(devid) = mevt {
69 println!("Discovered device {:?}", devid);
70 let dev = adapter.device(devid.device)?;
71 tokio::spawn(async move {
72 let mut events = dev.events().await.unwrap();
73 while let Some(ev) = events.next().await {
74 println!("On device {:?}, received event {:?}", dev, ev);
75 }
76 });
77 }
78 }
79
80 Ok(())
81}
Sourcepub async fn discovery_filter(&self) -> DiscoveryFilter
pub async fn discovery_filter(&self) -> DiscoveryFilter
Gets the filter used for device discovery.
Examples found in repository?
35async fn main() -> bluer::Result<()> {
36 let with_changes = env::args().any(|arg| arg == "--changes");
37 let all_properties = env::args().any(|arg| arg == "--all-properties");
38 let le_only = env::args().any(|arg| arg == "--le");
39 let br_edr_only = env::args().any(|arg| arg == "--bredr");
40 let filter_addr: HashSet<_> = env::args().filter_map(|arg| arg.parse::<Address>().ok()).collect();
41
42 env_logger::init();
43 let session = bluer::Session::new().await?;
44 let adapter = session.default_adapter().await?;
45 println!("Discovering devices using Bluetooth adapter {}\n", adapter.name());
46 adapter.set_powered(true).await?;
47
48 let filter = DiscoveryFilter {
49 transport: if le_only {
50 DiscoveryTransport::Le
51 } else if br_edr_only {
52 DiscoveryTransport::BrEdr
53 } else {
54 DiscoveryTransport::Auto
55 },
56 ..Default::default()
57 };
58 adapter.set_discovery_filter(filter).await?;
59 println!("Using discovery filter:\n{:#?}\n\n", adapter.discovery_filter().await);
60
61 let device_events = adapter.discover_devices().await?;
62 pin_mut!(device_events);
63
64 let mut all_change_events = SelectAll::new();
65
66 loop {
67 tokio::select! {
68 Some(device_event) = device_events.next() => {
69 match device_event {
70 AdapterEvent::DeviceAdded(addr) => {
71 if !filter_addr.is_empty() && !filter_addr.contains(&addr) {
72 continue;
73 }
74
75 println!("Device added: {addr}");
76 let res = if all_properties {
77 query_all_device_properties(&adapter, addr).await
78 } else {
79 query_device(&adapter, addr).await
80 };
81 if let Err(err) = res {
82 println!(" Error: {}", &err);
83 }
84
85 if with_changes {
86 let device = adapter.device(addr)?;
87 let change_events = device.events().await?.map(move |evt| (addr, evt));
88 all_change_events.push(change_events);
89 }
90 }
91 AdapterEvent::DeviceRemoved(addr) => {
92 println!("Device removed: {addr}");
93 }
94 _ => (),
95 }
96 println!();
97 }
98 Some((addr, DeviceEvent::PropertyChanged(property))) = all_change_events.next() => {
99 println!("Device changed: {addr}");
100 println!(" {property:?}");
101 }
102 else => break
103 }
104 }
105
106 Ok(())
107}
Sourcepub async fn set_discovery_filter(
&self,
discovery_filter: DiscoveryFilter,
) -> Result<()>
pub async fn set_discovery_filter( &self, discovery_filter: DiscoveryFilter, ) -> Result<()>
Sets the filter used for device discovery.
Setting a discovery filter does not guarantee that all its filters will be applied. A discovery session from another program might be active, leading to merging of the discovery filters by the Bluetooth daemon.
The discovery filter can only be changed when no device discovery is currently active. Otherwise a DiscoveryActive error will be returned.
Examples found in repository?
35async fn main() -> bluer::Result<()> {
36 let with_changes = env::args().any(|arg| arg == "--changes");
37 let all_properties = env::args().any(|arg| arg == "--all-properties");
38 let le_only = env::args().any(|arg| arg == "--le");
39 let br_edr_only = env::args().any(|arg| arg == "--bredr");
40 let filter_addr: HashSet<_> = env::args().filter_map(|arg| arg.parse::<Address>().ok()).collect();
41
42 env_logger::init();
43 let session = bluer::Session::new().await?;
44 let adapter = session.default_adapter().await?;
45 println!("Discovering devices using Bluetooth adapter {}\n", adapter.name());
46 adapter.set_powered(true).await?;
47
48 let filter = DiscoveryFilter {
49 transport: if le_only {
50 DiscoveryTransport::Le
51 } else if br_edr_only {
52 DiscoveryTransport::BrEdr
53 } else {
54 DiscoveryTransport::Auto
55 },
56 ..Default::default()
57 };
58 adapter.set_discovery_filter(filter).await?;
59 println!("Using discovery filter:\n{:#?}\n\n", adapter.discovery_filter().await);
60
61 let device_events = adapter.discover_devices().await?;
62 pin_mut!(device_events);
63
64 let mut all_change_events = SelectAll::new();
65
66 loop {
67 tokio::select! {
68 Some(device_event) = device_events.next() => {
69 match device_event {
70 AdapterEvent::DeviceAdded(addr) => {
71 if !filter_addr.is_empty() && !filter_addr.contains(&addr) {
72 continue;
73 }
74
75 println!("Device added: {addr}");
76 let res = if all_properties {
77 query_all_device_properties(&adapter, addr).await
78 } else {
79 query_device(&adapter, addr).await
80 };
81 if let Err(err) = res {
82 println!(" Error: {}", &err);
83 }
84
85 if with_changes {
86 let device = adapter.device(addr)?;
87 let change_events = device.events().await?.map(move |evt| (addr, evt));
88 all_change_events.push(change_events);
89 }
90 }
91 AdapterEvent::DeviceRemoved(addr) => {
92 println!("Device removed: {addr}");
93 }
94 _ => (),
95 }
96 println!();
97 }
98 Some((addr, DeviceEvent::PropertyChanged(property))) = all_change_events.next() => {
99 println!("Device changed: {addr}");
100 println!(" {property:?}");
101 }
102 else => break
103 }
104 }
105
106 Ok(())
107}
Sourcepub async fn discover_devices(&self) -> Result<impl Stream<Item = AdapterEvent>>
pub async fn discover_devices(&self) -> Result<impl Stream<Item = AdapterEvent>>
This method starts the device discovery session.
This includes an inquiry procedure and remote device name resolving.
This process will start streaming device addresses as new devices are discovered. A device may be discovered multiple times.
All already known devices are also included in the device stream. This may include devices that are currently not in range. Check the Device::rssi property to see if the device is currently present.
Device properties are queried asynchronously and may not be available yet when a DeviceAdded event occurs. Use discover_devices_with_changes when you want to be notified when the device properties change.
The discovery filter can be configured using set_discovery_filter.
Examples found in repository?
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
More examples
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
35async fn main() -> bluer::Result<()> {
36 let with_changes = env::args().any(|arg| arg == "--changes");
37 let all_properties = env::args().any(|arg| arg == "--all-properties");
38 let le_only = env::args().any(|arg| arg == "--le");
39 let br_edr_only = env::args().any(|arg| arg == "--bredr");
40 let filter_addr: HashSet<_> = env::args().filter_map(|arg| arg.parse::<Address>().ok()).collect();
41
42 env_logger::init();
43 let session = bluer::Session::new().await?;
44 let adapter = session.default_adapter().await?;
45 println!("Discovering devices using Bluetooth adapter {}\n", adapter.name());
46 adapter.set_powered(true).await?;
47
48 let filter = DiscoveryFilter {
49 transport: if le_only {
50 DiscoveryTransport::Le
51 } else if br_edr_only {
52 DiscoveryTransport::BrEdr
53 } else {
54 DiscoveryTransport::Auto
55 },
56 ..Default::default()
57 };
58 adapter.set_discovery_filter(filter).await?;
59 println!("Using discovery filter:\n{:#?}\n\n", adapter.discovery_filter().await);
60
61 let device_events = adapter.discover_devices().await?;
62 pin_mut!(device_events);
63
64 let mut all_change_events = SelectAll::new();
65
66 loop {
67 tokio::select! {
68 Some(device_event) = device_events.next() => {
69 match device_event {
70 AdapterEvent::DeviceAdded(addr) => {
71 if !filter_addr.is_empty() && !filter_addr.contains(&addr) {
72 continue;
73 }
74
75 println!("Device added: {addr}");
76 let res = if all_properties {
77 query_all_device_properties(&adapter, addr).await
78 } else {
79 query_device(&adapter, addr).await
80 };
81 if let Err(err) = res {
82 println!(" Error: {}", &err);
83 }
84
85 if with_changes {
86 let device = adapter.device(addr)?;
87 let change_events = device.events().await?.map(move |evt| (addr, evt));
88 all_change_events.push(change_events);
89 }
90 }
91 AdapterEvent::DeviceRemoved(addr) => {
92 println!("Device removed: {addr}");
93 }
94 _ => (),
95 }
96 println!();
97 }
98 Some((addr, DeviceEvent::PropertyChanged(property))) = all_change_events.next() => {
99 println!("Device changed: {addr}");
100 println!(" {property:?}");
101 }
102 else => break
103 }
104 }
105
106 Ok(())
107}
Sourcepub async fn discover_devices_with_changes(
&self,
) -> Result<impl Stream<Item = AdapterEvent>>
pub async fn discover_devices_with_changes( &self, ) -> Result<impl Stream<Item = AdapterEvent>>
This method starts the device discovery session and notifies of device property changes.
This includes an inquiry procedure and remote device name resolving.
This process will start streaming device addresses as new devices are discovered. Each time device properties change you will receive an additional DeviceAdded event for that device.
All already known devices are also included in the device stream. This may include devices that are currently not in range. Check the Device::rssi property to see if the device is currently present.
The discovery filter can be configured using set_discovery_filter.
Sourcepub async fn events(&self) -> Result<impl Stream<Item = AdapterEvent>>
pub async fn events(&self) -> Result<impl Stream<Item = AdapterEvent>>
Streams adapter property and device changes.
The stream ends when the adapter is removed.
Sourcepub async fn advertise(
&self,
le_advertisement: Advertisement,
) -> Result<AdvertisementHandle>
pub async fn advertise( &self, le_advertisement: Advertisement, ) -> Result<AdvertisementHandle>
Registers an advertisement object to be sent over the LE Advertising channel.
InvalidArguments error indicates that the object has invalid or conflicting properties.
InvalidLength error indicates that the data provided generates a data packet which is too long.
The properties of this object are parsed when it is registered, and any changes are ignored.
If the same object is registered twice it will result in an AlreadyExists error.
If the maximum number of advertisement instances is reached it will result in NotPermitted error.
Drop the returned AdvertisementHandle to unregister the advertisement.
Examples found in repository?
11async fn main() -> bluer::Result<()> {
12 env_logger::init();
13 let session = bluer::Session::new().await?;
14 let adapter = session.default_adapter().await?;
15 adapter.set_powered(true).await?;
16
17 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
18 let le_advertisement = Advertisement {
19 advertisement_type: bluer::adv::Type::Peripheral,
20 service_uuids: vec!["123e4567-e89b-12d3-a456-426614174000".parse().unwrap()].into_iter().collect(),
21 discoverable: Some(true),
22 local_name: Some("le_advertise".to_string()),
23 ..Default::default()
24 };
25 println!("{:?}", &le_advertisement);
26 let handle = adapter.advertise(le_advertisement).await?;
27
28 println!("Press enter to quit");
29 let stdin = BufReader::new(tokio::io::stdin());
30 let mut lines = stdin.lines();
31 let _ = lines.next_line().await;
32
33 println!("Removing advertisement");
34 drop(handle);
35 sleep(Duration::from_secs(1)).await;
36
37 Ok(())
38}
More examples
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20 let session = bluer::Session::new().await?;
21 let adapter = session.default_adapter().await?;
22 adapter.set_powered(true).await?;
23 let adapter_addr = adapter.address().await?;
24 let adapter_addr_type = adapter.address_type().await?;
25
26 // Advertising is necessary for device to be connectable.
27 println!(
28 "Advertising on Bluetooth adapter {} with {} address {}",
29 adapter.name(),
30 &adapter_addr_type,
31 &adapter_addr
32 );
33 let le_advertisement = Advertisement {
34 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
35 discoverable: Some(true),
36 local_name: Some("l2cap_server".to_string()),
37 ..Default::default()
38 };
39 let adv_handle = adapter.advertise(le_advertisement).await?;
40
41 let local_sa = SocketAddr::new(adapter_addr, adapter_addr_type, PSM);
42 let listener = StreamListener::bind(local_sa).await?;
43
44 println!("Listening on PSM {}. Press enter to quit.", listener.as_ref().local_addr()?.psm);
45 let stdin = BufReader::new(tokio::io::stdin());
46 let mut lines = stdin.lines();
47
48 loop {
49 println!("\nWaiting for connection...");
50
51 let (mut stream, sa) = tokio::select! {
52 l = listener.accept() => {
53 match l {
54 Ok(v) => v,
55 Err(err) => {
56 println!("Accepting connection failed: {}", &err);
57 continue;
58 }}
59 },
60 _ = lines.next_line() => break,
61 };
62 let recv_mtu = stream.as_ref().recv_mtu()?;
63
64 println!("Accepted connection from {:?} with receive MTU {} bytes", &sa, &recv_mtu);
65
66 println!("Sending hello");
67 if let Err(err) = stream.write_all(HELLO_MSG).await {
68 println!("Write failed: {}", &err);
69 continue;
70 }
71
72 let mut n = 0;
73 loop {
74 n += 1;
75
76 // Vary buffer size between MTU and smaller value to test
77 // partial reads.
78 let buf_size = if n % 5 == 0 { recv_mtu - 70 } else { recv_mtu };
79 let mut buf = vec![0; buf_size as _];
80
81 let n = match stream.read(&mut buf).await {
82 Ok(0) => {
83 println!("Stream ended");
84 break;
85 }
86 Ok(n) => n,
87 Err(err) => {
88 println!("Read failed: {}", &err);
89 continue;
90 }
91 };
92 let buf = &buf[..n];
93
94 println!("Echoing {} bytes", buf.len());
95 if let Err(err) = stream.write_all(buf).await {
96 println!("Write failed: {}", &err);
97 continue;
98 }
99 }
100 }
101
102 println!("Removing advertisement");
103 drop(adv_handle);
104 sleep(Duration::from_secs(1)).await;
105
106 Ok(())
107}
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}
21async fn main() -> bluer::Result<()> {
22 env_logger::init();
23 let session = bluer::Session::new().await?;
24 let adapter = session.default_adapter().await?;
25 adapter.set_powered(true).await?;
26
27 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
28 let mut manufacturer_data = BTreeMap::new();
29 manufacturer_data.insert(MANUFACTURER_ID, vec![0x21, 0x22, 0x23, 0x24]);
30 let le_advertisement = Advertisement {
31 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
32 manufacturer_data,
33 discoverable: Some(true),
34 local_name: Some("gatt_server".to_string()),
35 ..Default::default()
36 };
37 let adv_handle = adapter.advertise(le_advertisement).await?;
38
39 println!("Serving GATT service on Bluetooth adapter {}", adapter.name());
40 let value = Arc::new(Mutex::new(vec![0x10, 0x01, 0x01, 0x10]));
41 let value_read = value.clone();
42 let value_write = value.clone();
43 let value_notify = value.clone();
44 let app = Application {
45 services: vec![Service {
46 uuid: SERVICE_UUID,
47 primary: true,
48 characteristics: vec![Characteristic {
49 uuid: CHARACTERISTIC_UUID,
50 read: Some(CharacteristicRead {
51 read: true,
52 fun: Box::new(move |req| {
53 let value = value_read.clone();
54 async move {
55 let value = value.lock().await.clone();
56 println!("Read request {:?} with value {:x?}", &req, &value);
57 Ok(value)
58 }
59 .boxed()
60 }),
61 ..Default::default()
62 }),
63 write: Some(CharacteristicWrite {
64 write: true,
65 write_without_response: true,
66 method: CharacteristicWriteMethod::Fun(Box::new(move |new_value, req| {
67 let value = value_write.clone();
68 async move {
69 println!("Write request {:?} with value {:x?}", &req, &new_value);
70 let mut value = value.lock().await;
71 *value = new_value;
72 Ok(())
73 }
74 .boxed()
75 })),
76 ..Default::default()
77 }),
78 notify: Some(CharacteristicNotify {
79 notify: true,
80 method: CharacteristicNotifyMethod::Fun(Box::new(move |mut notifier| {
81 let value = value_notify.clone();
82 async move {
83 tokio::spawn(async move {
84 println!(
85 "Notification session start with confirming={:?}",
86 notifier.confirming()
87 );
88 loop {
89 {
90 let mut value = value.lock().await;
91 println!("Notifying with value {:x?}", &*value);
92 if let Err(err) = notifier.notify(value.to_vec()).await {
93 println!("Notification error: {}", &err);
94 break;
95 }
96 println!("Decrementing each element by one");
97 for v in &mut *value {
98 *v = v.saturating_sub(1);
99 }
100 }
101 sleep(Duration::from_secs(5)).await;
102 }
103 println!("Notification session stop");
104 });
105 }
106 .boxed()
107 })),
108 ..Default::default()
109 }),
110 ..Default::default()
111 }],
112 ..Default::default()
113 }],
114 ..Default::default()
115 };
116 let app_handle = adapter.serve_gatt_application(app).await?;
117
118 println!("Service ready. Press enter to quit.");
119 let stdin = BufReader::new(tokio::io::stdin());
120 let mut lines = stdin.lines();
121 let _ = lines.next_line().await;
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}
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 mut manufacturer_data = BTreeMap::new();
32 manufacturer_data.insert(MANUFACTURER_ID, vec![0x21, 0x22, 0x23, 0x24]);
33 let le_advertisement = Advertisement {
34 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
35 manufacturer_data,
36 discoverable: Some(true),
37 local_name: Some("gatt_server".to_string()),
38 ..Default::default()
39 };
40 let adv_handle = adapter.advertise(le_advertisement).await?;
41
42 println!("Serving GATT service on Bluetooth adapter {}", adapter.name());
43 let (service_control, service_handle) = service_control();
44 let (char_control, char_handle) = characteristic_control();
45 let app = Application {
46 services: vec![Service {
47 uuid: SERVICE_UUID,
48 primary: true,
49 characteristics: vec![Characteristic {
50 uuid: CHARACTERISTIC_UUID,
51 write: Some(CharacteristicWrite {
52 write: true,
53 write_without_response: true,
54 method: CharacteristicWriteMethod::Io,
55 ..Default::default()
56 }),
57 notify: Some(CharacteristicNotify {
58 notify: true,
59 method: CharacteristicNotifyMethod::Io,
60 ..Default::default()
61 }),
62 control_handle: char_handle,
63 ..Default::default()
64 }],
65 control_handle: service_handle,
66 ..Default::default()
67 }],
68 ..Default::default()
69 };
70 let app_handle = adapter.serve_gatt_application(app).await?;
71
72 println!("Service handle is 0x{:x}", service_control.handle()?);
73 println!("Characteristic handle is 0x{:x}", char_control.handle()?);
74
75 println!("Service ready. Press enter to quit.");
76 let stdin = BufReader::new(tokio::io::stdin());
77 let mut lines = stdin.lines();
78
79 let mut value: Vec<u8> = vec![0x10, 0x01, 0x01, 0x10];
80 let mut read_buf = Vec::new();
81 let mut reader_opt: Option<CharacteristicReader> = None;
82 let mut writer_opt: Option<CharacteristicWriter> = None;
83 let mut interval = interval(Duration::from_secs(1));
84 pin_mut!(char_control);
85
86 loop {
87 tokio::select! {
88 _ = lines.next_line() => break,
89 evt = char_control.next() => {
90 match evt {
91 Some(CharacteristicControlEvent::Write(req)) => {
92 println!("Accepting write event with MTU {} from {}", req.mtu(), req.device_address());
93 read_buf = vec![0; req.mtu()];
94 reader_opt = Some(req.accept()?);
95 },
96 Some(CharacteristicControlEvent::Notify(notifier)) => {
97 println!("Accepting notify request event with MTU {} from {}", notifier.mtu(), notifier.device_address());
98 writer_opt = Some(notifier);
99 },
100 None => break,
101 }
102 }
103 _ = interval.tick() => {
104 println!("Decrementing each element by one");
105 for v in &mut *value {
106 *v = v.saturating_sub(1);
107 }
108 println!("Value is {:x?}", &value);
109 if let Some(writer) = writer_opt.as_mut() {
110 println!("Notifying with value {:x?}", &value);
111 if let Err(err) = writer.write(&value).await {
112 println!("Notification stream error: {}", &err);
113 writer_opt = None;
114 }
115 }
116 }
117 read_res = async {
118 match &mut reader_opt {
119 Some(reader) => reader.read(&mut read_buf).await,
120 None => future::pending().await,
121 }
122 } => {
123 match read_res {
124 Ok(0) => {
125 println!("Write stream ended");
126 reader_opt = None;
127 }
128 Ok(n) => {
129 value = read_buf[0..n].to_vec();
130 println!("Write request with {} bytes: {:x?}", n, &value);
131 }
132 Err(err) => {
133 println!("Write stream error: {}", &err);
134 reader_opt = None;
135 }
136 }
137 }
138 }
139 }
140
141 println!("Removing service and advertisement");
142 drop(app_handle);
143 drop(adv_handle);
144 sleep(Duration::from_secs(1)).await;
145
146 Ok(())
147}
Sourcepub async fn serve_gatt_application(
&self,
gatt_application: Application,
) -> Result<ApplicationHandle>
pub async fn serve_gatt_application( &self, gatt_application: Application, ) -> Result<ApplicationHandle>
Registers a local GATT services hierarchy (GATT Server).
Registering a service allows applications to publish a local GATT service, which then becomes available to remote devices.
Drop the returned ApplicationHandle to unregister the application.
Examples found in repository?
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}
More examples
21async fn main() -> bluer::Result<()> {
22 env_logger::init();
23 let session = bluer::Session::new().await?;
24 let adapter = session.default_adapter().await?;
25 adapter.set_powered(true).await?;
26
27 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
28 let mut manufacturer_data = BTreeMap::new();
29 manufacturer_data.insert(MANUFACTURER_ID, vec![0x21, 0x22, 0x23, 0x24]);
30 let le_advertisement = Advertisement {
31 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
32 manufacturer_data,
33 discoverable: Some(true),
34 local_name: Some("gatt_server".to_string()),
35 ..Default::default()
36 };
37 let adv_handle = adapter.advertise(le_advertisement).await?;
38
39 println!("Serving GATT service on Bluetooth adapter {}", adapter.name());
40 let value = Arc::new(Mutex::new(vec![0x10, 0x01, 0x01, 0x10]));
41 let value_read = value.clone();
42 let value_write = value.clone();
43 let value_notify = value.clone();
44 let app = Application {
45 services: vec![Service {
46 uuid: SERVICE_UUID,
47 primary: true,
48 characteristics: vec![Characteristic {
49 uuid: CHARACTERISTIC_UUID,
50 read: Some(CharacteristicRead {
51 read: true,
52 fun: Box::new(move |req| {
53 let value = value_read.clone();
54 async move {
55 let value = value.lock().await.clone();
56 println!("Read request {:?} with value {:x?}", &req, &value);
57 Ok(value)
58 }
59 .boxed()
60 }),
61 ..Default::default()
62 }),
63 write: Some(CharacteristicWrite {
64 write: true,
65 write_without_response: true,
66 method: CharacteristicWriteMethod::Fun(Box::new(move |new_value, req| {
67 let value = value_write.clone();
68 async move {
69 println!("Write request {:?} with value {:x?}", &req, &new_value);
70 let mut value = value.lock().await;
71 *value = new_value;
72 Ok(())
73 }
74 .boxed()
75 })),
76 ..Default::default()
77 }),
78 notify: Some(CharacteristicNotify {
79 notify: true,
80 method: CharacteristicNotifyMethod::Fun(Box::new(move |mut notifier| {
81 let value = value_notify.clone();
82 async move {
83 tokio::spawn(async move {
84 println!(
85 "Notification session start with confirming={:?}",
86 notifier.confirming()
87 );
88 loop {
89 {
90 let mut value = value.lock().await;
91 println!("Notifying with value {:x?}", &*value);
92 if let Err(err) = notifier.notify(value.to_vec()).await {
93 println!("Notification error: {}", &err);
94 break;
95 }
96 println!("Decrementing each element by one");
97 for v in &mut *value {
98 *v = v.saturating_sub(1);
99 }
100 }
101 sleep(Duration::from_secs(5)).await;
102 }
103 println!("Notification session stop");
104 });
105 }
106 .boxed()
107 })),
108 ..Default::default()
109 }),
110 ..Default::default()
111 }],
112 ..Default::default()
113 }],
114 ..Default::default()
115 };
116 let app_handle = adapter.serve_gatt_application(app).await?;
117
118 println!("Service ready. Press enter to quit.");
119 let stdin = BufReader::new(tokio::io::stdin());
120 let mut lines = stdin.lines();
121 let _ = lines.next_line().await;
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}
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 mut manufacturer_data = BTreeMap::new();
32 manufacturer_data.insert(MANUFACTURER_ID, vec![0x21, 0x22, 0x23, 0x24]);
33 let le_advertisement = Advertisement {
34 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
35 manufacturer_data,
36 discoverable: Some(true),
37 local_name: Some("gatt_server".to_string()),
38 ..Default::default()
39 };
40 let adv_handle = adapter.advertise(le_advertisement).await?;
41
42 println!("Serving GATT service on Bluetooth adapter {}", adapter.name());
43 let (service_control, service_handle) = service_control();
44 let (char_control, char_handle) = characteristic_control();
45 let app = Application {
46 services: vec![Service {
47 uuid: SERVICE_UUID,
48 primary: true,
49 characteristics: vec![Characteristic {
50 uuid: CHARACTERISTIC_UUID,
51 write: Some(CharacteristicWrite {
52 write: true,
53 write_without_response: true,
54 method: CharacteristicWriteMethod::Io,
55 ..Default::default()
56 }),
57 notify: Some(CharacteristicNotify {
58 notify: true,
59 method: CharacteristicNotifyMethod::Io,
60 ..Default::default()
61 }),
62 control_handle: char_handle,
63 ..Default::default()
64 }],
65 control_handle: service_handle,
66 ..Default::default()
67 }],
68 ..Default::default()
69 };
70 let app_handle = adapter.serve_gatt_application(app).await?;
71
72 println!("Service handle is 0x{:x}", service_control.handle()?);
73 println!("Characteristic handle is 0x{:x}", char_control.handle()?);
74
75 println!("Service ready. Press enter to quit.");
76 let stdin = BufReader::new(tokio::io::stdin());
77 let mut lines = stdin.lines();
78
79 let mut value: Vec<u8> = vec![0x10, 0x01, 0x01, 0x10];
80 let mut read_buf = Vec::new();
81 let mut reader_opt: Option<CharacteristicReader> = None;
82 let mut writer_opt: Option<CharacteristicWriter> = None;
83 let mut interval = interval(Duration::from_secs(1));
84 pin_mut!(char_control);
85
86 loop {
87 tokio::select! {
88 _ = lines.next_line() => break,
89 evt = char_control.next() => {
90 match evt {
91 Some(CharacteristicControlEvent::Write(req)) => {
92 println!("Accepting write event with MTU {} from {}", req.mtu(), req.device_address());
93 read_buf = vec![0; req.mtu()];
94 reader_opt = Some(req.accept()?);
95 },
96 Some(CharacteristicControlEvent::Notify(notifier)) => {
97 println!("Accepting notify request event with MTU {} from {}", notifier.mtu(), notifier.device_address());
98 writer_opt = Some(notifier);
99 },
100 None => break,
101 }
102 }
103 _ = interval.tick() => {
104 println!("Decrementing each element by one");
105 for v in &mut *value {
106 *v = v.saturating_sub(1);
107 }
108 println!("Value is {:x?}", &value);
109 if let Some(writer) = writer_opt.as_mut() {
110 println!("Notifying with value {:x?}", &value);
111 if let Err(err) = writer.write(&value).await {
112 println!("Notification stream error: {}", &err);
113 writer_opt = None;
114 }
115 }
116 }
117 read_res = async {
118 match &mut reader_opt {
119 Some(reader) => reader.read(&mut read_buf).await,
120 None => future::pending().await,
121 }
122 } => {
123 match read_res {
124 Ok(0) => {
125 println!("Write stream ended");
126 reader_opt = None;
127 }
128 Ok(n) => {
129 value = read_buf[0..n].to_vec();
130 println!("Write request with {} bytes: {:x?}", n, &value);
131 }
132 Err(err) => {
133 println!("Write stream error: {}", &err);
134 reader_opt = None;
135 }
136 }
137 }
138 }
139 }
140
141 println!("Removing service and advertisement");
142 drop(app_handle);
143 drop(adv_handle);
144 sleep(Duration::from_secs(1)).await;
145
146 Ok(())
147}
Sourcepub async fn register_gatt_profile(
&self,
gatt_profile: Profile,
) -> Result<ProfileHandle>
pub async fn register_gatt_profile( &self, gatt_profile: Profile, ) -> Result<ProfileHandle>
Registers local GATT profiles (GATT Client).
By registering this type of object an application effectively indicates support for a specific GATT profile and requests automatic connections to be established to devices supporting it.
Drop the returned ProfileHandle to unregister the application.
Sourcepub async fn remove_device(&self, address: Address) -> Result<()>
pub async fn remove_device(&self, address: Address) -> Result<()>
This removes the remote device object for the given device address.
It will remove also the pairing information.
Examples found in repository?
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
More examples
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
Sourcepub async fn connect_device(
&self,
address: Address,
address_type: AddressType,
) -> Result<Device>
pub async fn connect_device( &self, address: Address, address_type: AddressType, ) -> Result<Device>
This method connects to device without need of performing General Discovery.
Connection mechanism is similar to Connect method from Device1 interface with exception that this method returns success when physical connection is established. After this method returns, services discovery will continue and any supported profile will be connected. There is no need for calling Connect on Device1 after this call. If connection was successful this method returns the created device object.
Parameters are the following:
address
- The Bluetooth device address of the remote device.address_type
- The Bluetooth device Address Type. This is address type that should be used for initial connection.
This method is experimental.
Source§impl Adapter
impl Adapter
Sourcepub async fn address(&self) -> Result<Address>
pub async fn address(&self) -> Result<Address>
The Bluetooth adapter address.
Examples found in repository?
11async fn main() -> bluer::Result<()> {
12 env_logger::init();
13 let session = bluer::Session::new().await?;
14 let adapter = session.default_adapter().await?;
15 adapter.set_powered(true).await?;
16
17 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
18 let le_advertisement = Advertisement {
19 advertisement_type: bluer::adv::Type::Peripheral,
20 service_uuids: vec!["123e4567-e89b-12d3-a456-426614174000".parse().unwrap()].into_iter().collect(),
21 discoverable: Some(true),
22 local_name: Some("le_advertise".to_string()),
23 ..Default::default()
24 };
25 println!("{:?}", &le_advertisement);
26 let handle = adapter.advertise(le_advertisement).await?;
27
28 println!("Press enter to quit");
29 let stdin = BufReader::new(tokio::io::stdin());
30 let mut lines = stdin.lines();
31 let _ = lines.next_line().await;
32
33 println!("Removing advertisement");
34 drop(handle);
35 sleep(Duration::from_secs(1)).await;
36
37 Ok(())
38}
More examples
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
9async fn main() -> bluer::Result<()> {
10 env_logger::init();
11 let session = bluer::Session::new().await?;
12 let adapter = session.default_adapter().await?;
13 adapter.set_powered(true).await?;
14 adapter.set_discoverable(true).await?;
15 let adapter_addr = adapter.address().await?;
16
17 let local_sa = SocketAddr::new(adapter_addr, CHANNEL);
18 let listener = Listener::bind(local_sa).await?;
19
20 println!(
21 "Listening on {} channel {}. Press enter to quit.",
22 listener.as_ref().local_addr()?.addr,
23 listener.as_ref().local_addr()?.channel
24 );
25 let stdin = BufReader::new(tokio::io::stdin());
26 let mut lines = stdin.lines();
27
28 loop {
29 println!("\nWaiting for connection...");
30
31 let (mut stream, sa) = tokio::select! {
32 l = listener.accept() => {
33 match l {
34 Ok(v) => v,
35 Err(err) => {
36 println!("Accepting connection failed: {}", &err);
37 continue;
38 }}
39 },
40 _ = lines.next_line() => break,
41 };
42
43 println!("Accepted connection from {:?}", &sa);
44
45 println!("Sending hello");
46 if let Err(err) = stream.write_all(HELLO_MSG).await {
47 println!("Write failed: {}", &err);
48 continue;
49 }
50
51 loop {
52 let buf_size = 1024;
53 let mut buf = vec![0; buf_size as _];
54
55 let n = match stream.read(&mut buf).await {
56 Ok(0) => {
57 println!("Stream ended");
58 break;
59 }
60 Ok(n) => n,
61 Err(err) => {
62 println!("Read failed: {}", &err);
63 break;
64 }
65 };
66 let buf = &buf[..n];
67
68 println!("Echoing {} bytes", buf.len());
69 if let Err(err) = stream.write_all(buf).await {
70 println!("Write failed: {}", &err);
71 continue;
72 }
73 }
74 }
75
76 Ok(())
77}
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20 let session = bluer::Session::new().await?;
21 let adapter = session.default_adapter().await?;
22 adapter.set_powered(true).await?;
23 let adapter_addr = adapter.address().await?;
24 let adapter_addr_type = adapter.address_type().await?;
25
26 // Advertising is necessary for device to be connectable.
27 println!(
28 "Advertising on Bluetooth adapter {} with {} address {}",
29 adapter.name(),
30 &adapter_addr_type,
31 &adapter_addr
32 );
33 let le_advertisement = Advertisement {
34 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
35 discoverable: Some(true),
36 local_name: Some("l2cap_server".to_string()),
37 ..Default::default()
38 };
39 let adv_handle = adapter.advertise(le_advertisement).await?;
40
41 let local_sa = SocketAddr::new(adapter_addr, adapter_addr_type, PSM);
42 let listener = StreamListener::bind(local_sa).await?;
43
44 println!("Listening on PSM {}. Press enter to quit.", listener.as_ref().local_addr()?.psm);
45 let stdin = BufReader::new(tokio::io::stdin());
46 let mut lines = stdin.lines();
47
48 loop {
49 println!("\nWaiting for connection...");
50
51 let (mut stream, sa) = tokio::select! {
52 l = listener.accept() => {
53 match l {
54 Ok(v) => v,
55 Err(err) => {
56 println!("Accepting connection failed: {}", &err);
57 continue;
58 }}
59 },
60 _ = lines.next_line() => break,
61 };
62 let recv_mtu = stream.as_ref().recv_mtu()?;
63
64 println!("Accepted connection from {:?} with receive MTU {} bytes", &sa, &recv_mtu);
65
66 println!("Sending hello");
67 if let Err(err) = stream.write_all(HELLO_MSG).await {
68 println!("Write failed: {}", &err);
69 continue;
70 }
71
72 let mut n = 0;
73 loop {
74 n += 1;
75
76 // Vary buffer size between MTU and smaller value to test
77 // partial reads.
78 let buf_size = if n % 5 == 0 { recv_mtu - 70 } else { recv_mtu };
79 let mut buf = vec![0; buf_size as _];
80
81 let n = match stream.read(&mut buf).await {
82 Ok(0) => {
83 println!("Stream ended");
84 break;
85 }
86 Ok(n) => n,
87 Err(err) => {
88 println!("Read failed: {}", &err);
89 continue;
90 }
91 };
92 let buf = &buf[..n];
93
94 println!("Echoing {} bytes", buf.len());
95 if let Err(err) = stream.write_all(buf).await {
96 println!("Write failed: {}", &err);
97 continue;
98 }
99 }
100 }
101
102 println!("Removing advertisement");
103 drop(adv_handle);
104 sleep(Duration::from_secs(1)).await;
105
106 Ok(())
107}
Sourcepub async fn address_type(&self) -> Result<AddressType>
pub async fn address_type(&self) -> Result<AddressType>
The Bluetooth adapter address type.
For dual-mode and BR/EDR only adapter this defaults to “public”. Single mode LE adapters may have either value. With privacy enabled this contains type of Identity Address and not type of address used for connection.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
More examples
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20 let session = bluer::Session::new().await?;
21 let adapter = session.default_adapter().await?;
22 adapter.set_powered(true).await?;
23 let adapter_addr = adapter.address().await?;
24 let adapter_addr_type = adapter.address_type().await?;
25
26 // Advertising is necessary for device to be connectable.
27 println!(
28 "Advertising on Bluetooth adapter {} with {} address {}",
29 adapter.name(),
30 &adapter_addr_type,
31 &adapter_addr
32 );
33 let le_advertisement = Advertisement {
34 service_uuids: vec![SERVICE_UUID].into_iter().collect(),
35 discoverable: Some(true),
36 local_name: Some("l2cap_server".to_string()),
37 ..Default::default()
38 };
39 let adv_handle = adapter.advertise(le_advertisement).await?;
40
41 let local_sa = SocketAddr::new(adapter_addr, adapter_addr_type, PSM);
42 let listener = StreamListener::bind(local_sa).await?;
43
44 println!("Listening on PSM {}. Press enter to quit.", listener.as_ref().local_addr()?.psm);
45 let stdin = BufReader::new(tokio::io::stdin());
46 let mut lines = stdin.lines();
47
48 loop {
49 println!("\nWaiting for connection...");
50
51 let (mut stream, sa) = tokio::select! {
52 l = listener.accept() => {
53 match l {
54 Ok(v) => v,
55 Err(err) => {
56 println!("Accepting connection failed: {}", &err);
57 continue;
58 }}
59 },
60 _ = lines.next_line() => break,
61 };
62 let recv_mtu = stream.as_ref().recv_mtu()?;
63
64 println!("Accepted connection from {:?} with receive MTU {} bytes", &sa, &recv_mtu);
65
66 println!("Sending hello");
67 if let Err(err) = stream.write_all(HELLO_MSG).await {
68 println!("Write failed: {}", &err);
69 continue;
70 }
71
72 let mut n = 0;
73 loop {
74 n += 1;
75
76 // Vary buffer size between MTU and smaller value to test
77 // partial reads.
78 let buf_size = if n % 5 == 0 { recv_mtu - 70 } else { recv_mtu };
79 let mut buf = vec![0; buf_size as _];
80
81 let n = match stream.read(&mut buf).await {
82 Ok(0) => {
83 println!("Stream ended");
84 break;
85 }
86 Ok(n) => n,
87 Err(err) => {
88 println!("Read failed: {}", &err);
89 continue;
90 }
91 };
92 let buf = &buf[..n];
93
94 println!("Echoing {} bytes", buf.len());
95 if let Err(err) = stream.write_all(buf).await {
96 println!("Write failed: {}", &err);
97 continue;
98 }
99 }
100 }
101
102 println!("Removing advertisement");
103 drop(adv_handle);
104 sleep(Duration::from_secs(1)).await;
105
106 Ok(())
107}
Sourcepub async fn system_name(&self) -> Result<String>
pub async fn system_name(&self) -> Result<String>
The Bluetooth system name (pretty hostname).
This property is either a static system default or controlled by an external daemon providing access to the pretty hostname configuration.
Sourcepub async fn alias(&self) -> Result<String>
pub async fn alias(&self) -> Result<String>
The Bluetooth friendly name.
This value can be changed.
In case no alias is set, it will return the system provided name. Setting an empty string as alias will convert it back to the system provided name.
When resetting the alias with an empty string, the property will default back to system name.
On a well configured system, this property never needs to be changed since it defaults to the system name and provides the pretty hostname. Only if the local name needs to be different from the pretty hostname, this property should be used as last resort.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn set_alias(&self, v: String) -> Result<()>
pub async fn set_alias(&self, v: String) -> Result<()>
The Bluetooth friendly name.
This value can be changed.
In case no alias is set, it will return the system provided name. Setting an empty string as alias will convert it back to the system provided name.
When resetting the alias with an empty string, the property will default back to system name.
On a well configured system, this property never needs to be changed since it defaults to the system name and provides the pretty hostname. Only if the local name needs to be different from the pretty hostname, this property should be used as last resort.
Sourcepub async fn class(&self) -> Result<u32>
pub async fn class(&self) -> Result<u32>
The Bluetooth class of device.
This property represents the value that is either automatically configured by DMI/ACPI information or provided as static configuration.
Sourcepub async fn is_powered(&self) -> Result<bool>
pub async fn is_powered(&self) -> Result<bool>
Switch an adapter on or off. This will also set the appropriate connectable state of the controller.
The value of this property is not persistent. After restart or unplugging of the adapter it will reset back to false.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn set_powered(&self, v: bool) -> Result<()>
pub async fn set_powered(&self, v: bool) -> Result<()>
Switch an adapter on or off. This will also set the appropriate connectable state of the controller.
The value of this property is not persistent. After restart or unplugging of the adapter it will reset back to false.
Examples found in repository?
11async fn main() -> bluer::Result<()> {
12 env_logger::init();
13 let session = bluer::Session::new().await?;
14 let adapter = session.default_adapter().await?;
15 adapter.set_powered(true).await?;
16
17 println!("Advertising on Bluetooth adapter {} with address {}", adapter.name(), adapter.address().await?);
18 let le_advertisement = Advertisement {
19 advertisement_type: bluer::adv::Type::Peripheral,
20 service_uuids: vec!["123e4567-e89b-12d3-a456-426614174000".parse().unwrap()].into_iter().collect(),
21 discoverable: Some(true),
22 local_name: Some("le_advertise".to_string()),
23 ..Default::default()
24 };
25 println!("{:?}", &le_advertisement);
26 let handle = adapter.advertise(le_advertisement).await?;
27
28 println!("Press enter to quit");
29 let stdin = BufReader::new(tokio::io::stdin());
30 let mut lines = stdin.lines();
31 let _ = lines.next_line().await;
32
33 println!("Removing advertisement");
34 drop(handle);
35 sleep(Duration::from_secs(1)).await;
36
37 Ok(())
38}
More examples
9async fn main() -> bluer::Result<()> {
10 env_logger::init();
11 let session = bluer::Session::new().await?;
12 let adapter = session.default_adapter().await?;
13 adapter.set_powered(true).await?;
14 adapter.set_discoverable(true).await?;
15 let adapter_addr = adapter.address().await?;
16
17 let local_sa = SocketAddr::new(adapter_addr, CHANNEL);
18 let listener = Listener::bind(local_sa).await?;
19
20 println!(
21 "Listening on {} channel {}. Press enter to quit.",
22 listener.as_ref().local_addr()?.addr,
23 listener.as_ref().local_addr()?.channel
24 );
25 let stdin = BufReader::new(tokio::io::stdin());
26 let mut lines = stdin.lines();
27
28 loop {
29 println!("\nWaiting for connection...");
30
31 let (mut stream, sa) = tokio::select! {
32 l = listener.accept() => {
33 match l {
34 Ok(v) => v,
35 Err(err) => {
36 println!("Accepting connection failed: {}", &err);
37 continue;
38 }}
39 },
40 _ = lines.next_line() => break,
41 };
42
43 println!("Accepted connection from {:?}", &sa);
44
45 println!("Sending hello");
46 if let Err(err) = stream.write_all(HELLO_MSG).await {
47 println!("Write failed: {}", &err);
48 continue;
49 }
50
51 loop {
52 let buf_size = 1024;
53 let mut buf = vec![0; buf_size as _];
54
55 let n = match stream.read(&mut buf).await {
56 Ok(0) => {
57 println!("Stream ended");
58 break;
59 }
60 Ok(n) => n,
61 Err(err) => {
62 println!("Read failed: {}", &err);
63 break;
64 }
65 };
66 let buf = &buf[..n];
67
68 println!("Echoing {} bytes", buf.len());
69 if let Err(err) = stream.write_all(buf).await {
70 println!("Write failed: {}", &err);
71 continue;
72 }
73 }
74 }
75
76 Ok(())
77}
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
146async fn main() -> bluer::Result<()> {
147 env_logger::init();
148 let session = bluer::Session::new().await?;
149 let adapter = session.default_adapter().await?;
150 adapter.set_powered(true).await?;
151
152 {
153 println!(
154 "Discovering on Bluetooth adapter {} with address {}\n",
155 adapter.name(),
156 adapter.address().await?
157 );
158 let discover = adapter.discover_devices().await?;
159 pin_mut!(discover);
160 let mut done = false;
161 while let Some(evt) = discover.next().await {
162 match evt {
163 AdapterEvent::DeviceAdded(addr) => {
164 let device = adapter.device(addr)?;
165 match find_our_characteristic(&device).await {
166 Ok(Some(char)) => match exercise_characteristic(&char).await {
167 Ok(()) => {
168 println!(" Characteristic exercise completed");
169 done = true;
170 }
171 Err(err) => {
172 println!(" Characteristic exercise failed: {}", &err);
173 }
174 },
175 Ok(None) => (),
176 Err(err) => {
177 println!(" Device failed: {}", &err);
178 let _ = adapter.remove_device(device.address()).await;
179 }
180 }
181 match device.disconnect().await {
182 Ok(()) => println!(" Device disconnected"),
183 Err(err) => println!(" Device disconnection failed: {}", &err),
184 }
185 println!();
186 }
187 AdapterEvent::DeviceRemoved(addr) => {
188 println!("Device removed {addr}");
189 }
190 _ => (),
191 }
192 if done {
193 break;
194 }
195 }
196 println!("Stopping discovery");
197 }
198
199 sleep(Duration::from_secs(1)).await;
200 Ok(())
201}
18async fn main() -> bluer::Result<()> {
19 env_logger::init();
20
21 let adapter_name = std::env::args().nth(1);
22 let data_type: u8 = match std::env::args().nth(2) {
23 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse AD type"),
24 None => 0xff,
25 };
26 let start_position: u8 = match std::env::args().nth(3) {
27 Some(s) => parse_u8_maybe_hex(&s).expect("Failed to parse or-pattern start position"),
28 None => 0x00,
29 };
30 let filter_string: Vec<String> = std::env::args().skip(4).collect();
31 let content: Vec<u8> = if !filter_string.is_empty() {
32 filter_string.iter().map(|s| parse_u8_maybe_hex(s).expect("Failed to parse or-pattern data")).collect()
33 } else {
34 vec![0xff, 0xff]
35 };
36
37 if content.is_empty() {
38 panic!("No filter bytes provided");
39 }
40
41 let pattern = Pattern { data_type, start_position, content };
42
43 let session = bluer::Session::new().await?;
44
45 let adapter = match adapter_name {
46 Some(name) => session.adapter(&name)?,
47 None => session.default_adapter().await?,
48 };
49 println!("Running le_passive_scan on adapter {} with or-pattern {:?}", adapter.name(), pattern);
50
51 adapter.set_powered(true).await?;
52
53 let mm = adapter.monitor().await?;
54 let mut monitor_handle = mm
55 .register(Monitor {
56 monitor_type: bluer::monitor::Type::OrPatterns,
57 rssi_low_threshold: None,
58 rssi_high_threshold: None,
59 rssi_low_timeout: None,
60 rssi_high_timeout: None,
61 rssi_sampling_period: Some(RssiSamplingPeriod::First),
62 patterns: Some(vec![pattern]),
63 ..Default::default()
64 })
65 .await?;
66
67 while let Some(mevt) = &monitor_handle.next().await {
68 if let MonitorEvent::DeviceFound(devid) = mevt {
69 println!("Discovered device {:?}", devid);
70 let dev = adapter.device(devid.device)?;
71 tokio::spawn(async move {
72 let mut events = dev.events().await.unwrap();
73 while let Some(ev) = events.next().await {
74 println!("On device {:?}, received event {:?}", dev, ev);
75 }
76 });
77 }
78 }
79
80 Ok(())
81}
14async fn main() -> bluer::Result<()> {
15 env_logger::init();
16 let session = bluer::Session::new().await?;
17 let adapter = session.default_adapter().await?;
18 adapter.set_powered(true).await?;
19
20 let args: Vec<_> = env::args().collect();
21 if args.len() != 2 {
22 eprintln!("Specify target Bluetooth address as argument");
23 exit(1);
24 }
25
26 let target_addr: Address = args[1].parse().expect("invalid address");
27 let target_sa = SocketAddr::new(target_addr, CHANNEL);
28
29 println!("Connecting to {:?}", &target_sa);
30 let mut stream = Stream::connect(target_sa).await.expect("connection failed");
31 println!("Local address: {:?}", stream.as_ref().local_addr()?);
32 println!("Remote address: {:?}", stream.peer_addr()?);
33 println!("Security: {:?}", stream.as_ref().security()?);
34
35 println!("\nReceiving hello");
36 let mut hello_buf = [0u8; HELLO_MSG.len()];
37 stream.read_exact(&mut hello_buf).await.expect("read failed");
38 println!("Received: {}", String::from_utf8_lossy(&hello_buf));
39 if hello_buf != HELLO_MSG {
40 panic!("Wrong hello message");
41 }
42
43 let (mut rh, mut wh) = stream.into_split();
44 let mut rng = rand::thread_rng();
45 for i in 0..15 {
46 let len = rng.gen_range(0..50000);
47 let data: Vec<u8> = (0..len).map(|_| rng.gen()).collect();
48
49 println!("\nTest iteration {i} with data size {len}");
50
51 // We must read back the data while sending, otherwise the connection
52 // buffer will overrun and we will lose data.
53 let read_task = tokio::spawn(async move {
54 let mut echo_buf = vec![0u8; len];
55 let res = match rh.read_exact(&mut echo_buf).await {
56 Ok(_) => Ok(echo_buf),
57 Err(err) => Err(err),
58 };
59 (rh, res)
60 });
61
62 // Note that write_all will automatically split the buffer into
63 // multiple writes of MTU size.
64 wh.write_all(&data).await.expect("write failed");
65
66 println!("Waiting for echo");
67 let (rh_back, res) = read_task.await.unwrap();
68 rh = rh_back;
69 let echo_buf = res.expect("read failed");
70
71 if echo_buf != data {
72 panic!("Echoed data does not match sent data");
73 }
74 println!("Data matches");
75 }
76
77 println!("Done");
78 Ok(())
79}
Sourcepub async fn is_discoverable(&self) -> Result<bool>
pub async fn is_discoverable(&self) -> Result<bool>
Switch an adapter to discoverable or non-discoverable to either make it visible or hide it.
This is a global setting and should only be used by the settings application.
If the DiscoverableTimeout is set to a non-zero value then the system will set this value back to false after the timer expired.
In case the adapter is switched off, setting this value will fail.
When changing the Powered property the new state of this property will be updated via a PropertiesChanged signal.
For any new adapter this settings defaults to false.
To send Bluetooth LE advertisements use the advertise method instead.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn set_discoverable(&self, v: bool) -> Result<()>
pub async fn set_discoverable(&self, v: bool) -> Result<()>
Switch an adapter to discoverable or non-discoverable to either make it visible or hide it.
This is a global setting and should only be used by the settings application.
If the DiscoverableTimeout is set to a non-zero value then the system will set this value back to false after the timer expired.
In case the adapter is switched off, setting this value will fail.
When changing the Powered property the new state of this property will be updated via a PropertiesChanged signal.
For any new adapter this settings defaults to false.
To send Bluetooth LE advertisements use the advertise method instead.
Examples found in repository?
9async fn main() -> bluer::Result<()> {
10 env_logger::init();
11 let session = bluer::Session::new().await?;
12 let adapter = session.default_adapter().await?;
13 adapter.set_powered(true).await?;
14 adapter.set_discoverable(true).await?;
15 let adapter_addr = adapter.address().await?;
16
17 let local_sa = SocketAddr::new(adapter_addr, CHANNEL);
18 let listener = Listener::bind(local_sa).await?;
19
20 println!(
21 "Listening on {} channel {}. Press enter to quit.",
22 listener.as_ref().local_addr()?.addr,
23 listener.as_ref().local_addr()?.channel
24 );
25 let stdin = BufReader::new(tokio::io::stdin());
26 let mut lines = stdin.lines();
27
28 loop {
29 println!("\nWaiting for connection...");
30
31 let (mut stream, sa) = tokio::select! {
32 l = listener.accept() => {
33 match l {
34 Ok(v) => v,
35 Err(err) => {
36 println!("Accepting connection failed: {}", &err);
37 continue;
38 }}
39 },
40 _ = lines.next_line() => break,
41 };
42
43 println!("Accepted connection from {:?}", &sa);
44
45 println!("Sending hello");
46 if let Err(err) = stream.write_all(HELLO_MSG).await {
47 println!("Write failed: {}", &err);
48 continue;
49 }
50
51 loop {
52 let buf_size = 1024;
53 let mut buf = vec![0; buf_size as _];
54
55 let n = match stream.read(&mut buf).await {
56 Ok(0) => {
57 println!("Stream ended");
58 break;
59 }
60 Ok(n) => n,
61 Err(err) => {
62 println!("Read failed: {}", &err);
63 break;
64 }
65 };
66 let buf = &buf[..n];
67
68 println!("Echoing {} bytes", buf.len());
69 if let Err(err) = stream.write_all(buf).await {
70 println!("Write failed: {}", &err);
71 continue;
72 }
73 }
74 }
75
76 Ok(())
77}
Sourcepub async fn is_pairable(&self) -> Result<bool>
pub async fn is_pairable(&self) -> Result<bool>
Switch an adapter to pairable or non-pairable.
This is a global setting and should only be used by the settings application.
Note that this property only affects incoming pairing requests.
For any new adapter this settings defaults to true.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn set_pairable(&self, v: bool) -> Result<()>
pub async fn set_pairable(&self, v: bool) -> Result<()>
Switch an adapter to pairable or non-pairable.
This is a global setting and should only be used by the settings application.
Note that this property only affects incoming pairing requests.
For any new adapter this settings defaults to true.
Sourcepub async fn pairable_timeout(&self) -> Result<u32>
pub async fn pairable_timeout(&self) -> Result<u32>
The pairable timeout in seconds.
A value of zero means that the timeout is disabled and it will stay in pairable mode forever.
The default value for pairable timeout should be disabled (value 0).
Sourcepub async fn set_pairable_timeout(&self, v: u32) -> Result<()>
pub async fn set_pairable_timeout(&self, v: u32) -> Result<()>
The pairable timeout in seconds.
A value of zero means that the timeout is disabled and it will stay in pairable mode forever.
The default value for pairable timeout should be disabled (value 0).
Sourcepub async fn discoverable_timeout(&self) -> Result<u32>
pub async fn discoverable_timeout(&self) -> Result<u32>
The discoverable timeout in seconds.
A value of zero means that the timeout is disabled and it will stay in discoverable/limited mode forever.
The default value for the discoverable timeout should be 180 seconds (3 minutes).
Sourcepub async fn set_discoverable_timeout(&self, v: u32) -> Result<()>
pub async fn set_discoverable_timeout(&self, v: u32) -> Result<()>
The discoverable timeout in seconds.
A value of zero means that the timeout is disabled and it will stay in discoverable/limited mode forever.
The default value for the discoverable timeout should be 180 seconds (3 minutes).
Sourcepub async fn is_discovering(&self) -> Result<bool>
pub async fn is_discovering(&self) -> Result<bool>
Indicates that a device discovery procedure is active.
Sourcepub async fn uuids(&self) -> Result<Option<HashSet<Uuid>>>
pub async fn uuids(&self) -> Result<Option<HashSet<Uuid>>>
List of 128-bit UUIDs that represents the available local services.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn modalias(&self) -> Result<Option<Modalias>>
pub async fn modalias(&self) -> Result<Option<Modalias>>
Local Device ID information in modalias format used by the kernel and udev.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn active_advertising_instances(&self) -> Result<u8>
pub async fn active_advertising_instances(&self) -> Result<u8>
Number of active advertising instances.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn supported_advertising_instances(&self) -> Result<u8>
pub async fn supported_advertising_instances(&self) -> Result<u8>
Number of available advertising instances.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn supported_advertising_system_includes(
&self,
) -> Result<BTreeSet<Feature>>
pub async fn supported_advertising_system_includes( &self, ) -> Result<BTreeSet<Feature>>
List of supported system includes.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn supported_advertising_secondary_channels(
&self,
) -> Result<Option<BTreeSet<SecondaryChannel>>>
pub async fn supported_advertising_secondary_channels( &self, ) -> Result<Option<BTreeSet<SecondaryChannel>>>
List of supported Secondary channels.
Secondary channels can be used to advertise with the corresponding PHY.
Sourcepub async fn supported_advertising_capabilities(
&self,
) -> Result<Option<Capabilities>>
pub async fn supported_advertising_capabilities( &self, ) -> Result<Option<Capabilities>>
Enumerates Advertising-related controller capabilities useful to the client.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn supported_advertising_features(
&self,
) -> Result<Option<BTreeSet<PlatformFeature>>>
pub async fn supported_advertising_features( &self, ) -> Result<Option<BTreeSet<PlatformFeature>>>
List of supported platform features.
If no features are available on the platform, the SupportedFeatures array will be empty.
Examples found in repository?
3async fn query_adapter(adapter: &bluer::Adapter) -> bluer::Result<()> {
4 println!(" Address: {}", adapter.address().await?);
5 println!(" Address type: {}", adapter.address_type().await?);
6 println!(" Friendly name: {}", adapter.alias().await?);
7 println!(" Modalias: {:?}", adapter.modalias().await?);
8 println!(" Powered: {:?}", adapter.is_powered().await?);
9 println!(" Discoverabe: {:?}", adapter.is_discoverable().await?);
10 println!(" Pairable: {:?}", adapter.is_pairable().await?);
11 println!(" UUIDs: {:?}", adapter.uuids().await?);
12 println!();
13 println!(" Active adv. instances: {}", adapter.active_advertising_instances().await?);
14 println!(" Supp. adv. instances: {}", adapter.supported_advertising_instances().await?);
15 println!(" Supp. adv. includes: {:?}", adapter.supported_advertising_system_includes().await?);
16 println!(" Adv. capabilites: {:?}", adapter.supported_advertising_capabilities().await?);
17 println!(" Adv. features: {:?}", adapter.supported_advertising_features().await?);
18
19 Ok(())
20}
Sourcepub async fn all_properties(&self) -> Result<Vec<AdapterProperty>>
pub async fn all_properties(&self) -> Result<Vec<AdapterProperty>>
Queries and returns all properties.