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