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