xref: /aosp_15_r20/tools/netsim/rust/daemon/src/wireless/bluetooth.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2023 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker 
15*cf78ab8cSAndroid Build Coastguard Worker use crate::devices::chip::ChipIdentifier;
16*cf78ab8cSAndroid Build Coastguard Worker use crate::ffi::ffi_bluetooth;
17*cf78ab8cSAndroid Build Coastguard Worker use crate::wireless::{WirelessAdaptor, WirelessAdaptorImpl};
18*cf78ab8cSAndroid Build Coastguard Worker 
19*cf78ab8cSAndroid Build Coastguard Worker use bytes::Bytes;
20*cf78ab8cSAndroid Build Coastguard Worker use cxx::{let_cxx_string, CxxString, CxxVector};
21*cf78ab8cSAndroid Build Coastguard Worker use log::{error, info};
22*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::config::Bluetooth as BluetoothConfig;
23*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::configuration::Controller as RootcanalController;
24*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::Bluetooth as ProtoBluetooth;
25*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::Radio as ProtoRadio;
26*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::Chip as ProtoChip;
27*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::stats::invalid_packet::Reason as InvalidPacketReason;
28*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::stats::{netsim_radio_stats, InvalidPacket, NetsimRadioStats as ProtoRadioStats};
29*cf78ab8cSAndroid Build Coastguard Worker use protobuf::{Enum, Message, MessageField};
30*cf78ab8cSAndroid Build Coastguard Worker use std::collections::BTreeMap;
31*cf78ab8cSAndroid Build Coastguard Worker use std::sync::atomic::{AtomicBool, Ordering};
32*cf78ab8cSAndroid Build Coastguard Worker use std::sync::{Arc, Mutex, OnceLock};
33*cf78ab8cSAndroid Build Coastguard Worker 
34*cf78ab8cSAndroid Build Coastguard Worker static WIRELESS_BT_MUTEX: Mutex<()> = Mutex::new(());
35*cf78ab8cSAndroid Build Coastguard Worker 
36*cf78ab8cSAndroid Build Coastguard Worker pub type RootcanalIdentifier = u32;
37*cf78ab8cSAndroid Build Coastguard Worker 
38*cf78ab8cSAndroid Build Coastguard Worker // BLUETOOTH_INVALID_PACKETS is a singleton that contains a hash map from
39*cf78ab8cSAndroid Build Coastguard Worker // RootcanalIdentifier to Vec<InvalidPacket>
40*cf78ab8cSAndroid Build Coastguard Worker // This singleton is only used when Rootcanal reports invalid
41*cf78ab8cSAndroid Build Coastguard Worker // packets by rootcanal_id and we add those to Bluetooth struct.
42*cf78ab8cSAndroid Build Coastguard Worker static BLUETOOTH_INVALID_PACKETS: OnceLock<
43*cf78ab8cSAndroid Build Coastguard Worker     Arc<Mutex<BTreeMap<RootcanalIdentifier, Vec<InvalidPacket>>>>,
44*cf78ab8cSAndroid Build Coastguard Worker > = OnceLock::new();
45*cf78ab8cSAndroid Build Coastguard Worker 
get_bluetooth_invalid_packets() -> Arc<Mutex<BTreeMap<RootcanalIdentifier, Vec<InvalidPacket>>>>46*cf78ab8cSAndroid Build Coastguard Worker fn get_bluetooth_invalid_packets() -> Arc<Mutex<BTreeMap<RootcanalIdentifier, Vec<InvalidPacket>>>>
47*cf78ab8cSAndroid Build Coastguard Worker {
48*cf78ab8cSAndroid Build Coastguard Worker     BLUETOOTH_INVALID_PACKETS.get_or_init(|| Arc::new(Mutex::new(BTreeMap::new()))).clone()
49*cf78ab8cSAndroid Build Coastguard Worker }
50*cf78ab8cSAndroid Build Coastguard Worker 
51*cf78ab8cSAndroid Build Coastguard Worker /// Parameters for creating Bluetooth chips
52*cf78ab8cSAndroid Build Coastguard Worker /// allow(dead_code) due to not being used in unit tests
53*cf78ab8cSAndroid Build Coastguard Worker #[allow(dead_code)]
54*cf78ab8cSAndroid Build Coastguard Worker pub struct CreateParams {
55*cf78ab8cSAndroid Build Coastguard Worker     pub address: String,
56*cf78ab8cSAndroid Build Coastguard Worker     pub bt_properties: Option<MessageField<RootcanalController>>,
57*cf78ab8cSAndroid Build Coastguard Worker }
58*cf78ab8cSAndroid Build Coastguard Worker 
59*cf78ab8cSAndroid Build Coastguard Worker /// Bluetooth struct will keep track of rootcanal_id
60*cf78ab8cSAndroid Build Coastguard Worker pub struct Bluetooth {
61*cf78ab8cSAndroid Build Coastguard Worker     rootcanal_id: RootcanalIdentifier,
62*cf78ab8cSAndroid Build Coastguard Worker     low_energy_enabled: AtomicBool,
63*cf78ab8cSAndroid Build Coastguard Worker     classic_enabled: AtomicBool,
64*cf78ab8cSAndroid Build Coastguard Worker }
65*cf78ab8cSAndroid Build Coastguard Worker 
patch_state( enabled: &AtomicBool, state: Option<bool>, id: RootcanalIdentifier, is_low_energy: bool, )66*cf78ab8cSAndroid Build Coastguard Worker fn patch_state(
67*cf78ab8cSAndroid Build Coastguard Worker     enabled: &AtomicBool,
68*cf78ab8cSAndroid Build Coastguard Worker     state: Option<bool>,
69*cf78ab8cSAndroid Build Coastguard Worker     id: RootcanalIdentifier,
70*cf78ab8cSAndroid Build Coastguard Worker     is_low_energy: bool,
71*cf78ab8cSAndroid Build Coastguard Worker ) {
72*cf78ab8cSAndroid Build Coastguard Worker     if let Some(state) = state {
73*cf78ab8cSAndroid Build Coastguard Worker         let _guard = WIRELESS_BT_MUTEX.lock().expect("Failed to lock WIRELESS_BT_MUTEX");
74*cf78ab8cSAndroid Build Coastguard Worker         let last_state: bool = enabled.swap(state, Ordering::SeqCst);
75*cf78ab8cSAndroid Build Coastguard Worker         match (last_state, state) {
76*cf78ab8cSAndroid Build Coastguard Worker             (false, true) => ffi_bluetooth::add_device_to_phy(id, is_low_energy),
77*cf78ab8cSAndroid Build Coastguard Worker             (true, false) => ffi_bluetooth::remove_device_from_phy(id, is_low_energy),
78*cf78ab8cSAndroid Build Coastguard Worker             _ => {}
79*cf78ab8cSAndroid Build Coastguard Worker         }
80*cf78ab8cSAndroid Build Coastguard Worker     }
81*cf78ab8cSAndroid Build Coastguard Worker }
82*cf78ab8cSAndroid Build Coastguard Worker 
83*cf78ab8cSAndroid Build Coastguard Worker impl Drop for Bluetooth {
drop(&mut self)84*cf78ab8cSAndroid Build Coastguard Worker     fn drop(&mut self) {
85*cf78ab8cSAndroid Build Coastguard Worker         // Lock to protect id_to_chip_info_ table in C++
86*cf78ab8cSAndroid Build Coastguard Worker         let _guard = WIRELESS_BT_MUTEX.lock().expect("Failed to acquire lock on WIRELESS_BT_MUTEX");
87*cf78ab8cSAndroid Build Coastguard Worker         ffi_bluetooth::bluetooth_remove(self.rootcanal_id);
88*cf78ab8cSAndroid Build Coastguard Worker         get_bluetooth_invalid_packets().lock().expect("invalid packets").remove(&self.rootcanal_id);
89*cf78ab8cSAndroid Build Coastguard Worker     }
90*cf78ab8cSAndroid Build Coastguard Worker }
91*cf78ab8cSAndroid Build Coastguard Worker 
92*cf78ab8cSAndroid Build Coastguard Worker impl WirelessAdaptor for Bluetooth {
handle_request(&self, packet: &Bytes)93*cf78ab8cSAndroid Build Coastguard Worker     fn handle_request(&self, packet: &Bytes) {
94*cf78ab8cSAndroid Build Coastguard Worker         // Lock to protect device_to_transport_ table in C++
95*cf78ab8cSAndroid Build Coastguard Worker         let _guard = WIRELESS_BT_MUTEX.lock().expect("Failed to acquire lock on WIRELESS_BT_MUTEX");
96*cf78ab8cSAndroid Build Coastguard Worker         ffi_bluetooth::handle_bt_request(self.rootcanal_id, packet[0], &packet[1..].to_vec())
97*cf78ab8cSAndroid Build Coastguard Worker     }
98*cf78ab8cSAndroid Build Coastguard Worker 
reset(&self)99*cf78ab8cSAndroid Build Coastguard Worker     fn reset(&self) {
100*cf78ab8cSAndroid Build Coastguard Worker         let _guard = WIRELESS_BT_MUTEX.lock().expect("Failed to acquire lock on WIRELESS_BT_MUTEX");
101*cf78ab8cSAndroid Build Coastguard Worker         ffi_bluetooth::bluetooth_reset(self.rootcanal_id);
102*cf78ab8cSAndroid Build Coastguard Worker         self.low_energy_enabled.store(true, Ordering::SeqCst);
103*cf78ab8cSAndroid Build Coastguard Worker         self.classic_enabled.store(true, Ordering::SeqCst);
104*cf78ab8cSAndroid Build Coastguard Worker     }
105*cf78ab8cSAndroid Build Coastguard Worker 
get(&self) -> ProtoChip106*cf78ab8cSAndroid Build Coastguard Worker     fn get(&self) -> ProtoChip {
107*cf78ab8cSAndroid Build Coastguard Worker         let bluetooth_bytes = ffi_bluetooth::bluetooth_get_cxx(self.rootcanal_id);
108*cf78ab8cSAndroid Build Coastguard Worker         let bt_proto = ProtoBluetooth::parse_from_bytes(&bluetooth_bytes).unwrap();
109*cf78ab8cSAndroid Build Coastguard Worker         let mut chip_proto = ProtoChip::new();
110*cf78ab8cSAndroid Build Coastguard Worker         chip_proto.set_bt(ProtoBluetooth {
111*cf78ab8cSAndroid Build Coastguard Worker             low_energy: Some(ProtoRadio {
112*cf78ab8cSAndroid Build Coastguard Worker                 state: self.low_energy_enabled.load(Ordering::SeqCst).into(),
113*cf78ab8cSAndroid Build Coastguard Worker                 tx_count: bt_proto.low_energy.tx_count,
114*cf78ab8cSAndroid Build Coastguard Worker                 rx_count: bt_proto.low_energy.rx_count,
115*cf78ab8cSAndroid Build Coastguard Worker                 ..Default::default()
116*cf78ab8cSAndroid Build Coastguard Worker             })
117*cf78ab8cSAndroid Build Coastguard Worker             .into(),
118*cf78ab8cSAndroid Build Coastguard Worker             classic: Some(ProtoRadio {
119*cf78ab8cSAndroid Build Coastguard Worker                 state: self.classic_enabled.load(Ordering::SeqCst).into(),
120*cf78ab8cSAndroid Build Coastguard Worker                 tx_count: bt_proto.classic.tx_count,
121*cf78ab8cSAndroid Build Coastguard Worker                 rx_count: bt_proto.classic.rx_count,
122*cf78ab8cSAndroid Build Coastguard Worker                 ..Default::default()
123*cf78ab8cSAndroid Build Coastguard Worker             })
124*cf78ab8cSAndroid Build Coastguard Worker             .into(),
125*cf78ab8cSAndroid Build Coastguard Worker             address: bt_proto.address,
126*cf78ab8cSAndroid Build Coastguard Worker             bt_properties: bt_proto.bt_properties,
127*cf78ab8cSAndroid Build Coastguard Worker             ..Default::default()
128*cf78ab8cSAndroid Build Coastguard Worker         });
129*cf78ab8cSAndroid Build Coastguard Worker         chip_proto
130*cf78ab8cSAndroid Build Coastguard Worker     }
131*cf78ab8cSAndroid Build Coastguard Worker 
patch(&self, chip: &ProtoChip)132*cf78ab8cSAndroid Build Coastguard Worker     fn patch(&self, chip: &ProtoChip) {
133*cf78ab8cSAndroid Build Coastguard Worker         if !chip.has_bt() {
134*cf78ab8cSAndroid Build Coastguard Worker             return;
135*cf78ab8cSAndroid Build Coastguard Worker         }
136*cf78ab8cSAndroid Build Coastguard Worker         let id = self.rootcanal_id;
137*cf78ab8cSAndroid Build Coastguard Worker         patch_state(&self.low_energy_enabled, chip.bt().low_energy.state, id, true);
138*cf78ab8cSAndroid Build Coastguard Worker         patch_state(&self.classic_enabled, chip.bt().classic.state, id, false);
139*cf78ab8cSAndroid Build Coastguard Worker     }
140*cf78ab8cSAndroid Build Coastguard Worker 
get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats>141*cf78ab8cSAndroid Build Coastguard Worker     fn get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats> {
142*cf78ab8cSAndroid Build Coastguard Worker         // Construct NetsimRadioStats for BLE and Classic.
143*cf78ab8cSAndroid Build Coastguard Worker         let mut ble_stats_proto = ProtoRadioStats::new();
144*cf78ab8cSAndroid Build Coastguard Worker         ble_stats_proto.set_duration_secs(duration_secs);
145*cf78ab8cSAndroid Build Coastguard Worker         if let Some(v) = get_bluetooth_invalid_packets()
146*cf78ab8cSAndroid Build Coastguard Worker             .lock()
147*cf78ab8cSAndroid Build Coastguard Worker             .expect("Failed to acquire lock on BLUETOOTH_INVALID_PACKETS")
148*cf78ab8cSAndroid Build Coastguard Worker             .get(&self.rootcanal_id)
149*cf78ab8cSAndroid Build Coastguard Worker         {
150*cf78ab8cSAndroid Build Coastguard Worker             for invalid_packet in v {
151*cf78ab8cSAndroid Build Coastguard Worker                 ble_stats_proto.invalid_packets.push(invalid_packet.clone());
152*cf78ab8cSAndroid Build Coastguard Worker             }
153*cf78ab8cSAndroid Build Coastguard Worker         }
154*cf78ab8cSAndroid Build Coastguard Worker         let mut classic_stats_proto = ble_stats_proto.clone();
155*cf78ab8cSAndroid Build Coastguard Worker 
156*cf78ab8cSAndroid Build Coastguard Worker         // Obtain the Chip Information with get()
157*cf78ab8cSAndroid Build Coastguard Worker         let chip_proto = self.get();
158*cf78ab8cSAndroid Build Coastguard Worker         if chip_proto.has_bt() {
159*cf78ab8cSAndroid Build Coastguard Worker             // Setting values for BLE Radio Stats
160*cf78ab8cSAndroid Build Coastguard Worker             ble_stats_proto.set_kind(netsim_radio_stats::Kind::BLUETOOTH_LOW_ENERGY);
161*cf78ab8cSAndroid Build Coastguard Worker             ble_stats_proto.set_tx_count(chip_proto.bt().low_energy.tx_count);
162*cf78ab8cSAndroid Build Coastguard Worker             ble_stats_proto.set_rx_count(chip_proto.bt().low_energy.rx_count);
163*cf78ab8cSAndroid Build Coastguard Worker             // Setting values for Classic Radio Stats
164*cf78ab8cSAndroid Build Coastguard Worker             classic_stats_proto.set_kind(netsim_radio_stats::Kind::BLUETOOTH_CLASSIC);
165*cf78ab8cSAndroid Build Coastguard Worker             classic_stats_proto.set_tx_count(chip_proto.bt().classic.tx_count);
166*cf78ab8cSAndroid Build Coastguard Worker             classic_stats_proto.set_rx_count(chip_proto.bt().classic.rx_count);
167*cf78ab8cSAndroid Build Coastguard Worker         }
168*cf78ab8cSAndroid Build Coastguard Worker         vec![ble_stats_proto, classic_stats_proto]
169*cf78ab8cSAndroid Build Coastguard Worker     }
170*cf78ab8cSAndroid Build Coastguard Worker }
171*cf78ab8cSAndroid Build Coastguard Worker 
172*cf78ab8cSAndroid Build Coastguard Worker /// Create a new Emulated Bluetooth Chip
173*cf78ab8cSAndroid Build Coastguard Worker /// allow(dead_code) due to not being used in unit tests
174*cf78ab8cSAndroid Build Coastguard Worker #[allow(dead_code)]
new(create_params: &CreateParams, chip_id: ChipIdentifier) -> WirelessAdaptorImpl175*cf78ab8cSAndroid Build Coastguard Worker pub fn new(create_params: &CreateParams, chip_id: ChipIdentifier) -> WirelessAdaptorImpl {
176*cf78ab8cSAndroid Build Coastguard Worker     // Lock to protect id_to_chip_info_ table in C++
177*cf78ab8cSAndroid Build Coastguard Worker     let _guard = WIRELESS_BT_MUTEX.lock().expect("Failed to acquire lock on WIRELESS_BT_MUTEX");
178*cf78ab8cSAndroid Build Coastguard Worker     let_cxx_string!(cxx_address = create_params.address.clone());
179*cf78ab8cSAndroid Build Coastguard Worker     let proto_bytes = match &create_params.bt_properties {
180*cf78ab8cSAndroid Build Coastguard Worker         Some(properties) => properties.write_to_bytes().unwrap(),
181*cf78ab8cSAndroid Build Coastguard Worker         None => Vec::new(),
182*cf78ab8cSAndroid Build Coastguard Worker     };
183*cf78ab8cSAndroid Build Coastguard Worker     let rootcanal_id = ffi_bluetooth::bluetooth_add(chip_id.0, &cxx_address, &proto_bytes);
184*cf78ab8cSAndroid Build Coastguard Worker     info!("Bluetooth WirelessAdaptor created with rootcanal_id: {rootcanal_id} chip_id: {chip_id}");
185*cf78ab8cSAndroid Build Coastguard Worker     let wireless_adaptor = Bluetooth {
186*cf78ab8cSAndroid Build Coastguard Worker         rootcanal_id,
187*cf78ab8cSAndroid Build Coastguard Worker         low_energy_enabled: AtomicBool::new(true),
188*cf78ab8cSAndroid Build Coastguard Worker         classic_enabled: AtomicBool::new(true),
189*cf78ab8cSAndroid Build Coastguard Worker     };
190*cf78ab8cSAndroid Build Coastguard Worker     get_bluetooth_invalid_packets()
191*cf78ab8cSAndroid Build Coastguard Worker         .lock()
192*cf78ab8cSAndroid Build Coastguard Worker         .expect("invalid packets")
193*cf78ab8cSAndroid Build Coastguard Worker         .insert(rootcanal_id, Vec::new());
194*cf78ab8cSAndroid Build Coastguard Worker     Box::new(wireless_adaptor)
195*cf78ab8cSAndroid Build Coastguard Worker }
196*cf78ab8cSAndroid Build Coastguard Worker 
197*cf78ab8cSAndroid Build Coastguard Worker /// Starts the Bluetooth service.
bluetooth_start(config: &MessageField<BluetoothConfig>, instance_num: u16)198*cf78ab8cSAndroid Build Coastguard Worker pub fn bluetooth_start(config: &MessageField<BluetoothConfig>, instance_num: u16) {
199*cf78ab8cSAndroid Build Coastguard Worker     let proto_bytes = config.as_ref().unwrap_or_default().write_to_bytes().unwrap();
200*cf78ab8cSAndroid Build Coastguard Worker     ffi_bluetooth::bluetooth_start(&proto_bytes, instance_num);
201*cf78ab8cSAndroid Build Coastguard Worker }
202*cf78ab8cSAndroid Build Coastguard Worker 
203*cf78ab8cSAndroid Build Coastguard Worker /// Stops the Bluetooth service.
bluetooth_stop()204*cf78ab8cSAndroid Build Coastguard Worker pub fn bluetooth_stop() {
205*cf78ab8cSAndroid Build Coastguard Worker     ffi_bluetooth::bluetooth_stop();
206*cf78ab8cSAndroid Build Coastguard Worker }
207*cf78ab8cSAndroid Build Coastguard Worker 
208*cf78ab8cSAndroid Build Coastguard Worker /// Report Invalid Packet
report_invalid_packet( rootcanal_id: RootcanalIdentifier, reason: InvalidPacketReason, description: String, packet: Vec<u8>, )209*cf78ab8cSAndroid Build Coastguard Worker pub fn report_invalid_packet(
210*cf78ab8cSAndroid Build Coastguard Worker     rootcanal_id: RootcanalIdentifier,
211*cf78ab8cSAndroid Build Coastguard Worker     reason: InvalidPacketReason,
212*cf78ab8cSAndroid Build Coastguard Worker     description: String,
213*cf78ab8cSAndroid Build Coastguard Worker     packet: Vec<u8>,
214*cf78ab8cSAndroid Build Coastguard Worker ) {
215*cf78ab8cSAndroid Build Coastguard Worker     // TODO(b/330726276): spawn task on tokio once context is provided from rust_main
216*cf78ab8cSAndroid Build Coastguard Worker     let _ = std::thread::Builder::new().name("report_invalid_packet".to_string()).spawn(move || {
217*cf78ab8cSAndroid Build Coastguard Worker         match get_bluetooth_invalid_packets().lock().unwrap().get_mut(&rootcanal_id) {
218*cf78ab8cSAndroid Build Coastguard Worker             Some(v) => {
219*cf78ab8cSAndroid Build Coastguard Worker                 // Remove the earliest reported packet if length greater than 5
220*cf78ab8cSAndroid Build Coastguard Worker                 if v.len() >= 5 {
221*cf78ab8cSAndroid Build Coastguard Worker                     v.remove(0);
222*cf78ab8cSAndroid Build Coastguard Worker                 }
223*cf78ab8cSAndroid Build Coastguard Worker                 // append error packet
224*cf78ab8cSAndroid Build Coastguard Worker                 let mut invalid_packet = InvalidPacket::new();
225*cf78ab8cSAndroid Build Coastguard Worker                 invalid_packet.set_reason(reason);
226*cf78ab8cSAndroid Build Coastguard Worker                 invalid_packet.set_description(description.clone());
227*cf78ab8cSAndroid Build Coastguard Worker                 invalid_packet.set_packet(packet.clone());
228*cf78ab8cSAndroid Build Coastguard Worker                 v.push(invalid_packet);
229*cf78ab8cSAndroid Build Coastguard Worker                 // Log the report
230*cf78ab8cSAndroid Build Coastguard Worker                 info!("Invalid Packet for rootcanal_id: {rootcanal_id}, reason: {reason:?}, description: {description:?}, packet: {packet:?}");
231*cf78ab8cSAndroid Build Coastguard Worker             }
232*cf78ab8cSAndroid Build Coastguard Worker             None => error!("Bluetooth WirelessAdaptor not created for rootcanal_id: {rootcanal_id}"),
233*cf78ab8cSAndroid Build Coastguard Worker         }
234*cf78ab8cSAndroid Build Coastguard Worker     });
235*cf78ab8cSAndroid Build Coastguard Worker }
236*cf78ab8cSAndroid Build Coastguard Worker 
237*cf78ab8cSAndroid Build Coastguard Worker /// (Called by C++) Report Invalid Packet
report_invalid_packet_cxx( rootcanal_id: RootcanalIdentifier, reason: i32, description: &CxxString, packet: &CxxVector<u8>, )238*cf78ab8cSAndroid Build Coastguard Worker pub fn report_invalid_packet_cxx(
239*cf78ab8cSAndroid Build Coastguard Worker     rootcanal_id: RootcanalIdentifier,
240*cf78ab8cSAndroid Build Coastguard Worker     reason: i32,
241*cf78ab8cSAndroid Build Coastguard Worker     description: &CxxString,
242*cf78ab8cSAndroid Build Coastguard Worker     packet: &CxxVector<u8>,
243*cf78ab8cSAndroid Build Coastguard Worker ) {
244*cf78ab8cSAndroid Build Coastguard Worker     report_invalid_packet(
245*cf78ab8cSAndroid Build Coastguard Worker         rootcanal_id,
246*cf78ab8cSAndroid Build Coastguard Worker         InvalidPacketReason::from_i32(reason).unwrap_or(InvalidPacketReason::UNKNOWN),
247*cf78ab8cSAndroid Build Coastguard Worker         description.to_string(),
248*cf78ab8cSAndroid Build Coastguard Worker         packet.as_slice().to_vec(),
249*cf78ab8cSAndroid Build Coastguard Worker     );
250*cf78ab8cSAndroid Build Coastguard Worker }
251