xref: /aosp_15_r20/system/nfc/src/rust/hal/hal.rs (revision 7eba2f3b06c51ae21384f6a4f14577b668a869b3)
1*7eba2f3bSAndroid Build Coastguard Worker // Copyright 2021, The Android Open Source Project
2*7eba2f3bSAndroid Build Coastguard Worker //
3*7eba2f3bSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*7eba2f3bSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*7eba2f3bSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*7eba2f3bSAndroid Build Coastguard Worker //
7*7eba2f3bSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*7eba2f3bSAndroid Build Coastguard Worker //
9*7eba2f3bSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*7eba2f3bSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*7eba2f3bSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*7eba2f3bSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*7eba2f3bSAndroid Build Coastguard Worker // limitations under the License.
14*7eba2f3bSAndroid Build Coastguard Worker 
15*7eba2f3bSAndroid Build Coastguard Worker //! NCI Hardware Abstraction Layer
16*7eba2f3bSAndroid Build Coastguard Worker //! Supports sending NCI commands to the HAL and receiving
17*7eba2f3bSAndroid Build Coastguard Worker //! NCI events from the HAL
18*7eba2f3bSAndroid Build Coastguard Worker 
19*7eba2f3bSAndroid Build Coastguard Worker use nfc_packets::nci::{DataPacket, NciPacket};
20*7eba2f3bSAndroid Build Coastguard Worker use std::collections::HashMap;
21*7eba2f3bSAndroid Build Coastguard Worker use std::sync::Arc;
22*7eba2f3bSAndroid Build Coastguard Worker use thiserror::Error;
23*7eba2f3bSAndroid Build Coastguard Worker use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
24*7eba2f3bSAndroid Build Coastguard Worker use tokio::sync::{oneshot, Mutex};
25*7eba2f3bSAndroid Build Coastguard Worker 
26*7eba2f3bSAndroid Build Coastguard Worker #[cfg(target_os = "android")]
27*7eba2f3bSAndroid Build Coastguard Worker #[path = "hidl_hal.rs"]
28*7eba2f3bSAndroid Build Coastguard Worker pub mod ihal;
29*7eba2f3bSAndroid Build Coastguard Worker 
30*7eba2f3bSAndroid Build Coastguard Worker #[cfg(not(target_os = "android"))]
31*7eba2f3bSAndroid Build Coastguard Worker #[path = "rootcanal_hal.rs"]
32*7eba2f3bSAndroid Build Coastguard Worker pub mod ihal;
33*7eba2f3bSAndroid Build Coastguard Worker 
34*7eba2f3bSAndroid Build Coastguard Worker /// HAL module interface
35*7eba2f3bSAndroid Build Coastguard Worker pub struct Hal {
36*7eba2f3bSAndroid Build Coastguard Worker     /// HAL events
37*7eba2f3bSAndroid Build Coastguard Worker     pub hal_events: HalEventRegistry,
38*7eba2f3bSAndroid Build Coastguard Worker     /// HAL outbound channel for Command messages
39*7eba2f3bSAndroid Build Coastguard Worker     pub out_cmd_tx: UnboundedSender<NciPacket>,
40*7eba2f3bSAndroid Build Coastguard Worker     /// HAL inbound channel for Response and Notification messages
41*7eba2f3bSAndroid Build Coastguard Worker     pub in_cmd_rx: UnboundedReceiver<NciPacket>,
42*7eba2f3bSAndroid Build Coastguard Worker     /// HAL outbound channel for Data messages
43*7eba2f3bSAndroid Build Coastguard Worker     pub out_data_tx: UnboundedSender<DataPacket>,
44*7eba2f3bSAndroid Build Coastguard Worker     /// HAL inbound channel for Data messages
45*7eba2f3bSAndroid Build Coastguard Worker     pub in_data_rx: UnboundedReceiver<DataPacket>,
46*7eba2f3bSAndroid Build Coastguard Worker }
47*7eba2f3bSAndroid Build Coastguard Worker 
48*7eba2f3bSAndroid Build Coastguard Worker /// Initialize the module and connect the channels
init() -> Hal49*7eba2f3bSAndroid Build Coastguard Worker pub async fn init() -> Hal {
50*7eba2f3bSAndroid Build Coastguard Worker     ihal::init().await
51*7eba2f3bSAndroid Build Coastguard Worker }
52*7eba2f3bSAndroid Build Coastguard Worker 
53*7eba2f3bSAndroid Build Coastguard Worker /// NFC HAL specific events
54*7eba2f3bSAndroid Build Coastguard Worker #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
55*7eba2f3bSAndroid Build Coastguard Worker pub enum HalEvent {
56*7eba2f3bSAndroid Build Coastguard Worker     /// HAL CLOSE_CPLT event
57*7eba2f3bSAndroid Build Coastguard Worker     CloseComplete,
58*7eba2f3bSAndroid Build Coastguard Worker }
59*7eba2f3bSAndroid Build Coastguard Worker 
60*7eba2f3bSAndroid Build Coastguard Worker /// Status of a NFC HAL event
61*7eba2f3bSAndroid Build Coastguard Worker #[derive(Debug)]
62*7eba2f3bSAndroid Build Coastguard Worker pub enum HalEventStatus {
63*7eba2f3bSAndroid Build Coastguard Worker     /// HAL OK status
64*7eba2f3bSAndroid Build Coastguard Worker     Success,
65*7eba2f3bSAndroid Build Coastguard Worker     /// HAL FAILED status
66*7eba2f3bSAndroid Build Coastguard Worker     Failed,
67*7eba2f3bSAndroid Build Coastguard Worker     /// HAL ERR_TRANSPORT status
68*7eba2f3bSAndroid Build Coastguard Worker     TransportError,
69*7eba2f3bSAndroid Build Coastguard Worker     /// HAL ERR_CMD_TIMEOUT status
70*7eba2f3bSAndroid Build Coastguard Worker     Timeout,
71*7eba2f3bSAndroid Build Coastguard Worker     /// HAL REFUSED status
72*7eba2f3bSAndroid Build Coastguard Worker     Refused,
73*7eba2f3bSAndroid Build Coastguard Worker }
74*7eba2f3bSAndroid Build Coastguard Worker 
75*7eba2f3bSAndroid Build Coastguard Worker /// Provides ability to register and unregister for HAL event notifications
76*7eba2f3bSAndroid Build Coastguard Worker #[derive(Clone)]
77*7eba2f3bSAndroid Build Coastguard Worker pub struct HalEventRegistry {
78*7eba2f3bSAndroid Build Coastguard Worker     handlers: Arc<Mutex<HashMap<HalEvent, oneshot::Sender<HalEventStatus>>>>,
79*7eba2f3bSAndroid Build Coastguard Worker }
80*7eba2f3bSAndroid Build Coastguard Worker 
81*7eba2f3bSAndroid Build Coastguard Worker impl HalEventRegistry {
82*7eba2f3bSAndroid Build Coastguard Worker     /// Indicate interest in specific HAL event
register(&mut self, event: HalEvent, sender: oneshot::Sender<HalEventStatus>)83*7eba2f3bSAndroid Build Coastguard Worker     pub async fn register(&mut self, event: HalEvent, sender: oneshot::Sender<HalEventStatus>) {
84*7eba2f3bSAndroid Build Coastguard Worker         assert!(
85*7eba2f3bSAndroid Build Coastguard Worker             self.handlers.lock().await.insert(event, sender).is_none(),
86*7eba2f3bSAndroid Build Coastguard Worker             "A handler for {:?} is already registered",
87*7eba2f3bSAndroid Build Coastguard Worker             event
88*7eba2f3bSAndroid Build Coastguard Worker         );
89*7eba2f3bSAndroid Build Coastguard Worker     }
90*7eba2f3bSAndroid Build Coastguard Worker 
91*7eba2f3bSAndroid Build Coastguard Worker     /// Remove interest in specific HAL event
unregister(&mut self, event: HalEvent) -> Option<oneshot::Sender<HalEventStatus>>92*7eba2f3bSAndroid Build Coastguard Worker     pub async fn unregister(&mut self, event: HalEvent) -> Option<oneshot::Sender<HalEventStatus>> {
93*7eba2f3bSAndroid Build Coastguard Worker         self.handlers.lock().await.remove(&event)
94*7eba2f3bSAndroid Build Coastguard Worker     }
95*7eba2f3bSAndroid Build Coastguard Worker }
96*7eba2f3bSAndroid Build Coastguard Worker 
97*7eba2f3bSAndroid Build Coastguard Worker mod internal {
98*7eba2f3bSAndroid Build Coastguard Worker     use crate::{Hal, HalEventRegistry};
99*7eba2f3bSAndroid Build Coastguard Worker     use nfc_packets::nci::{DataPacket, NciPacket};
100*7eba2f3bSAndroid Build Coastguard Worker     use std::collections::HashMap;
101*7eba2f3bSAndroid Build Coastguard Worker     use std::sync::Arc;
102*7eba2f3bSAndroid Build Coastguard Worker     use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
103*7eba2f3bSAndroid Build Coastguard Worker     use tokio::sync::Mutex;
104*7eba2f3bSAndroid Build Coastguard Worker 
105*7eba2f3bSAndroid Build Coastguard Worker     pub struct InnerHal {
106*7eba2f3bSAndroid Build Coastguard Worker         pub out_cmd_rx: UnboundedReceiver<NciPacket>,
107*7eba2f3bSAndroid Build Coastguard Worker         pub in_cmd_tx: UnboundedSender<NciPacket>,
108*7eba2f3bSAndroid Build Coastguard Worker         pub out_data_rx: UnboundedReceiver<DataPacket>,
109*7eba2f3bSAndroid Build Coastguard Worker         pub in_data_tx: UnboundedSender<DataPacket>,
110*7eba2f3bSAndroid Build Coastguard Worker     }
111*7eba2f3bSAndroid Build Coastguard Worker 
112*7eba2f3bSAndroid Build Coastguard Worker     impl InnerHal {
new() -> (Hal, Self)113*7eba2f3bSAndroid Build Coastguard Worker         pub fn new() -> (Hal, Self) {
114*7eba2f3bSAndroid Build Coastguard Worker             let (out_cmd_tx, out_cmd_rx) = unbounded_channel();
115*7eba2f3bSAndroid Build Coastguard Worker             let (in_cmd_tx, in_cmd_rx) = unbounded_channel();
116*7eba2f3bSAndroid Build Coastguard Worker             let (out_data_tx, out_data_rx) = unbounded_channel();
117*7eba2f3bSAndroid Build Coastguard Worker             let (in_data_tx, in_data_rx) = unbounded_channel();
118*7eba2f3bSAndroid Build Coastguard Worker             let handlers = Arc::new(Mutex::new(HashMap::new()));
119*7eba2f3bSAndroid Build Coastguard Worker             let hal_events = HalEventRegistry { handlers };
120*7eba2f3bSAndroid Build Coastguard Worker             (
121*7eba2f3bSAndroid Build Coastguard Worker                 Hal { hal_events, out_cmd_tx, in_cmd_rx, out_data_tx, in_data_rx },
122*7eba2f3bSAndroid Build Coastguard Worker                 Self { out_cmd_rx, in_cmd_tx, out_data_rx, in_data_tx },
123*7eba2f3bSAndroid Build Coastguard Worker             )
124*7eba2f3bSAndroid Build Coastguard Worker         }
125*7eba2f3bSAndroid Build Coastguard Worker     }
126*7eba2f3bSAndroid Build Coastguard Worker }
127*7eba2f3bSAndroid Build Coastguard Worker 
128*7eba2f3bSAndroid Build Coastguard Worker /// Is this NCI control stream or data response
is_control_packet(data: &[u8]) -> bool129*7eba2f3bSAndroid Build Coastguard Worker pub fn is_control_packet(data: &[u8]) -> bool {
130*7eba2f3bSAndroid Build Coastguard Worker     // Check the MT bits
131*7eba2f3bSAndroid Build Coastguard Worker     (data[0] >> 5) & 0x7 != 0
132*7eba2f3bSAndroid Build Coastguard Worker }
133*7eba2f3bSAndroid Build Coastguard Worker 
134*7eba2f3bSAndroid Build Coastguard Worker /// Result type
135*7eba2f3bSAndroid Build Coastguard Worker type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
136*7eba2f3bSAndroid Build Coastguard Worker 
137*7eba2f3bSAndroid Build Coastguard Worker /// Errors that can be encountered while dealing with the HAL
138*7eba2f3bSAndroid Build Coastguard Worker #[derive(Error, Debug)]
139*7eba2f3bSAndroid Build Coastguard Worker pub enum HalError {
140*7eba2f3bSAndroid Build Coastguard Worker     /// Invalid rootcanal host error
141*7eba2f3bSAndroid Build Coastguard Worker     #[error("Invalid rootcanal host")]
142*7eba2f3bSAndroid Build Coastguard Worker     InvalidAddressError,
143*7eba2f3bSAndroid Build Coastguard Worker     /// Error while connecting to rootcanal
144*7eba2f3bSAndroid Build Coastguard Worker     #[error("Connection to rootcanal failed: {0}")]
145*7eba2f3bSAndroid Build Coastguard Worker     RootcanalConnectError(#[from] tokio::io::Error),
146*7eba2f3bSAndroid Build Coastguard Worker }
147