xref: /aosp_15_r20/system/nfc/src/rust/hal/rootcanal_hal.rs (revision 7eba2f3b06c51ae21384f6a4f14577b668a869b3)
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