blob: b21a66e5218de4be3ab920f0c51673f9f381e4c9 [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.
/// A Chip is a generic emulated radio that connects to Chip Facade
/// library.
///
/// The chip facade is a library that implements the controller protocol.
///
use crate::devices::facades::FacadeIdentifier;
use crate::devices::facades::*;
use crate::devices::id_factory::IdFactory;
use frontend_proto::common::ChipKind as ProtoChipKind;
use frontend_proto::model::Chip as ProtoChip;
use lazy_static::lazy_static;
use protobuf::EnumOrUnknown;
use std::sync::RwLock;
use super::facades;
use crate::devices::device::DeviceIdentifier;
pub type ChipIdentifier = i32;
// Allocator for chip identifiers.
lazy_static! {
static ref IDS: RwLock<IdFactory<ChipIdentifier>> = RwLock::new(IdFactory::new(2000, 1));
}
pub struct Chip {
pub id: ChipIdentifier,
pub facade_id: FacadeIdentifier,
pub kind: ProtoChipKind,
pub name: String,
// TODO: may not be necessary
pub device_name: String,
// These are patchable
manufacturer: String,
product_name: String,
}
impl Chip {
fn new(
id: ChipIdentifier,
facade_id: FacadeIdentifier,
kind: ProtoChipKind,
name: &str,
device_name: &str,
manufacturer: &str,
product_name: &str,
) -> Self {
Self {
id,
facade_id,
kind,
name: name.to_string(),
device_name: device_name.to_string(),
manufacturer: manufacturer.to_string(),
product_name: product_name.to_string(),
}
}
/// Create the model protobuf
pub fn get(&self) -> ProtoChip {
let mut chip = ProtoChip::new();
chip.kind = EnumOrUnknown::new(self.kind);
chip.id = self.id;
chip.name = self.name.clone();
chip.manufacturer = self.manufacturer.clone();
chip.product_name = self.product_name.clone();
match chip.kind.enum_value() {
Ok(ProtoChipKind::BLUETOOTH) => {
chip.set_bt(hci_get(self.facade_id));
}
Ok(ProtoChipKind::WIFI) => {
chip.set_wifi(wifi_get(self.facade_id));
}
_ => {
eprint!("Unknown chip kind: {:?}", chip.kind);
}
}
chip
}
/// Patch processing for the chip. Validate and move state from the patch
/// into the chip changing the ChipFacade as needed.
pub fn patch(&mut self, patch: &ProtoChip) {
if !patch.manufacturer.is_empty() {
self.manufacturer = patch.manufacturer.clone();
}
if !patch.product_name.is_empty() {
self.product_name = patch.product_name.clone();
}
// Check both ChipKind and RadioKind fields, they should be consistent
if self.kind == ProtoChipKind::BLUETOOTH && patch.has_bt() {
facades::hci_patch(self.facade_id, patch.bt());
} else if self.kind == ProtoChipKind::WIFI && patch.has_wifi() {
wifi_patch(self.facade_id, patch.wifi());
} else {
eprint!("Unknown chip kind or missing radio: {:?}", self.kind);
}
}
pub fn remove(&mut self) {
match self.kind {
ProtoChipKind::BLUETOOTH => {
hci_remove(self.facade_id);
}
ProtoChipKind::WIFI => {
wifi_remove(self.facade_id);
}
_ => {
eprint!("Unknown chip kind: {:?}", self.kind);
}
}
}
pub fn reset(&mut self) {
match self.kind {
ProtoChipKind::BLUETOOTH => {
hci_reset(self.facade_id);
}
ProtoChipKind::WIFI => {
wifi_reset(self.facade_id);
}
_ => {
eprint!("Unknown chip kind: {:?}", self.kind);
}
}
}
}
/// Allocates a new chip with a facade_id.
pub fn chip_new(
device_id: DeviceIdentifier,
chip_kind: ProtoChipKind,
chip_name: &str,
device_name: &str,
chip_manufacturer: &str,
chip_product_name: &str,
) -> Chip {
let id = IDS.write().unwrap().next_id();
let facade_id = match chip_kind {
ProtoChipKind::BLUETOOTH => facades::hci_add(device_id),
ProtoChipKind::WIFI => facades::wifi_add(device_id),
_ => {
panic!("Unknown chip kind: {:?}", chip_kind);
}
};
Chip::new(
id,
facade_id,
chip_kind,
chip_name,
device_name,
chip_manufacturer,
chip_product_name,
)
}