xref: /aosp_15_r20/system/nfc/src/rust/hal/hidl_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 //! Implementation of the HAl that talks to NFC controller over Android's HIDL
16*7eba2f3bSAndroid Build Coastguard Worker use crate::internal::InnerHal;
17*7eba2f3bSAndroid Build Coastguard Worker #[allow(unused)]
18*7eba2f3bSAndroid Build Coastguard Worker use crate::{is_control_packet, Hal, HalEvent, HalEventRegistry, HalEventStatus, Result};
19*7eba2f3bSAndroid Build Coastguard Worker use log::{debug, error};
20*7eba2f3bSAndroid Build Coastguard Worker use nfc_packets::nci::{DataPacket, NciPacket};
21*7eba2f3bSAndroid Build Coastguard Worker use pdl_runtime::Packet;
22*7eba2f3bSAndroid Build Coastguard Worker use std::sync::Mutex;
23*7eba2f3bSAndroid Build Coastguard Worker use tokio::select;
24*7eba2f3bSAndroid Build Coastguard Worker use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
25*7eba2f3bSAndroid Build Coastguard Worker use tokio::sync::oneshot;
26*7eba2f3bSAndroid Build Coastguard Worker 
27*7eba2f3bSAndroid Build Coastguard Worker /// Initialize the module
init() -> Hal28*7eba2f3bSAndroid Build Coastguard Worker pub async fn init() -> Hal {
29*7eba2f3bSAndroid Build Coastguard Worker     let (raw_hal, inner_hal) = InnerHal::new();
30*7eba2f3bSAndroid Build Coastguard Worker     let (hal_open_evt_tx, hal_open_evt_rx) = oneshot::channel::<ffi::NfcStatus>();
31*7eba2f3bSAndroid Build Coastguard Worker     let (hal_close_evt_tx, hal_close_evt_rx) = oneshot::channel::<ffi::NfcStatus>();
32*7eba2f3bSAndroid Build Coastguard Worker     *CALLBACKS.lock().unwrap() = Some(Callbacks {
33*7eba2f3bSAndroid Build Coastguard Worker         hal_open_evt_tx: Some(hal_open_evt_tx),
34*7eba2f3bSAndroid Build Coastguard Worker         hal_close_evt_tx: Some(hal_close_evt_tx),
35*7eba2f3bSAndroid Build Coastguard Worker         in_cmd_tx: inner_hal.in_cmd_tx,
36*7eba2f3bSAndroid Build Coastguard Worker         in_data_tx: inner_hal.in_data_tx,
37*7eba2f3bSAndroid Build Coastguard Worker     });
38*7eba2f3bSAndroid Build Coastguard Worker     ffi::start_hal();
39*7eba2f3bSAndroid Build Coastguard Worker     hal_open_evt_rx.await.unwrap();
40*7eba2f3bSAndroid Build Coastguard Worker 
41*7eba2f3bSAndroid Build Coastguard Worker     tokio::spawn(dispatch_outgoing(
42*7eba2f3bSAndroid Build Coastguard Worker         raw_hal.hal_events.clone(),
43*7eba2f3bSAndroid Build Coastguard Worker         inner_hal.out_cmd_rx,
44*7eba2f3bSAndroid Build Coastguard Worker         inner_hal.out_data_rx,
45*7eba2f3bSAndroid Build Coastguard Worker         hal_close_evt_rx,
46*7eba2f3bSAndroid Build Coastguard Worker     ));
47*7eba2f3bSAndroid Build Coastguard Worker 
48*7eba2f3bSAndroid Build Coastguard Worker     raw_hal
49*7eba2f3bSAndroid Build Coastguard Worker }
50*7eba2f3bSAndroid Build Coastguard Worker 
51*7eba2f3bSAndroid Build Coastguard Worker #[cxx::bridge(namespace = nfc::hal)]
52*7eba2f3bSAndroid Build Coastguard Worker // TODO Either use or remove these functions, this shouldn't be the long term state
53*7eba2f3bSAndroid Build Coastguard Worker #[allow(dead_code)]
54*7eba2f3bSAndroid Build Coastguard Worker #[allow(unsafe_op_in_unsafe_fn)]
55*7eba2f3bSAndroid Build Coastguard Worker mod ffi {
56*7eba2f3bSAndroid Build Coastguard Worker 
57*7eba2f3bSAndroid Build Coastguard Worker     #[repr(u32)]
58*7eba2f3bSAndroid Build Coastguard Worker     #[derive(Debug)]
59*7eba2f3bSAndroid Build Coastguard Worker     enum NfcEvent {
60*7eba2f3bSAndroid Build Coastguard Worker         OPEN_CPLT = 0,
61*7eba2f3bSAndroid Build Coastguard Worker         CLOSE_CPLT = 1,
62*7eba2f3bSAndroid Build Coastguard Worker         POST_INIT_CPLT = 2,
63*7eba2f3bSAndroid Build Coastguard Worker         PRE_DISCOVER_CPLT = 3,
64*7eba2f3bSAndroid Build Coastguard Worker         REQUEST_CONTROL = 4,
65*7eba2f3bSAndroid Build Coastguard Worker         RELEASE_CONTROL = 5,
66*7eba2f3bSAndroid Build Coastguard Worker         ERROR = 6,
67*7eba2f3bSAndroid Build Coastguard Worker         HCI_NETWORK_RESET = 7,
68*7eba2f3bSAndroid Build Coastguard Worker     }
69*7eba2f3bSAndroid Build Coastguard Worker 
70*7eba2f3bSAndroid Build Coastguard Worker     #[repr(u32)]
71*7eba2f3bSAndroid Build Coastguard Worker     #[derive(Debug)]
72*7eba2f3bSAndroid Build Coastguard Worker     enum NfcStatus {
73*7eba2f3bSAndroid Build Coastguard Worker         OK = 0,
74*7eba2f3bSAndroid Build Coastguard Worker         FAILED = 1,
75*7eba2f3bSAndroid Build Coastguard Worker         ERR_TRANSPORT = 2,
76*7eba2f3bSAndroid Build Coastguard Worker         ERR_CMD_TIMEOUT = 3,
77*7eba2f3bSAndroid Build Coastguard Worker         REFUSED = 4,
78*7eba2f3bSAndroid Build Coastguard Worker     }
79*7eba2f3bSAndroid Build Coastguard Worker 
80*7eba2f3bSAndroid Build Coastguard Worker     unsafe extern "C++" {
81*7eba2f3bSAndroid Build Coastguard Worker         include!("hal/ffi/hidl.h");
start_hal()82*7eba2f3bSAndroid Build Coastguard Worker         fn start_hal();
stop_hal()83*7eba2f3bSAndroid Build Coastguard Worker         fn stop_hal();
send_command(data: &[u8])84*7eba2f3bSAndroid Build Coastguard Worker         fn send_command(data: &[u8]);
85*7eba2f3bSAndroid Build Coastguard Worker 
86*7eba2f3bSAndroid Build Coastguard Worker         #[namespace = "android::hardware::nfc::V1_1"]
87*7eba2f3bSAndroid Build Coastguard Worker         type NfcEvent;
88*7eba2f3bSAndroid Build Coastguard Worker 
89*7eba2f3bSAndroid Build Coastguard Worker         #[namespace = "android::hardware::nfc::V1_0"]
90*7eba2f3bSAndroid Build Coastguard Worker         type NfcStatus;
91*7eba2f3bSAndroid Build Coastguard Worker     }
92*7eba2f3bSAndroid Build Coastguard Worker 
93*7eba2f3bSAndroid Build Coastguard Worker     extern "Rust" {
on_event(evt: NfcEvent, status: NfcStatus)94*7eba2f3bSAndroid Build Coastguard Worker         fn on_event(evt: NfcEvent, status: NfcStatus);
on_data(data: &[u8])95*7eba2f3bSAndroid Build Coastguard Worker         fn on_data(data: &[u8]);
96*7eba2f3bSAndroid Build Coastguard Worker     }
97*7eba2f3bSAndroid Build Coastguard Worker }
98*7eba2f3bSAndroid Build Coastguard Worker 
99*7eba2f3bSAndroid Build Coastguard Worker impl From<ffi::NfcStatus> for HalEventStatus {
from(ffi_nfc_status: ffi::NfcStatus) -> Self100*7eba2f3bSAndroid Build Coastguard Worker     fn from(ffi_nfc_status: ffi::NfcStatus) -> Self {
101*7eba2f3bSAndroid Build Coastguard Worker         match ffi_nfc_status {
102*7eba2f3bSAndroid Build Coastguard Worker             ffi::NfcStatus::OK => HalEventStatus::Success,
103*7eba2f3bSAndroid Build Coastguard Worker             ffi::NfcStatus::FAILED => HalEventStatus::Failed,
104*7eba2f3bSAndroid Build Coastguard Worker             ffi::NfcStatus::ERR_TRANSPORT => HalEventStatus::TransportError,
105*7eba2f3bSAndroid Build Coastguard Worker             ffi::NfcStatus::ERR_CMD_TIMEOUT => HalEventStatus::Timeout,
106*7eba2f3bSAndroid Build Coastguard Worker             ffi::NfcStatus::REFUSED => HalEventStatus::Refused,
107*7eba2f3bSAndroid Build Coastguard Worker             _ => HalEventStatus::Failed,
108*7eba2f3bSAndroid Build Coastguard Worker         }
109*7eba2f3bSAndroid Build Coastguard Worker     }
110*7eba2f3bSAndroid Build Coastguard Worker }
111*7eba2f3bSAndroid Build Coastguard Worker 
112*7eba2f3bSAndroid Build Coastguard Worker struct Callbacks {
113*7eba2f3bSAndroid Build Coastguard Worker     hal_open_evt_tx: Option<oneshot::Sender<ffi::NfcStatus>>,
114*7eba2f3bSAndroid Build Coastguard Worker     hal_close_evt_tx: Option<oneshot::Sender<ffi::NfcStatus>>,
115*7eba2f3bSAndroid Build Coastguard Worker     in_cmd_tx: UnboundedSender<NciPacket>,
116*7eba2f3bSAndroid Build Coastguard Worker     in_data_tx: UnboundedSender<DataPacket>,
117*7eba2f3bSAndroid Build Coastguard Worker }
118*7eba2f3bSAndroid Build Coastguard Worker 
119*7eba2f3bSAndroid Build Coastguard Worker static CALLBACKS: Mutex<Option<Callbacks>> = Mutex::new(None);
120*7eba2f3bSAndroid Build Coastguard Worker 
on_event(evt: ffi::NfcEvent, status: ffi::NfcStatus)121*7eba2f3bSAndroid Build Coastguard Worker fn on_event(evt: ffi::NfcEvent, status: ffi::NfcStatus) {
122*7eba2f3bSAndroid Build Coastguard Worker     debug!("got event: {:?} with status {:?}", evt, status);
123*7eba2f3bSAndroid Build Coastguard Worker     let mut callbacks = CALLBACKS.lock().unwrap();
124*7eba2f3bSAndroid Build Coastguard Worker     match evt {
125*7eba2f3bSAndroid Build Coastguard Worker         ffi::NfcEvent::OPEN_CPLT => {
126*7eba2f3bSAndroid Build Coastguard Worker             if let Some(evt_tx) = callbacks.as_mut().unwrap().hal_open_evt_tx.take() {
127*7eba2f3bSAndroid Build Coastguard Worker                 evt_tx.send(status).unwrap();
128*7eba2f3bSAndroid Build Coastguard Worker             }
129*7eba2f3bSAndroid Build Coastguard Worker         }
130*7eba2f3bSAndroid Build Coastguard Worker         ffi::NfcEvent::CLOSE_CPLT => {
131*7eba2f3bSAndroid Build Coastguard Worker             if let Some(evt_tx) = callbacks.as_mut().unwrap().hal_close_evt_tx.take() {
132*7eba2f3bSAndroid Build Coastguard Worker                 evt_tx.send(status).unwrap();
133*7eba2f3bSAndroid Build Coastguard Worker             }
134*7eba2f3bSAndroid Build Coastguard Worker         }
135*7eba2f3bSAndroid Build Coastguard Worker         _ => error!("Unhandled HAL event {:?}", evt),
136*7eba2f3bSAndroid Build Coastguard Worker     }
137*7eba2f3bSAndroid Build Coastguard Worker }
138*7eba2f3bSAndroid Build Coastguard Worker 
on_data(data: &[u8])139*7eba2f3bSAndroid Build Coastguard Worker fn on_data(data: &[u8]) {
140*7eba2f3bSAndroid Build Coastguard Worker     debug!("got packet: {:02x?}", data);
141*7eba2f3bSAndroid Build Coastguard Worker     let callbacks = CALLBACKS.lock().unwrap();
142*7eba2f3bSAndroid Build Coastguard Worker     if is_control_packet(data) {
143*7eba2f3bSAndroid Build Coastguard Worker         match NciPacket::parse(data) {
144*7eba2f3bSAndroid Build Coastguard Worker             Ok(p) => callbacks.as_ref().unwrap().in_cmd_tx.send(p).unwrap(),
145*7eba2f3bSAndroid Build Coastguard Worker             Err(e) => error!("failure to parse response: {:?} data: {:02x?}", e, data),
146*7eba2f3bSAndroid Build Coastguard Worker         }
147*7eba2f3bSAndroid Build Coastguard Worker     } else {
148*7eba2f3bSAndroid Build Coastguard Worker         match DataPacket::parse(data) {
149*7eba2f3bSAndroid Build Coastguard Worker             Ok(p) => callbacks.as_ref().unwrap().in_data_tx.send(p).unwrap(),
150*7eba2f3bSAndroid Build Coastguard Worker             Err(e) => error!("failure to parse response: {:?} data: {:02x?}", e, data),
151*7eba2f3bSAndroid Build Coastguard Worker         }
152*7eba2f3bSAndroid Build Coastguard Worker     }
153*7eba2f3bSAndroid Build Coastguard Worker }
154*7eba2f3bSAndroid Build Coastguard Worker 
dispatch_outgoing( mut hal_events: HalEventRegistry, mut out_cmd_rx: UnboundedReceiver<NciPacket>, mut out_data_rx: UnboundedReceiver<DataPacket>, hal_close_evt_rx: oneshot::Receiver<ffi::NfcStatus>, )155*7eba2f3bSAndroid Build Coastguard Worker async fn dispatch_outgoing(
156*7eba2f3bSAndroid Build Coastguard Worker     mut hal_events: HalEventRegistry,
157*7eba2f3bSAndroid Build Coastguard Worker     mut out_cmd_rx: UnboundedReceiver<NciPacket>,
158*7eba2f3bSAndroid Build Coastguard Worker     mut out_data_rx: UnboundedReceiver<DataPacket>,
159*7eba2f3bSAndroid Build Coastguard Worker     hal_close_evt_rx: oneshot::Receiver<ffi::NfcStatus>,
160*7eba2f3bSAndroid Build Coastguard Worker ) {
161*7eba2f3bSAndroid Build Coastguard Worker     loop {
162*7eba2f3bSAndroid Build Coastguard Worker         select! {
163*7eba2f3bSAndroid Build Coastguard Worker             Some(cmd) = out_cmd_rx.recv() => ffi::send_command(&cmd.encode_to_bytes().unwrap()),
164*7eba2f3bSAndroid Build Coastguard Worker             Some(data) = out_data_rx.recv() => ffi::send_command(&data.encode_to_bytes().unwrap()),
165*7eba2f3bSAndroid Build Coastguard Worker             else => break,
166*7eba2f3bSAndroid Build Coastguard Worker         }
167*7eba2f3bSAndroid Build Coastguard Worker     }
168*7eba2f3bSAndroid Build Coastguard Worker     ffi::stop_hal();
169*7eba2f3bSAndroid Build Coastguard Worker     let status = hal_close_evt_rx.await.unwrap();
170*7eba2f3bSAndroid Build Coastguard Worker     if let Some(evt) = hal_events.unregister(HalEvent::CloseComplete).await {
171*7eba2f3bSAndroid Build Coastguard Worker         evt.send(HalEventStatus::from(status)).unwrap();
172*7eba2f3bSAndroid Build Coastguard Worker     }
173*7eba2f3bSAndroid Build Coastguard Worker }
174