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