blob: bc5d605a65ec2e79b9fe8399a69603db2daa4fcc [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::devices::chip::ChipIdentifier;
use crate::ffi::ffi_bluetooth;
use crate::{
devices::device::DeviceIdentifier,
echip::{EmulatedChip, SharedEmulatedChip},
};
use cxx::let_cxx_string;
use netsim_proto::common::ChipKind as ProtoChipKind;
use netsim_proto::config::Bluetooth as BluetoothConfig;
use netsim_proto::configuration::Controller as RootcanalController;
use netsim_proto::model::chip::Bluetooth as ProtoBluetooth;
use netsim_proto::model::Chip as ProtoChip;
use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats};
use protobuf::{Message, MessageField};
use std::sync::{Arc, Mutex};
static ECHIP_BT_MUTEX: Mutex<()> = Mutex::new(());
pub type RootcanalIdentifier = u32;
/// Parameters for creating Bluetooth chips
pub struct CreateParams {
pub address: String,
pub bt_properties: Option<MessageField<RootcanalController>>,
}
/// Bluetooth struct will keep track of rootcanal_id
pub struct Bluetooth {
rootcanal_id: RootcanalIdentifier,
}
impl EmulatedChip for Bluetooth {
fn handle_request(&self, packet: &[u8]) {
// Lock to protect device_to_transport_ table in C++
let _unused = ECHIP_BT_MUTEX.lock().expect("Failed to acquire lock on ECHIP_BT_MUTEX");
ffi_bluetooth::handle_bt_request(self.rootcanal_id, packet[0], &packet[1..].to_vec())
}
fn reset(&self) {
ffi_bluetooth::bluetooth_reset(self.rootcanal_id);
}
fn get(&self) -> ProtoChip {
let bluetooth_bytes = ffi_bluetooth::bluetooth_get_cxx(self.rootcanal_id);
let bt_proto = ProtoBluetooth::parse_from_bytes(&bluetooth_bytes).unwrap();
let mut chip_proto = ProtoChip::new();
chip_proto.mut_bt().clone_from(&bt_proto);
chip_proto
}
fn patch(&self, chip: &ProtoChip) {
let bluetooth_bytes = chip.bt().write_to_bytes().unwrap();
ffi_bluetooth::bluetooth_patch_cxx(self.rootcanal_id, &bluetooth_bytes);
}
fn remove(&self) {
// Lock to protect id_to_chip_info_ table in C++
let _unused = ECHIP_BT_MUTEX.lock().expect("Failed to acquire lock on ECHIP_BT_MUTEX");
ffi_bluetooth::bluetooth_remove(self.rootcanal_id);
}
fn get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats> {
// Construct NetsimRadioStats for BLE and Classic.
let mut ble_stats_proto = ProtoRadioStats::new();
ble_stats_proto.set_duration_secs(duration_secs);
let mut classic_stats_proto = ble_stats_proto.clone();
// Obtain the Chip Information with get()
let chip_proto = self.get();
if chip_proto.has_bt() {
// Setting values for BLE Radio Stats
ble_stats_proto.set_kind(netsim_radio_stats::Kind::BLUETOOTH_LOW_ENERGY);
ble_stats_proto.set_tx_count(chip_proto.bt().low_energy.tx_count);
ble_stats_proto.set_rx_count(chip_proto.bt().low_energy.rx_count);
// Setting values for Classic Radio Stats
classic_stats_proto.set_kind(netsim_radio_stats::Kind::BLUETOOTH_CLASSIC);
classic_stats_proto.set_tx_count(chip_proto.bt().classic.tx_count);
classic_stats_proto.set_rx_count(chip_proto.bt().classic.rx_count);
}
vec![ble_stats_proto, classic_stats_proto]
}
fn get_kind(&self) -> ProtoChipKind {
ProtoChipKind::BLUETOOTH
}
fn get_facade_id(&self) -> RootcanalIdentifier {
self.rootcanal_id
}
}
/// Create a new Emulated Bluetooth Chip
pub fn new(
create_params: &CreateParams,
device_id: DeviceIdentifier,
chip_id: ChipIdentifier,
) -> SharedEmulatedChip {
// Lock to protect id_to_chip_info_ table in C++
let _unused = ECHIP_BT_MUTEX.lock().expect("Failed to acquire lock on ECHIP_BT_MUTEX");
let_cxx_string!(cxx_address = create_params.address.clone());
let proto_bytes = match &create_params.bt_properties {
Some(properties) => properties.write_to_bytes().unwrap(),
None => Vec::new(),
};
let rootcanal_id = ffi_bluetooth::bluetooth_add(device_id, chip_id, &cxx_address, &proto_bytes);
let echip = Bluetooth { rootcanal_id };
Arc::new(Box::new(echip))
}
/// Starts the Bluetooth service.
pub fn bluetooth_start(
config: &MessageField<BluetoothConfig>,
instance_num: u16,
disable_address_reuse: bool,
) {
let proto_bytes = config.as_ref().unwrap_or_default().write_to_bytes().unwrap();
ffi_bluetooth::bluetooth_start(&proto_bytes, instance_num, disable_address_reuse);
}
/// Stops the Bluetooth service.
pub fn bluetooth_stop() {
ffi_bluetooth::bluetooth_stop();
}