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 //! Rootcanal HAL
16*7eba2f3bSAndroid Build Coastguard Worker //! This connects to "rootcanal" which provides a simulated
17*7eba2f3bSAndroid Build Coastguard Worker //! Nfc chip as well as a simulated environment.
18*7eba2f3bSAndroid Build Coastguard Worker
19*7eba2f3bSAndroid Build Coastguard Worker use crate::internal::InnerHal;
20*7eba2f3bSAndroid Build Coastguard Worker use crate::{is_control_packet, Hal, HalEvent, HalEventRegistry, HalEventStatus, Result};
21*7eba2f3bSAndroid Build Coastguard Worker use bytes::{BufMut, BytesMut};
22*7eba2f3bSAndroid Build Coastguard Worker use log::{debug, error};
23*7eba2f3bSAndroid Build Coastguard Worker use nfc_packets::nci::{DataPacket, NciPacket};
24*7eba2f3bSAndroid Build Coastguard Worker use pdl_runtime::Packet;
25*7eba2f3bSAndroid Build Coastguard Worker use std::convert::TryInto;
26*7eba2f3bSAndroid Build Coastguard Worker use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
27*7eba2f3bSAndroid Build Coastguard Worker use tokio::net::TcpStream;
28*7eba2f3bSAndroid Build Coastguard Worker use tokio::select;
29*7eba2f3bSAndroid Build Coastguard Worker use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
30*7eba2f3bSAndroid Build Coastguard Worker
31*7eba2f3bSAndroid Build Coastguard Worker /// Initialize the module
init() -> Hal32*7eba2f3bSAndroid Build Coastguard Worker pub async fn init() -> Hal {
33*7eba2f3bSAndroid Build Coastguard Worker let (raw_hal, inner_hal) = InnerHal::new();
34*7eba2f3bSAndroid Build Coastguard Worker let (reader, writer) = TcpStream::connect("127.0.0.1:7000")
35*7eba2f3bSAndroid Build Coastguard Worker .await
36*7eba2f3bSAndroid Build Coastguard Worker .expect("unable to create stream to rootcanal")
37*7eba2f3bSAndroid Build Coastguard Worker .into_split();
38*7eba2f3bSAndroid Build Coastguard Worker
39*7eba2f3bSAndroid Build Coastguard Worker let reader = BufReader::new(reader);
40*7eba2f3bSAndroid Build Coastguard Worker tokio::spawn(dispatch_incoming(inner_hal.in_cmd_tx, inner_hal.in_data_tx, reader));
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 writer,
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 /// Send NCI events received from the HAL to the NCI layer
dispatch_incoming<R>( in_cmd_tx: UnboundedSender<NciPacket>, in_data_tx: UnboundedSender<DataPacket>, mut reader: R, ) -> Result<()> where R: AsyncReadExt + Unpin,52*7eba2f3bSAndroid Build Coastguard Worker async fn dispatch_incoming<R>(
53*7eba2f3bSAndroid Build Coastguard Worker in_cmd_tx: UnboundedSender<NciPacket>,
54*7eba2f3bSAndroid Build Coastguard Worker in_data_tx: UnboundedSender<DataPacket>,
55*7eba2f3bSAndroid Build Coastguard Worker mut reader: R,
56*7eba2f3bSAndroid Build Coastguard Worker ) -> Result<()>
57*7eba2f3bSAndroid Build Coastguard Worker where
58*7eba2f3bSAndroid Build Coastguard Worker R: AsyncReadExt + Unpin,
59*7eba2f3bSAndroid Build Coastguard Worker {
60*7eba2f3bSAndroid Build Coastguard Worker loop {
61*7eba2f3bSAndroid Build Coastguard Worker let mut buffer = BytesMut::with_capacity(1024);
62*7eba2f3bSAndroid Build Coastguard Worker let len: usize = reader.read_u16().await?.into();
63*7eba2f3bSAndroid Build Coastguard Worker buffer.resize(len, 0);
64*7eba2f3bSAndroid Build Coastguard Worker reader.read_exact(&mut buffer).await?;
65*7eba2f3bSAndroid Build Coastguard Worker let frozen = buffer.freeze();
66*7eba2f3bSAndroid Build Coastguard Worker debug!("{:?}", &frozen);
67*7eba2f3bSAndroid Build Coastguard Worker if is_control_packet(&frozen[..]) {
68*7eba2f3bSAndroid Build Coastguard Worker match NciPacket::parse(&frozen) {
69*7eba2f3bSAndroid Build Coastguard Worker Ok(p) => {
70*7eba2f3bSAndroid Build Coastguard Worker if in_cmd_tx.send(p).is_err() {
71*7eba2f3bSAndroid Build Coastguard Worker break;
72*7eba2f3bSAndroid Build Coastguard Worker }
73*7eba2f3bSAndroid Build Coastguard Worker }
74*7eba2f3bSAndroid Build Coastguard Worker Err(e) => error!("dropping invalid cmd event packet: {}: {:02x}", e, frozen),
75*7eba2f3bSAndroid Build Coastguard Worker }
76*7eba2f3bSAndroid Build Coastguard Worker } else {
77*7eba2f3bSAndroid Build Coastguard Worker match DataPacket::parse(&frozen) {
78*7eba2f3bSAndroid Build Coastguard Worker Ok(p) => {
79*7eba2f3bSAndroid Build Coastguard Worker if in_data_tx.send(p).is_err() {
80*7eba2f3bSAndroid Build Coastguard Worker break;
81*7eba2f3bSAndroid Build Coastguard Worker }
82*7eba2f3bSAndroid Build Coastguard Worker }
83*7eba2f3bSAndroid Build Coastguard Worker Err(e) => error!("dropping invalid data event packet: {}: {:02x}", e, frozen),
84*7eba2f3bSAndroid Build Coastguard Worker }
85*7eba2f3bSAndroid Build Coastguard Worker }
86*7eba2f3bSAndroid Build Coastguard Worker }
87*7eba2f3bSAndroid Build Coastguard Worker debug!("Dispatch incoming finished.");
88*7eba2f3bSAndroid Build Coastguard Worker Ok(())
89*7eba2f3bSAndroid Build Coastguard Worker }
90*7eba2f3bSAndroid Build Coastguard Worker
91*7eba2f3bSAndroid Build Coastguard Worker /// Send commands received from the NCI later to rootcanal
dispatch_outgoing<W>( mut hal_events: HalEventRegistry, mut out_cmd_rx: UnboundedReceiver<NciPacket>, mut out_data_rx: UnboundedReceiver<DataPacket>, mut writer: W, ) -> Result<()> where W: AsyncWriteExt + Unpin,92*7eba2f3bSAndroid Build Coastguard Worker async fn dispatch_outgoing<W>(
93*7eba2f3bSAndroid Build Coastguard Worker mut hal_events: HalEventRegistry,
94*7eba2f3bSAndroid Build Coastguard Worker mut out_cmd_rx: UnboundedReceiver<NciPacket>,
95*7eba2f3bSAndroid Build Coastguard Worker mut out_data_rx: UnboundedReceiver<DataPacket>,
96*7eba2f3bSAndroid Build Coastguard Worker mut writer: W,
97*7eba2f3bSAndroid Build Coastguard Worker ) -> Result<()>
98*7eba2f3bSAndroid Build Coastguard Worker where
99*7eba2f3bSAndroid Build Coastguard Worker W: AsyncWriteExt + Unpin,
100*7eba2f3bSAndroid Build Coastguard Worker {
101*7eba2f3bSAndroid Build Coastguard Worker loop {
102*7eba2f3bSAndroid Build Coastguard Worker select! {
103*7eba2f3bSAndroid Build Coastguard Worker Some(cmd) = out_cmd_rx.recv() => write_nci(&mut writer, cmd).await?,
104*7eba2f3bSAndroid Build Coastguard Worker Some(data) = out_data_rx.recv() => write_nci(&mut writer, data).await?,
105*7eba2f3bSAndroid Build Coastguard Worker else => break,
106*7eba2f3bSAndroid Build Coastguard Worker }
107*7eba2f3bSAndroid Build Coastguard Worker }
108*7eba2f3bSAndroid Build Coastguard Worker
109*7eba2f3bSAndroid Build Coastguard Worker writer.shutdown().await?;
110*7eba2f3bSAndroid Build Coastguard Worker if let Some(evt) = hal_events.unregister(HalEvent::CloseComplete).await {
111*7eba2f3bSAndroid Build Coastguard Worker evt.send(HalEventStatus::Success).unwrap();
112*7eba2f3bSAndroid Build Coastguard Worker }
113*7eba2f3bSAndroid Build Coastguard Worker debug!("Dispatch outgoing finished.");
114*7eba2f3bSAndroid Build Coastguard Worker Ok(())
115*7eba2f3bSAndroid Build Coastguard Worker }
116*7eba2f3bSAndroid Build Coastguard Worker
write_nci<W, P>(writer: &mut W, cmd: P) -> Result<()> where W: AsyncWriteExt + Unpin, P: Packet,117*7eba2f3bSAndroid Build Coastguard Worker async fn write_nci<W, P>(writer: &mut W, cmd: P) -> Result<()>
118*7eba2f3bSAndroid Build Coastguard Worker where
119*7eba2f3bSAndroid Build Coastguard Worker W: AsyncWriteExt + Unpin,
120*7eba2f3bSAndroid Build Coastguard Worker P: Packet,
121*7eba2f3bSAndroid Build Coastguard Worker {
122*7eba2f3bSAndroid Build Coastguard Worker let b = cmd.encode_to_bytes().unwrap();
123*7eba2f3bSAndroid Build Coastguard Worker let mut data = BytesMut::with_capacity(b.len() + 2);
124*7eba2f3bSAndroid Build Coastguard Worker data.put_u16(b.len().try_into().unwrap());
125*7eba2f3bSAndroid Build Coastguard Worker data.extend(b);
126*7eba2f3bSAndroid Build Coastguard Worker writer.write_all(&data[..]).await?;
127*7eba2f3bSAndroid Build Coastguard Worker debug!("Sent {:?}", data);
128*7eba2f3bSAndroid Build Coastguard Worker Ok(())
129*7eba2f3bSAndroid Build Coastguard Worker }
130