xref: /aosp_15_r20/tools/netsim/rust/daemon/src/wireless/uwb.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 bytes::Bytes;
16*cf78ab8cSAndroid Build Coastguard Worker use futures::{channel::mpsc::UnboundedSender, sink::SinkExt, StreamExt};
17*cf78ab8cSAndroid Build Coastguard Worker use pica::{Handle, Pica};
18*cf78ab8cSAndroid Build Coastguard Worker 
19*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::Radio as ProtoRadio;
20*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::Chip as ProtoChip;
21*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats};
22*cf78ab8cSAndroid Build Coastguard Worker 
23*cf78ab8cSAndroid Build Coastguard Worker use crate::devices::chip::ChipIdentifier;
24*cf78ab8cSAndroid Build Coastguard Worker use crate::uwb::ranging_estimator::{SharedState, UwbRangingEstimator};
25*cf78ab8cSAndroid Build Coastguard Worker use crate::wireless::packet::handle_response;
26*cf78ab8cSAndroid Build Coastguard Worker 
27*cf78ab8cSAndroid Build Coastguard Worker use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
28*cf78ab8cSAndroid Build Coastguard Worker use std::sync::{Arc, Mutex, OnceLock};
29*cf78ab8cSAndroid Build Coastguard Worker use std::thread;
30*cf78ab8cSAndroid Build Coastguard Worker 
31*cf78ab8cSAndroid Build Coastguard Worker use super::{WirelessAdaptor, WirelessAdaptorImpl};
32*cf78ab8cSAndroid Build Coastguard Worker 
33*cf78ab8cSAndroid Build Coastguard Worker // TODO(b/331267949): Construct Manager struct for each wireless_adaptor module
34*cf78ab8cSAndroid Build Coastguard Worker static PICA_HANDLE_TO_STATE: OnceLock<SharedState> = OnceLock::new();
35*cf78ab8cSAndroid Build Coastguard Worker 
get_pica_handle_to_state() -> &'static SharedState36*cf78ab8cSAndroid Build Coastguard Worker fn get_pica_handle_to_state() -> &'static SharedState {
37*cf78ab8cSAndroid Build Coastguard Worker     PICA_HANDLE_TO_STATE.get_or_init(SharedState::new)
38*cf78ab8cSAndroid Build Coastguard Worker }
39*cf78ab8cSAndroid Build Coastguard Worker 
40*cf78ab8cSAndroid Build Coastguard Worker static PICA: OnceLock<Arc<Mutex<Pica>>> = OnceLock::new();
41*cf78ab8cSAndroid Build Coastguard Worker 
get_pica() -> Arc<Mutex<Pica>>42*cf78ab8cSAndroid Build Coastguard Worker fn get_pica() -> Arc<Mutex<Pica>> {
43*cf78ab8cSAndroid Build Coastguard Worker     PICA.get_or_init(|| {
44*cf78ab8cSAndroid Build Coastguard Worker         Arc::new(Mutex::new(Pica::new(
45*cf78ab8cSAndroid Build Coastguard Worker             Box::new(UwbRangingEstimator::new(get_pica_handle_to_state().clone())),
46*cf78ab8cSAndroid Build Coastguard Worker             None,
47*cf78ab8cSAndroid Build Coastguard Worker         )))
48*cf78ab8cSAndroid Build Coastguard Worker     })
49*cf78ab8cSAndroid Build Coastguard Worker     .clone()
50*cf78ab8cSAndroid Build Coastguard Worker }
51*cf78ab8cSAndroid Build Coastguard Worker 
52*cf78ab8cSAndroid Build Coastguard Worker static PICA_RUNTIME: OnceLock<Arc<tokio::runtime::Runtime>> = OnceLock::new();
53*cf78ab8cSAndroid Build Coastguard Worker 
get_pica_runtime() -> Arc<tokio::runtime::Runtime>54*cf78ab8cSAndroid Build Coastguard Worker fn get_pica_runtime() -> Arc<tokio::runtime::Runtime> {
55*cf78ab8cSAndroid Build Coastguard Worker     PICA_RUNTIME.get_or_init(|| Arc::new(tokio::runtime::Runtime::new().unwrap())).clone()
56*cf78ab8cSAndroid Build Coastguard Worker }
57*cf78ab8cSAndroid Build Coastguard Worker 
58*cf78ab8cSAndroid Build Coastguard Worker /// Parameters for creating UWB chips
59*cf78ab8cSAndroid Build Coastguard Worker pub struct CreateParams {
60*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
61*cf78ab8cSAndroid Build Coastguard Worker     pub address: String,
62*cf78ab8cSAndroid Build Coastguard Worker }
63*cf78ab8cSAndroid Build Coastguard Worker 
64*cf78ab8cSAndroid Build Coastguard Worker /// UWB struct will keep track of pica_id
65*cf78ab8cSAndroid Build Coastguard Worker pub struct Uwb {
66*cf78ab8cSAndroid Build Coastguard Worker     pica_id: Handle,
67*cf78ab8cSAndroid Build Coastguard Worker     uci_stream_writer: UnboundedSender<Vec<u8>>,
68*cf78ab8cSAndroid Build Coastguard Worker     state: AtomicBool,
69*cf78ab8cSAndroid Build Coastguard Worker     tx_count: AtomicI32,
70*cf78ab8cSAndroid Build Coastguard Worker     rx_count: Arc<AtomicI32>,
71*cf78ab8cSAndroid Build Coastguard Worker }
72*cf78ab8cSAndroid Build Coastguard Worker 
73*cf78ab8cSAndroid Build Coastguard Worker impl Drop for Uwb {
drop(&mut self)74*cf78ab8cSAndroid Build Coastguard Worker     fn drop(&mut self) {
75*cf78ab8cSAndroid Build Coastguard Worker         get_pica_handle_to_state().remove(&self.pica_id);
76*cf78ab8cSAndroid Build Coastguard Worker     }
77*cf78ab8cSAndroid Build Coastguard Worker }
78*cf78ab8cSAndroid Build Coastguard Worker 
79*cf78ab8cSAndroid Build Coastguard Worker impl WirelessAdaptor for Uwb {
handle_request(&self, packet: &Bytes)80*cf78ab8cSAndroid Build Coastguard Worker     fn handle_request(&self, packet: &Bytes) {
81*cf78ab8cSAndroid Build Coastguard Worker         // TODO(b/330788870): Increment tx_count
82*cf78ab8cSAndroid Build Coastguard Worker         self.uci_stream_writer
83*cf78ab8cSAndroid Build Coastguard Worker             .unbounded_send(packet.clone().into())
84*cf78ab8cSAndroid Build Coastguard Worker             .expect("UciStream Receiver Disconnected");
85*cf78ab8cSAndroid Build Coastguard Worker         let _ = self.tx_count.fetch_add(1, Ordering::SeqCst);
86*cf78ab8cSAndroid Build Coastguard Worker     }
87*cf78ab8cSAndroid Build Coastguard Worker 
reset(&self)88*cf78ab8cSAndroid Build Coastguard Worker     fn reset(&self) {
89*cf78ab8cSAndroid Build Coastguard Worker         self.state.store(true, Ordering::SeqCst);
90*cf78ab8cSAndroid Build Coastguard Worker         self.tx_count.store(0, Ordering::SeqCst);
91*cf78ab8cSAndroid Build Coastguard Worker         self.rx_count.store(0, Ordering::SeqCst);
92*cf78ab8cSAndroid Build Coastguard Worker     }
93*cf78ab8cSAndroid Build Coastguard Worker 
get(&self) -> ProtoChip94*cf78ab8cSAndroid Build Coastguard Worker     fn get(&self) -> ProtoChip {
95*cf78ab8cSAndroid Build Coastguard Worker         let mut chip_proto = ProtoChip::new();
96*cf78ab8cSAndroid Build Coastguard Worker         let uwb_proto = ProtoRadio {
97*cf78ab8cSAndroid Build Coastguard Worker             state: self.state.load(Ordering::SeqCst).into(),
98*cf78ab8cSAndroid Build Coastguard Worker             tx_count: self.tx_count.load(Ordering::SeqCst),
99*cf78ab8cSAndroid Build Coastguard Worker             rx_count: self.rx_count.load(Ordering::SeqCst),
100*cf78ab8cSAndroid Build Coastguard Worker             ..Default::default()
101*cf78ab8cSAndroid Build Coastguard Worker         };
102*cf78ab8cSAndroid Build Coastguard Worker         chip_proto.mut_uwb().clone_from(&uwb_proto);
103*cf78ab8cSAndroid Build Coastguard Worker         chip_proto
104*cf78ab8cSAndroid Build Coastguard Worker     }
105*cf78ab8cSAndroid Build Coastguard Worker 
patch(&self, chip: &ProtoChip)106*cf78ab8cSAndroid Build Coastguard Worker     fn patch(&self, chip: &ProtoChip) {
107*cf78ab8cSAndroid Build Coastguard Worker         if !chip.has_uwb() {
108*cf78ab8cSAndroid Build Coastguard Worker             return;
109*cf78ab8cSAndroid Build Coastguard Worker         }
110*cf78ab8cSAndroid Build Coastguard Worker         if let Some(patch_state) = chip.uwb().state {
111*cf78ab8cSAndroid Build Coastguard Worker             self.state.store(patch_state, Ordering::SeqCst);
112*cf78ab8cSAndroid Build Coastguard Worker         }
113*cf78ab8cSAndroid Build Coastguard Worker     }
114*cf78ab8cSAndroid Build Coastguard Worker 
get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats>115*cf78ab8cSAndroid Build Coastguard Worker     fn get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats> {
116*cf78ab8cSAndroid Build Coastguard Worker         let mut stats_proto = ProtoRadioStats::new();
117*cf78ab8cSAndroid Build Coastguard Worker         stats_proto.set_duration_secs(duration_secs);
118*cf78ab8cSAndroid Build Coastguard Worker         stats_proto.set_kind(netsim_radio_stats::Kind::UWB);
119*cf78ab8cSAndroid Build Coastguard Worker         let chip_proto = self.get();
120*cf78ab8cSAndroid Build Coastguard Worker         if chip_proto.has_uwb() {
121*cf78ab8cSAndroid Build Coastguard Worker             stats_proto.set_tx_count(chip_proto.uwb().tx_count);
122*cf78ab8cSAndroid Build Coastguard Worker             stats_proto.set_rx_count(chip_proto.uwb().rx_count);
123*cf78ab8cSAndroid Build Coastguard Worker         }
124*cf78ab8cSAndroid Build Coastguard Worker         vec![stats_proto]
125*cf78ab8cSAndroid Build Coastguard Worker     }
126*cf78ab8cSAndroid Build Coastguard Worker }
127*cf78ab8cSAndroid Build Coastguard Worker 
uwb_start()128*cf78ab8cSAndroid Build Coastguard Worker pub fn uwb_start() {
129*cf78ab8cSAndroid Build Coastguard Worker     // TODO: Provide TcpStream as UWB connector
130*cf78ab8cSAndroid Build Coastguard Worker     let _ = thread::Builder::new().name("pica_service".to_string()).spawn(move || {
131*cf78ab8cSAndroid Build Coastguard Worker         log::info!("PICA STARTED");
132*cf78ab8cSAndroid Build Coastguard Worker         let _guard = get_pica_runtime().enter();
133*cf78ab8cSAndroid Build Coastguard Worker         futures::executor::block_on(pica::run(&get_pica()))
134*cf78ab8cSAndroid Build Coastguard Worker     });
135*cf78ab8cSAndroid Build Coastguard Worker }
136*cf78ab8cSAndroid Build Coastguard Worker 
new(_create_params: &CreateParams, chip_id: ChipIdentifier) -> WirelessAdaptorImpl137*cf78ab8cSAndroid Build Coastguard Worker pub fn new(_create_params: &CreateParams, chip_id: ChipIdentifier) -> WirelessAdaptorImpl {
138*cf78ab8cSAndroid Build Coastguard Worker     let (uci_stream_sender, uci_stream_receiver) = futures::channel::mpsc::unbounded();
139*cf78ab8cSAndroid Build Coastguard Worker     let (uci_sink_sender, uci_sink_receiver) = futures::channel::mpsc::unbounded();
140*cf78ab8cSAndroid Build Coastguard Worker     let _guard = get_pica_runtime().enter();
141*cf78ab8cSAndroid Build Coastguard Worker     let pica_id = get_pica()
142*cf78ab8cSAndroid Build Coastguard Worker         .lock()
143*cf78ab8cSAndroid Build Coastguard Worker         .unwrap()
144*cf78ab8cSAndroid Build Coastguard Worker         .add_device(Box::pin(uci_stream_receiver), Box::pin(uci_sink_sender.sink_err_into()))
145*cf78ab8cSAndroid Build Coastguard Worker         .unwrap();
146*cf78ab8cSAndroid Build Coastguard Worker     get_pica_handle_to_state().insert(pica_id, chip_id);
147*cf78ab8cSAndroid Build Coastguard Worker 
148*cf78ab8cSAndroid Build Coastguard Worker     let rx_count = Arc::new(AtomicI32::new(0));
149*cf78ab8cSAndroid Build Coastguard Worker     let uwb = Uwb {
150*cf78ab8cSAndroid Build Coastguard Worker         pica_id,
151*cf78ab8cSAndroid Build Coastguard Worker         uci_stream_writer: uci_stream_sender,
152*cf78ab8cSAndroid Build Coastguard Worker         state: AtomicBool::new(true),
153*cf78ab8cSAndroid Build Coastguard Worker         tx_count: AtomicI32::new(0),
154*cf78ab8cSAndroid Build Coastguard Worker         rx_count: rx_count.clone(),
155*cf78ab8cSAndroid Build Coastguard Worker     };
156*cf78ab8cSAndroid Build Coastguard Worker 
157*cf78ab8cSAndroid Build Coastguard Worker     // Spawn a future for obtaining packet from pica and invoking handle_response_rust
158*cf78ab8cSAndroid Build Coastguard Worker     get_pica_runtime().spawn(async move {
159*cf78ab8cSAndroid Build Coastguard Worker         let mut uci_sink_receiver = uci_sink_receiver;
160*cf78ab8cSAndroid Build Coastguard Worker         while let Some(packet) = uci_sink_receiver.next().await {
161*cf78ab8cSAndroid Build Coastguard Worker             handle_response(chip_id, &Bytes::from(packet));
162*cf78ab8cSAndroid Build Coastguard Worker             rx_count.fetch_add(1, Ordering::SeqCst);
163*cf78ab8cSAndroid Build Coastguard Worker         }
164*cf78ab8cSAndroid Build Coastguard Worker     });
165*cf78ab8cSAndroid Build Coastguard Worker     Box::new(uwb)
166*cf78ab8cSAndroid Build Coastguard Worker }
167*cf78ab8cSAndroid Build Coastguard Worker 
168*cf78ab8cSAndroid Build Coastguard Worker #[cfg(test)]
169*cf78ab8cSAndroid Build Coastguard Worker mod tests {
170*cf78ab8cSAndroid Build Coastguard Worker 
171*cf78ab8cSAndroid Build Coastguard Worker     use super::*;
172*cf78ab8cSAndroid Build Coastguard Worker 
new_uwb_wireless_adaptor() -> WirelessAdaptorImpl173*cf78ab8cSAndroid Build Coastguard Worker     fn new_uwb_wireless_adaptor() -> WirelessAdaptorImpl {
174*cf78ab8cSAndroid Build Coastguard Worker         new(&CreateParams { address: "test".to_string() }, ChipIdentifier(0))
175*cf78ab8cSAndroid Build Coastguard Worker     }
176*cf78ab8cSAndroid Build Coastguard Worker 
patch_chip_proto() -> ProtoChip177*cf78ab8cSAndroid Build Coastguard Worker     fn patch_chip_proto() -> ProtoChip {
178*cf78ab8cSAndroid Build Coastguard Worker         let mut chip_proto = ProtoChip::new();
179*cf78ab8cSAndroid Build Coastguard Worker         let uwb_proto = ProtoRadio { state: false.into(), ..Default::default() };
180*cf78ab8cSAndroid Build Coastguard Worker         chip_proto.mut_uwb().clone_from(&uwb_proto);
181*cf78ab8cSAndroid Build Coastguard Worker         chip_proto
182*cf78ab8cSAndroid Build Coastguard Worker     }
183*cf78ab8cSAndroid Build Coastguard Worker 
184*cf78ab8cSAndroid Build Coastguard Worker     #[test]
test_uwb_get()185*cf78ab8cSAndroid Build Coastguard Worker     fn test_uwb_get() {
186*cf78ab8cSAndroid Build Coastguard Worker         let wireless_adaptor = new_uwb_wireless_adaptor();
187*cf78ab8cSAndroid Build Coastguard Worker         assert!(wireless_adaptor.get().has_uwb());
188*cf78ab8cSAndroid Build Coastguard Worker     }
189*cf78ab8cSAndroid Build Coastguard Worker 
190*cf78ab8cSAndroid Build Coastguard Worker     #[test]
test_uwb_patch_and_reset()191*cf78ab8cSAndroid Build Coastguard Worker     fn test_uwb_patch_and_reset() {
192*cf78ab8cSAndroid Build Coastguard Worker         let wireless_adaptor = new_uwb_wireless_adaptor();
193*cf78ab8cSAndroid Build Coastguard Worker         wireless_adaptor.patch(&patch_chip_proto());
194*cf78ab8cSAndroid Build Coastguard Worker         let binding = wireless_adaptor.get();
195*cf78ab8cSAndroid Build Coastguard Worker         let radio = binding.uwb();
196*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(radio.state, Some(false));
197*cf78ab8cSAndroid Build Coastguard Worker         wireless_adaptor.reset();
198*cf78ab8cSAndroid Build Coastguard Worker         let binding = wireless_adaptor.get();
199*cf78ab8cSAndroid Build Coastguard Worker         let radio = binding.uwb();
200*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(radio.rx_count, 0);
201*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(radio.tx_count, 0);
202*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(radio.state, Some(true));
203*cf78ab8cSAndroid Build Coastguard Worker     }
204*cf78ab8cSAndroid Build Coastguard Worker 
205*cf78ab8cSAndroid Build Coastguard Worker     #[test]
test_get_stats()206*cf78ab8cSAndroid Build Coastguard Worker     fn test_get_stats() {
207*cf78ab8cSAndroid Build Coastguard Worker         let wireless_adaptor = new_uwb_wireless_adaptor();
208*cf78ab8cSAndroid Build Coastguard Worker         let radio_stat_vec = wireless_adaptor.get_stats(0);
209*cf78ab8cSAndroid Build Coastguard Worker         let radio_stat = radio_stat_vec.first().unwrap();
210*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(radio_stat.kind(), netsim_radio_stats::Kind::UWB);
211*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(radio_stat.duration_secs(), 0);
212*cf78ab8cSAndroid Build Coastguard Worker     }
213*cf78ab8cSAndroid Build Coastguard Worker }
214