1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 use anyhow::anyhow;
16 use bumble::{
17 adv::{AdvertisementDataBuilder, CommonDataType},
18 wrapper::{
19 device::Device,
20 logging::{bumble_env_logging_level, py_logging_basic_config},
21 transport::Transport,
22 },
23 };
24 use clap::Parser as _;
25 use pyo3::PyResult;
26 use rand::Rng;
27 use std::path;
28
29 #[pyo3_asyncio::tokio::main]
main() -> PyResult<()>30 async fn main() -> PyResult<()> {
31 env_logger::builder()
32 .filter_level(log::LevelFilter::Info)
33 .init();
34
35 let cli = Cli::parse();
36
37 if cli.log_hci {
38 py_logging_basic_config(bumble_env_logging_level("DEBUG"))?;
39 }
40
41 let transport = Transport::open(cli.transport).await?;
42
43 let mut device = Device::from_config_file_with_hci(
44 &cli.device_config,
45 transport.source()?,
46 transport.sink()?,
47 )?;
48
49 let mut adv_data = AdvertisementDataBuilder::new();
50
51 adv_data
52 .append(
53 CommonDataType::CompleteLocalName,
54 "Bumble from Rust".as_bytes(),
55 )
56 .map_err(|e| anyhow!(e))?;
57
58 // Randomized TX power
59 adv_data
60 .append(
61 CommonDataType::TxPowerLevel,
62 &[rand::thread_rng().gen_range(-100_i8..=20) as u8],
63 )
64 .map_err(|e| anyhow!(e))?;
65
66 device.power_on().await?;
67
68 if cli.extended {
69 println!("Starting extended advertisement...");
70 device.start_advertising_extended(adv_data).await?;
71 } else {
72 device.set_advertising_data(adv_data)?;
73
74 println!("Starting legacy advertisement...");
75 device.start_advertising(true).await?;
76 }
77
78 // wait until user kills the process
79 tokio::signal::ctrl_c().await?;
80
81 if cli.extended {
82 println!("Stopping extended advertisement...");
83 device.stop_advertising_extended().await?;
84 } else {
85 println!("Stopping legacy advertisement...");
86 device.stop_advertising().await?;
87 }
88
89 Ok(())
90 }
91
92 #[derive(clap::Parser)]
93 #[command(author, version, about, long_about = None)]
94 struct Cli {
95 /// Bumble device config.
96 ///
97 /// See, for instance, `examples/device1.json` in the Python project.
98 #[arg(long)]
99 device_config: path::PathBuf,
100
101 /// Bumble transport spec.
102 ///
103 /// <https://google.github.io/bumble/transports/index.html>
104 #[arg(long)]
105 transport: String,
106
107 /// Whether to perform an extended (BT 5.0) advertisement
108 #[arg(long)]
109 extended: bool,
110
111 /// Log HCI commands
112 #[arg(long)]
113 log_hci: bool,
114 }
115