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