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