• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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