1*7eba2f3bSAndroid Build Coastguard Worker // Copyright 2023, 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 //! NFCC and RF emulator.
16*7eba2f3bSAndroid Build Coastguard Worker
17*7eba2f3bSAndroid Build Coastguard Worker use anyhow::Result;
18*7eba2f3bSAndroid Build Coastguard Worker use argh::FromArgs;
19*7eba2f3bSAndroid Build Coastguard Worker use log::{error, info, warn};
20*7eba2f3bSAndroid Build Coastguard Worker use std::collections::HashMap;
21*7eba2f3bSAndroid Build Coastguard Worker use std::future::Future;
22*7eba2f3bSAndroid Build Coastguard Worker use std::net::{Ipv4Addr, SocketAddrV4};
23*7eba2f3bSAndroid Build Coastguard Worker use std::pin::{pin, Pin};
24*7eba2f3bSAndroid Build Coastguard Worker use std::task::Poll;
25*7eba2f3bSAndroid Build Coastguard Worker use tokio::io::AsyncReadExt;
26*7eba2f3bSAndroid Build Coastguard Worker use tokio::io::AsyncWriteExt;
27*7eba2f3bSAndroid Build Coastguard Worker use tokio::net::{tcp, TcpListener, TcpStream};
28*7eba2f3bSAndroid Build Coastguard Worker use tokio::select;
29*7eba2f3bSAndroid Build Coastguard Worker use tokio::sync::mpsc;
30*7eba2f3bSAndroid Build Coastguard Worker
31*7eba2f3bSAndroid Build Coastguard Worker pub mod controller;
32*7eba2f3bSAndroid Build Coastguard Worker pub mod packets;
33*7eba2f3bSAndroid Build Coastguard Worker mod proto;
34*7eba2f3bSAndroid Build Coastguard Worker
35*7eba2f3bSAndroid Build Coastguard Worker use controller::Controller;
36*7eba2f3bSAndroid Build Coastguard Worker use packets::{nci, rf};
37*7eba2f3bSAndroid Build Coastguard Worker use proto::{casimir, casimir_grpc};
38*7eba2f3bSAndroid Build Coastguard Worker
39*7eba2f3bSAndroid Build Coastguard Worker const MAX_DEVICES: usize = 128;
40*7eba2f3bSAndroid Build Coastguard Worker type Id = u16;
41*7eba2f3bSAndroid Build Coastguard Worker
42*7eba2f3bSAndroid Build Coastguard Worker /// Read RF Control and Data packets received on the RF transport.
43*7eba2f3bSAndroid Build Coastguard Worker /// Performs recombination of the segmented packets.
44*7eba2f3bSAndroid Build Coastguard Worker pub struct RfReader {
45*7eba2f3bSAndroid Build Coastguard Worker socket: tcp::OwnedReadHalf,
46*7eba2f3bSAndroid Build Coastguard Worker }
47*7eba2f3bSAndroid Build Coastguard Worker
48*7eba2f3bSAndroid Build Coastguard Worker /// Write RF Control and Data packets received to the RF transport.
49*7eba2f3bSAndroid Build Coastguard Worker /// Performs segmentation of the packets.
50*7eba2f3bSAndroid Build Coastguard Worker pub struct RfWriter {
51*7eba2f3bSAndroid Build Coastguard Worker socket: tcp::OwnedWriteHalf,
52*7eba2f3bSAndroid Build Coastguard Worker }
53*7eba2f3bSAndroid Build Coastguard Worker
54*7eba2f3bSAndroid Build Coastguard Worker impl RfReader {
55*7eba2f3bSAndroid Build Coastguard Worker /// Create a new RF reader from the TCP socket half.
new(socket: tcp::OwnedReadHalf) -> Self56*7eba2f3bSAndroid Build Coastguard Worker pub fn new(socket: tcp::OwnedReadHalf) -> Self {
57*7eba2f3bSAndroid Build Coastguard Worker RfReader { socket }
58*7eba2f3bSAndroid Build Coastguard Worker }
59*7eba2f3bSAndroid Build Coastguard Worker
60*7eba2f3bSAndroid Build Coastguard Worker /// Read a single RF packet from the reader.
61*7eba2f3bSAndroid Build Coastguard Worker /// RF packets are framed with the byte size encoded as little-endian u16.
read(&mut self) -> Result<Vec<u8>>62*7eba2f3bSAndroid Build Coastguard Worker pub async fn read(&mut self) -> Result<Vec<u8>> {
63*7eba2f3bSAndroid Build Coastguard Worker const HEADER_SIZE: usize = 2;
64*7eba2f3bSAndroid Build Coastguard Worker let mut header_bytes = [0; HEADER_SIZE];
65*7eba2f3bSAndroid Build Coastguard Worker
66*7eba2f3bSAndroid Build Coastguard Worker // Read the header bytes.
67*7eba2f3bSAndroid Build Coastguard Worker self.socket.read_exact(&mut header_bytes[0..HEADER_SIZE]).await?;
68*7eba2f3bSAndroid Build Coastguard Worker let packet_length = u16::from_le_bytes(header_bytes) as usize;
69*7eba2f3bSAndroid Build Coastguard Worker
70*7eba2f3bSAndroid Build Coastguard Worker // Read the packet data.
71*7eba2f3bSAndroid Build Coastguard Worker let mut packet_bytes = vec![0; packet_length];
72*7eba2f3bSAndroid Build Coastguard Worker self.socket.read_exact(&mut packet_bytes).await?;
73*7eba2f3bSAndroid Build Coastguard Worker
74*7eba2f3bSAndroid Build Coastguard Worker Ok(packet_bytes)
75*7eba2f3bSAndroid Build Coastguard Worker }
76*7eba2f3bSAndroid Build Coastguard Worker }
77*7eba2f3bSAndroid Build Coastguard Worker
78*7eba2f3bSAndroid Build Coastguard Worker impl RfWriter {
79*7eba2f3bSAndroid Build Coastguard Worker /// Create a new RF writer from the TCP socket half.
new(socket: tcp::OwnedWriteHalf) -> Self80*7eba2f3bSAndroid Build Coastguard Worker pub fn new(socket: tcp::OwnedWriteHalf) -> Self {
81*7eba2f3bSAndroid Build Coastguard Worker RfWriter { socket }
82*7eba2f3bSAndroid Build Coastguard Worker }
83*7eba2f3bSAndroid Build Coastguard Worker
84*7eba2f3bSAndroid Build Coastguard Worker /// Write a single RF packet to the writer.
85*7eba2f3bSAndroid Build Coastguard Worker /// RF packets are framed with the byte size encoded as little-endian u16.
write(&mut self, packet: &[u8]) -> Result<()>86*7eba2f3bSAndroid Build Coastguard Worker async fn write(&mut self, packet: &[u8]) -> Result<()> {
87*7eba2f3bSAndroid Build Coastguard Worker let packet_length: u16 = packet.len().try_into()?;
88*7eba2f3bSAndroid Build Coastguard Worker let header_bytes = packet_length.to_le_bytes();
89*7eba2f3bSAndroid Build Coastguard Worker
90*7eba2f3bSAndroid Build Coastguard Worker // Write the header bytes.
91*7eba2f3bSAndroid Build Coastguard Worker self.socket.write_all(&header_bytes).await?;
92*7eba2f3bSAndroid Build Coastguard Worker
93*7eba2f3bSAndroid Build Coastguard Worker // Write the packet data.
94*7eba2f3bSAndroid Build Coastguard Worker self.socket.write_all(packet).await?;
95*7eba2f3bSAndroid Build Coastguard Worker
96*7eba2f3bSAndroid Build Coastguard Worker Ok(())
97*7eba2f3bSAndroid Build Coastguard Worker }
98*7eba2f3bSAndroid Build Coastguard Worker }
99*7eba2f3bSAndroid Build Coastguard Worker
100*7eba2f3bSAndroid Build Coastguard Worker /// Identify the device type.
101*7eba2f3bSAndroid Build Coastguard Worker pub enum DeviceType {
102*7eba2f3bSAndroid Build Coastguard Worker Nci,
103*7eba2f3bSAndroid Build Coastguard Worker Rf,
104*7eba2f3bSAndroid Build Coastguard Worker }
105*7eba2f3bSAndroid Build Coastguard Worker
106*7eba2f3bSAndroid Build Coastguard Worker /// Represent shared contextual information.
107*7eba2f3bSAndroid Build Coastguard Worker pub struct DeviceInformation {
108*7eba2f3bSAndroid Build Coastguard Worker id: Id,
109*7eba2f3bSAndroid Build Coastguard Worker position: u32,
110*7eba2f3bSAndroid Build Coastguard Worker r#type: DeviceType,
111*7eba2f3bSAndroid Build Coastguard Worker }
112*7eba2f3bSAndroid Build Coastguard Worker
113*7eba2f3bSAndroid Build Coastguard Worker /// Represent a generic NFC device interacting on the RF transport.
114*7eba2f3bSAndroid Build Coastguard Worker /// Devices communicate together through the RF mpsc channel.
115*7eba2f3bSAndroid Build Coastguard Worker /// NFCCs are an instance of Device.
116*7eba2f3bSAndroid Build Coastguard Worker pub struct Device {
117*7eba2f3bSAndroid Build Coastguard Worker // Unique identifier associated with the device.
118*7eba2f3bSAndroid Build Coastguard Worker // The identifier is assured never to be reused in the lifetime of
119*7eba2f3bSAndroid Build Coastguard Worker // the emulator.
120*7eba2f3bSAndroid Build Coastguard Worker id: Id,
121*7eba2f3bSAndroid Build Coastguard Worker // Async task running the controller main loop.
122*7eba2f3bSAndroid Build Coastguard Worker task: Pin<Box<dyn Future<Output = Result<()>>>>,
123*7eba2f3bSAndroid Build Coastguard Worker // Channel for injecting RF data packets into the controller instance.
124*7eba2f3bSAndroid Build Coastguard Worker rf_tx: mpsc::UnboundedSender<rf::RfPacket>,
125*7eba2f3bSAndroid Build Coastguard Worker }
126*7eba2f3bSAndroid Build Coastguard Worker
127*7eba2f3bSAndroid Build Coastguard Worker impl Device {
nci( id: Id, socket: TcpStream, controller_rf_tx: mpsc::UnboundedSender<rf::RfPacket>, ) -> Device128*7eba2f3bSAndroid Build Coastguard Worker fn nci(
129*7eba2f3bSAndroid Build Coastguard Worker id: Id,
130*7eba2f3bSAndroid Build Coastguard Worker socket: TcpStream,
131*7eba2f3bSAndroid Build Coastguard Worker controller_rf_tx: mpsc::UnboundedSender<rf::RfPacket>,
132*7eba2f3bSAndroid Build Coastguard Worker ) -> Device {
133*7eba2f3bSAndroid Build Coastguard Worker let (rf_tx, rf_rx) = mpsc::unbounded_channel();
134*7eba2f3bSAndroid Build Coastguard Worker Device {
135*7eba2f3bSAndroid Build Coastguard Worker id,
136*7eba2f3bSAndroid Build Coastguard Worker rf_tx,
137*7eba2f3bSAndroid Build Coastguard Worker task: Box::pin(async move {
138*7eba2f3bSAndroid Build Coastguard Worker let (nci_rx, nci_tx) = socket.into_split();
139*7eba2f3bSAndroid Build Coastguard Worker Controller::run(
140*7eba2f3bSAndroid Build Coastguard Worker id,
141*7eba2f3bSAndroid Build Coastguard Worker pin!(nci::Reader::new(nci_rx).into_stream()),
142*7eba2f3bSAndroid Build Coastguard Worker nci::Writer::new(nci_tx),
143*7eba2f3bSAndroid Build Coastguard Worker rf_rx,
144*7eba2f3bSAndroid Build Coastguard Worker controller_rf_tx,
145*7eba2f3bSAndroid Build Coastguard Worker )
146*7eba2f3bSAndroid Build Coastguard Worker .await
147*7eba2f3bSAndroid Build Coastguard Worker }),
148*7eba2f3bSAndroid Build Coastguard Worker }
149*7eba2f3bSAndroid Build Coastguard Worker }
150*7eba2f3bSAndroid Build Coastguard Worker
rf( id: Id, socket: TcpStream, controller_rf_tx: mpsc::UnboundedSender<rf::RfPacket>, ) -> Device151*7eba2f3bSAndroid Build Coastguard Worker fn rf(
152*7eba2f3bSAndroid Build Coastguard Worker id: Id,
153*7eba2f3bSAndroid Build Coastguard Worker socket: TcpStream,
154*7eba2f3bSAndroid Build Coastguard Worker controller_rf_tx: mpsc::UnboundedSender<rf::RfPacket>,
155*7eba2f3bSAndroid Build Coastguard Worker ) -> Device {
156*7eba2f3bSAndroid Build Coastguard Worker let (rf_tx, mut rf_rx) = mpsc::unbounded_channel();
157*7eba2f3bSAndroid Build Coastguard Worker Device {
158*7eba2f3bSAndroid Build Coastguard Worker id,
159*7eba2f3bSAndroid Build Coastguard Worker rf_tx,
160*7eba2f3bSAndroid Build Coastguard Worker task: Box::pin(async move {
161*7eba2f3bSAndroid Build Coastguard Worker let (socket_rx, socket_tx) = socket.into_split();
162*7eba2f3bSAndroid Build Coastguard Worker let mut rf_reader = RfReader::new(socket_rx);
163*7eba2f3bSAndroid Build Coastguard Worker let mut rf_writer = RfWriter::new(socket_tx);
164*7eba2f3bSAndroid Build Coastguard Worker
165*7eba2f3bSAndroid Build Coastguard Worker let result: Result<((), ())> = futures::future::try_join(
166*7eba2f3bSAndroid Build Coastguard Worker async {
167*7eba2f3bSAndroid Build Coastguard Worker loop {
168*7eba2f3bSAndroid Build Coastguard Worker // Replace the sender identifier in the packet
169*7eba2f3bSAndroid Build Coastguard Worker // with the assigned number for the RF connection.
170*7eba2f3bSAndroid Build Coastguard Worker // TODO: currently the generated API does not allow
171*7eba2f3bSAndroid Build Coastguard Worker // modifying the parsed fields so the change needs to be
172*7eba2f3bSAndroid Build Coastguard Worker // applied to the unparsed packet.
173*7eba2f3bSAndroid Build Coastguard Worker let mut packet_bytes = rf_reader.read().await?;
174*7eba2f3bSAndroid Build Coastguard Worker packet_bytes[0..2].copy_from_slice(&id.to_le_bytes());
175*7eba2f3bSAndroid Build Coastguard Worker
176*7eba2f3bSAndroid Build Coastguard Worker // Parse the input packet.
177*7eba2f3bSAndroid Build Coastguard Worker let packet = rf::RfPacket::parse(&packet_bytes)?;
178*7eba2f3bSAndroid Build Coastguard Worker
179*7eba2f3bSAndroid Build Coastguard Worker // Forward the packet to other devices.
180*7eba2f3bSAndroid Build Coastguard Worker controller_rf_tx.send(packet)?;
181*7eba2f3bSAndroid Build Coastguard Worker }
182*7eba2f3bSAndroid Build Coastguard Worker },
183*7eba2f3bSAndroid Build Coastguard Worker async {
184*7eba2f3bSAndroid Build Coastguard Worker loop {
185*7eba2f3bSAndroid Build Coastguard Worker // Forward the packet to the socket connection.
186*7eba2f3bSAndroid Build Coastguard Worker use pdl_runtime::Packet;
187*7eba2f3bSAndroid Build Coastguard Worker let packet = rf_rx
188*7eba2f3bSAndroid Build Coastguard Worker .recv()
189*7eba2f3bSAndroid Build Coastguard Worker .await
190*7eba2f3bSAndroid Build Coastguard Worker .ok_or(anyhow::anyhow!("rf_rx channel closed"))?;
191*7eba2f3bSAndroid Build Coastguard Worker rf_writer.write(&packet.to_vec()).await?;
192*7eba2f3bSAndroid Build Coastguard Worker }
193*7eba2f3bSAndroid Build Coastguard Worker },
194*7eba2f3bSAndroid Build Coastguard Worker )
195*7eba2f3bSAndroid Build Coastguard Worker .await;
196*7eba2f3bSAndroid Build Coastguard Worker
197*7eba2f3bSAndroid Build Coastguard Worker result?;
198*7eba2f3bSAndroid Build Coastguard Worker Ok(())
199*7eba2f3bSAndroid Build Coastguard Worker }),
200*7eba2f3bSAndroid Build Coastguard Worker }
201*7eba2f3bSAndroid Build Coastguard Worker }
202*7eba2f3bSAndroid Build Coastguard Worker }
203*7eba2f3bSAndroid Build Coastguard Worker
204*7eba2f3bSAndroid Build Coastguard Worker struct Scene {
205*7eba2f3bSAndroid Build Coastguard Worker next_id: u16,
206*7eba2f3bSAndroid Build Coastguard Worker waker: Option<std::task::Waker>,
207*7eba2f3bSAndroid Build Coastguard Worker devices: [Option<Device>; MAX_DEVICES],
208*7eba2f3bSAndroid Build Coastguard Worker context: std::sync::Arc<std::sync::Mutex<HashMap<Id, DeviceInformation>>>,
209*7eba2f3bSAndroid Build Coastguard Worker }
210*7eba2f3bSAndroid Build Coastguard Worker
211*7eba2f3bSAndroid Build Coastguard Worker impl Scene {
new() -> Scene212*7eba2f3bSAndroid Build Coastguard Worker fn new() -> Scene {
213*7eba2f3bSAndroid Build Coastguard Worker const NONE: Option<Device> = None;
214*7eba2f3bSAndroid Build Coastguard Worker Scene {
215*7eba2f3bSAndroid Build Coastguard Worker next_id: 0,
216*7eba2f3bSAndroid Build Coastguard Worker waker: None,
217*7eba2f3bSAndroid Build Coastguard Worker devices: [NONE; MAX_DEVICES],
218*7eba2f3bSAndroid Build Coastguard Worker context: std::sync::Arc::new(std::sync::Mutex::new(HashMap::new())),
219*7eba2f3bSAndroid Build Coastguard Worker }
220*7eba2f3bSAndroid Build Coastguard Worker }
221*7eba2f3bSAndroid Build Coastguard Worker
wake(&mut self)222*7eba2f3bSAndroid Build Coastguard Worker fn wake(&mut self) {
223*7eba2f3bSAndroid Build Coastguard Worker if let Some(waker) = self.waker.take() {
224*7eba2f3bSAndroid Build Coastguard Worker waker.wake()
225*7eba2f3bSAndroid Build Coastguard Worker }
226*7eba2f3bSAndroid Build Coastguard Worker }
227*7eba2f3bSAndroid Build Coastguard Worker
add_device(&mut self, builder: impl FnOnce(Id) -> Device) -> Result<Id>228*7eba2f3bSAndroid Build Coastguard Worker fn add_device(&mut self, builder: impl FnOnce(Id) -> Device) -> Result<Id> {
229*7eba2f3bSAndroid Build Coastguard Worker for n in 0..MAX_DEVICES {
230*7eba2f3bSAndroid Build Coastguard Worker if self.devices[n].is_none() {
231*7eba2f3bSAndroid Build Coastguard Worker let id = self.next_id;
232*7eba2f3bSAndroid Build Coastguard Worker self.devices[n] = Some(builder(id));
233*7eba2f3bSAndroid Build Coastguard Worker self.next_id += 1;
234*7eba2f3bSAndroid Build Coastguard Worker self.wake();
235*7eba2f3bSAndroid Build Coastguard Worker return Ok(id);
236*7eba2f3bSAndroid Build Coastguard Worker }
237*7eba2f3bSAndroid Build Coastguard Worker }
238*7eba2f3bSAndroid Build Coastguard Worker Err(anyhow::anyhow!("max number of connections reached"))
239*7eba2f3bSAndroid Build Coastguard Worker }
240*7eba2f3bSAndroid Build Coastguard Worker
disconnect(&mut self, n: usize)241*7eba2f3bSAndroid Build Coastguard Worker fn disconnect(&mut self, n: usize) {
242*7eba2f3bSAndroid Build Coastguard Worker let id = self.devices[n].as_ref().unwrap().id;
243*7eba2f3bSAndroid Build Coastguard Worker self.devices[n] = None;
244*7eba2f3bSAndroid Build Coastguard Worker self.context.lock().unwrap().remove(&id);
245*7eba2f3bSAndroid Build Coastguard Worker for other_n in 0..MAX_DEVICES {
246*7eba2f3bSAndroid Build Coastguard Worker let Some(ref device) = self.devices[other_n] else { continue };
247*7eba2f3bSAndroid Build Coastguard Worker assert!(n != other_n);
248*7eba2f3bSAndroid Build Coastguard Worker device
249*7eba2f3bSAndroid Build Coastguard Worker .rf_tx
250*7eba2f3bSAndroid Build Coastguard Worker .send(
251*7eba2f3bSAndroid Build Coastguard Worker rf::DeactivateNotificationBuilder {
252*7eba2f3bSAndroid Build Coastguard Worker type_: rf::DeactivateType::Discovery,
253*7eba2f3bSAndroid Build Coastguard Worker reason: rf::DeactivateReason::RfLinkLoss,
254*7eba2f3bSAndroid Build Coastguard Worker sender: id,
255*7eba2f3bSAndroid Build Coastguard Worker receiver: device.id,
256*7eba2f3bSAndroid Build Coastguard Worker technology: rf::Technology::NfcA,
257*7eba2f3bSAndroid Build Coastguard Worker protocol: rf::Protocol::Undetermined,
258*7eba2f3bSAndroid Build Coastguard Worker }
259*7eba2f3bSAndroid Build Coastguard Worker .into(),
260*7eba2f3bSAndroid Build Coastguard Worker )
261*7eba2f3bSAndroid Build Coastguard Worker .expect("failed to send deactive notification")
262*7eba2f3bSAndroid Build Coastguard Worker }
263*7eba2f3bSAndroid Build Coastguard Worker }
264*7eba2f3bSAndroid Build Coastguard Worker
send(&self, packet: &rf::RfPacket) -> Result<()>265*7eba2f3bSAndroid Build Coastguard Worker fn send(&self, packet: &rf::RfPacket) -> Result<()> {
266*7eba2f3bSAndroid Build Coastguard Worker let context = self.context.lock().unwrap();
267*7eba2f3bSAndroid Build Coastguard Worker for n in 0..MAX_DEVICES {
268*7eba2f3bSAndroid Build Coastguard Worker let Some(ref device) = self.devices[n] else { continue };
269*7eba2f3bSAndroid Build Coastguard Worker if packet.get_sender() != device.id
270*7eba2f3bSAndroid Build Coastguard Worker && (packet.get_receiver() == u16::MAX || packet.get_receiver() == device.id)
271*7eba2f3bSAndroid Build Coastguard Worker && context.get(&device.id).map(|info| info.position)
272*7eba2f3bSAndroid Build Coastguard Worker == context.get(&packet.get_sender()).map(|info| info.position)
273*7eba2f3bSAndroid Build Coastguard Worker {
274*7eba2f3bSAndroid Build Coastguard Worker device.rf_tx.send(packet.to_owned())?;
275*7eba2f3bSAndroid Build Coastguard Worker }
276*7eba2f3bSAndroid Build Coastguard Worker }
277*7eba2f3bSAndroid Build Coastguard Worker
278*7eba2f3bSAndroid Build Coastguard Worker Ok(())
279*7eba2f3bSAndroid Build Coastguard Worker }
280*7eba2f3bSAndroid Build Coastguard Worker }
281*7eba2f3bSAndroid Build Coastguard Worker
282*7eba2f3bSAndroid Build Coastguard Worker impl Future for Scene {
283*7eba2f3bSAndroid Build Coastguard Worker type Output = ();
284*7eba2f3bSAndroid Build Coastguard Worker
poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<()>285*7eba2f3bSAndroid Build Coastguard Worker fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<()> {
286*7eba2f3bSAndroid Build Coastguard Worker for n in 0..MAX_DEVICES {
287*7eba2f3bSAndroid Build Coastguard Worker let dropped = match self.devices[n] {
288*7eba2f3bSAndroid Build Coastguard Worker Some(ref mut device) => match device.task.as_mut().poll(cx) {
289*7eba2f3bSAndroid Build Coastguard Worker Poll::Ready(Ok(_)) => unreachable!(),
290*7eba2f3bSAndroid Build Coastguard Worker Poll::Ready(Err(err)) => {
291*7eba2f3bSAndroid Build Coastguard Worker warn!("dropping device {}: {}", n, err);
292*7eba2f3bSAndroid Build Coastguard Worker true
293*7eba2f3bSAndroid Build Coastguard Worker }
294*7eba2f3bSAndroid Build Coastguard Worker Poll::Pending => false,
295*7eba2f3bSAndroid Build Coastguard Worker },
296*7eba2f3bSAndroid Build Coastguard Worker None => false,
297*7eba2f3bSAndroid Build Coastguard Worker };
298*7eba2f3bSAndroid Build Coastguard Worker if dropped {
299*7eba2f3bSAndroid Build Coastguard Worker self.disconnect(n)
300*7eba2f3bSAndroid Build Coastguard Worker }
301*7eba2f3bSAndroid Build Coastguard Worker }
302*7eba2f3bSAndroid Build Coastguard Worker self.waker = Some(cx.waker().clone());
303*7eba2f3bSAndroid Build Coastguard Worker Poll::Pending
304*7eba2f3bSAndroid Build Coastguard Worker }
305*7eba2f3bSAndroid Build Coastguard Worker }
306*7eba2f3bSAndroid Build Coastguard Worker
307*7eba2f3bSAndroid Build Coastguard Worker #[derive(Clone)]
308*7eba2f3bSAndroid Build Coastguard Worker struct Service {
309*7eba2f3bSAndroid Build Coastguard Worker context: std::sync::Arc<std::sync::Mutex<HashMap<Id, DeviceInformation>>>,
310*7eba2f3bSAndroid Build Coastguard Worker }
311*7eba2f3bSAndroid Build Coastguard Worker
312*7eba2f3bSAndroid Build Coastguard Worker impl From<&DeviceInformation> for casimir::Device {
from(info: &DeviceInformation) -> Self313*7eba2f3bSAndroid Build Coastguard Worker fn from(info: &DeviceInformation) -> Self {
314*7eba2f3bSAndroid Build Coastguard Worker let mut device = casimir::Device::new();
315*7eba2f3bSAndroid Build Coastguard Worker device.set_device_id(info.id as u32);
316*7eba2f3bSAndroid Build Coastguard Worker device.set_position(info.position);
317*7eba2f3bSAndroid Build Coastguard Worker match info.r#type {
318*7eba2f3bSAndroid Build Coastguard Worker DeviceType::Nci => device.set_nci(Default::default()),
319*7eba2f3bSAndroid Build Coastguard Worker DeviceType::Rf => device.set_rf(Default::default()),
320*7eba2f3bSAndroid Build Coastguard Worker }
321*7eba2f3bSAndroid Build Coastguard Worker device
322*7eba2f3bSAndroid Build Coastguard Worker }
323*7eba2f3bSAndroid Build Coastguard Worker }
324*7eba2f3bSAndroid Build Coastguard Worker
325*7eba2f3bSAndroid Build Coastguard Worker impl casimir_grpc::Casimir for Service {
list_devices( &mut self, _ctx: grpcio::RpcContext<'_>, _req: casimir::ListDevicesRequest, sink: grpcio::UnarySink<casimir::ListDevicesResponse>, )326*7eba2f3bSAndroid Build Coastguard Worker fn list_devices(
327*7eba2f3bSAndroid Build Coastguard Worker &mut self,
328*7eba2f3bSAndroid Build Coastguard Worker _ctx: grpcio::RpcContext<'_>,
329*7eba2f3bSAndroid Build Coastguard Worker _req: casimir::ListDevicesRequest,
330*7eba2f3bSAndroid Build Coastguard Worker sink: grpcio::UnarySink<casimir::ListDevicesResponse>,
331*7eba2f3bSAndroid Build Coastguard Worker ) {
332*7eba2f3bSAndroid Build Coastguard Worker let mut response = casimir::ListDevicesResponse::new();
333*7eba2f3bSAndroid Build Coastguard Worker response.set_device(
334*7eba2f3bSAndroid Build Coastguard Worker self.context
335*7eba2f3bSAndroid Build Coastguard Worker .lock()
336*7eba2f3bSAndroid Build Coastguard Worker .unwrap()
337*7eba2f3bSAndroid Build Coastguard Worker .values()
338*7eba2f3bSAndroid Build Coastguard Worker .map(casimir::Device::from)
339*7eba2f3bSAndroid Build Coastguard Worker .collect::<Vec<_>>()
340*7eba2f3bSAndroid Build Coastguard Worker .into(),
341*7eba2f3bSAndroid Build Coastguard Worker );
342*7eba2f3bSAndroid Build Coastguard Worker sink.success(response);
343*7eba2f3bSAndroid Build Coastguard Worker }
344*7eba2f3bSAndroid Build Coastguard Worker
get_device( &mut self, _ctx: grpcio::RpcContext<'_>, req: casimir::GetDeviceRequest, sink: grpcio::UnarySink<casimir::GetDeviceResponse>, )345*7eba2f3bSAndroid Build Coastguard Worker fn get_device(
346*7eba2f3bSAndroid Build Coastguard Worker &mut self,
347*7eba2f3bSAndroid Build Coastguard Worker _ctx: grpcio::RpcContext<'_>,
348*7eba2f3bSAndroid Build Coastguard Worker req: casimir::GetDeviceRequest,
349*7eba2f3bSAndroid Build Coastguard Worker sink: grpcio::UnarySink<casimir::GetDeviceResponse>,
350*7eba2f3bSAndroid Build Coastguard Worker ) {
351*7eba2f3bSAndroid Build Coastguard Worker match self.context.lock().unwrap().get(&(req.get_device_id() as u16)) {
352*7eba2f3bSAndroid Build Coastguard Worker Some(info) => {
353*7eba2f3bSAndroid Build Coastguard Worker let mut response = casimir::GetDeviceResponse::new();
354*7eba2f3bSAndroid Build Coastguard Worker response.set_device(info.into());
355*7eba2f3bSAndroid Build Coastguard Worker sink.success(response)
356*7eba2f3bSAndroid Build Coastguard Worker }
357*7eba2f3bSAndroid Build Coastguard Worker None => sink.fail(grpcio::RpcStatus::with_message(
358*7eba2f3bSAndroid Build Coastguard Worker grpcio::RpcStatusCode::INVALID_ARGUMENT,
359*7eba2f3bSAndroid Build Coastguard Worker format!("device_id {} not found", req.get_device_id()),
360*7eba2f3bSAndroid Build Coastguard Worker )),
361*7eba2f3bSAndroid Build Coastguard Worker };
362*7eba2f3bSAndroid Build Coastguard Worker }
363*7eba2f3bSAndroid Build Coastguard Worker
move_device( &mut self, _ctx: grpcio::RpcContext<'_>, req: casimir::MoveDeviceRequest, sink: grpcio::UnarySink<casimir::MoveDeviceResponse>, )364*7eba2f3bSAndroid Build Coastguard Worker fn move_device(
365*7eba2f3bSAndroid Build Coastguard Worker &mut self,
366*7eba2f3bSAndroid Build Coastguard Worker _ctx: grpcio::RpcContext<'_>,
367*7eba2f3bSAndroid Build Coastguard Worker req: casimir::MoveDeviceRequest,
368*7eba2f3bSAndroid Build Coastguard Worker sink: grpcio::UnarySink<casimir::MoveDeviceResponse>,
369*7eba2f3bSAndroid Build Coastguard Worker ) {
370*7eba2f3bSAndroid Build Coastguard Worker match self.context.lock().unwrap().get_mut(&(req.get_device_id() as u16)) {
371*7eba2f3bSAndroid Build Coastguard Worker Some(info) => {
372*7eba2f3bSAndroid Build Coastguard Worker info.position = req.get_position();
373*7eba2f3bSAndroid Build Coastguard Worker sink.success(Default::default())
374*7eba2f3bSAndroid Build Coastguard Worker }
375*7eba2f3bSAndroid Build Coastguard Worker None => sink.fail(grpcio::RpcStatus::with_message(
376*7eba2f3bSAndroid Build Coastguard Worker grpcio::RpcStatusCode::INVALID_ARGUMENT,
377*7eba2f3bSAndroid Build Coastguard Worker format!("device_id {} not found", req.get_device_id()),
378*7eba2f3bSAndroid Build Coastguard Worker )),
379*7eba2f3bSAndroid Build Coastguard Worker };
380*7eba2f3bSAndroid Build Coastguard Worker }
381*7eba2f3bSAndroid Build Coastguard Worker }
382*7eba2f3bSAndroid Build Coastguard Worker
383*7eba2f3bSAndroid Build Coastguard Worker #[derive(FromArgs, Debug)]
384*7eba2f3bSAndroid Build Coastguard Worker /// Nfc emulator.
385*7eba2f3bSAndroid Build Coastguard Worker struct Opt {
386*7eba2f3bSAndroid Build Coastguard Worker #[argh(option, default = "7000")]
387*7eba2f3bSAndroid Build Coastguard Worker /// configure the TCP port for the NCI server.
388*7eba2f3bSAndroid Build Coastguard Worker nci_port: u16,
389*7eba2f3bSAndroid Build Coastguard Worker #[argh(option, default = "7001")]
390*7eba2f3bSAndroid Build Coastguard Worker /// configure the TCP port for the RF server.
391*7eba2f3bSAndroid Build Coastguard Worker rf_port: u16,
392*7eba2f3bSAndroid Build Coastguard Worker #[argh(option, default = "50051")]
393*7eba2f3bSAndroid Build Coastguard Worker /// configure the gRPC port.
394*7eba2f3bSAndroid Build Coastguard Worker grpc_port: u16,
395*7eba2f3bSAndroid Build Coastguard Worker }
396*7eba2f3bSAndroid Build Coastguard Worker
run() -> Result<()>397*7eba2f3bSAndroid Build Coastguard Worker async fn run() -> Result<()> {
398*7eba2f3bSAndroid Build Coastguard Worker env_logger::init_from_env(
399*7eba2f3bSAndroid Build Coastguard Worker env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "debug"),
400*7eba2f3bSAndroid Build Coastguard Worker );
401*7eba2f3bSAndroid Build Coastguard Worker
402*7eba2f3bSAndroid Build Coastguard Worker let opt: Opt = argh::from_env();
403*7eba2f3bSAndroid Build Coastguard Worker let nci_listener =
404*7eba2f3bSAndroid Build Coastguard Worker TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, opt.nci_port)).await?;
405*7eba2f3bSAndroid Build Coastguard Worker let rf_listener =
406*7eba2f3bSAndroid Build Coastguard Worker TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, opt.rf_port)).await?;
407*7eba2f3bSAndroid Build Coastguard Worker let (rf_tx, mut rf_rx) = mpsc::unbounded_channel();
408*7eba2f3bSAndroid Build Coastguard Worker let mut scene = Scene::new();
409*7eba2f3bSAndroid Build Coastguard Worker
410*7eba2f3bSAndroid Build Coastguard Worker info!("Listening for NCI connections at address 127.0.0.1:{}", opt.nci_port);
411*7eba2f3bSAndroid Build Coastguard Worker info!("Listening for RF connections at address 127.0.0.1:{}", opt.rf_port);
412*7eba2f3bSAndroid Build Coastguard Worker info!("Listening for gRPC connections at address 127.0.0.1:{}", opt.grpc_port);
413*7eba2f3bSAndroid Build Coastguard Worker
414*7eba2f3bSAndroid Build Coastguard Worker let env = std::sync::Arc::new(grpcio::Environment::new(1));
415*7eba2f3bSAndroid Build Coastguard Worker let service = casimir_grpc::create_casimir(Service { context: scene.context.clone() });
416*7eba2f3bSAndroid Build Coastguard Worker let quota = grpcio::ResourceQuota::new(Some("CasimirQuota")).resize_memory(1024 * 1024);
417*7eba2f3bSAndroid Build Coastguard Worker let channel_builder = grpcio::ChannelBuilder::new(env.clone()).set_resource_quota(quota);
418*7eba2f3bSAndroid Build Coastguard Worker
419*7eba2f3bSAndroid Build Coastguard Worker let mut server = grpcio::ServerBuilder::new(env)
420*7eba2f3bSAndroid Build Coastguard Worker .register_service(service)
421*7eba2f3bSAndroid Build Coastguard Worker .channel_args(channel_builder.build_args())
422*7eba2f3bSAndroid Build Coastguard Worker .build()
423*7eba2f3bSAndroid Build Coastguard Worker .unwrap();
424*7eba2f3bSAndroid Build Coastguard Worker server
425*7eba2f3bSAndroid Build Coastguard Worker .add_listening_port(
426*7eba2f3bSAndroid Build Coastguard Worker format!("127.0.0.1:{}", opt.grpc_port),
427*7eba2f3bSAndroid Build Coastguard Worker grpcio::ServerCredentials::insecure(),
428*7eba2f3bSAndroid Build Coastguard Worker )
429*7eba2f3bSAndroid Build Coastguard Worker .unwrap();
430*7eba2f3bSAndroid Build Coastguard Worker server.start();
431*7eba2f3bSAndroid Build Coastguard Worker
432*7eba2f3bSAndroid Build Coastguard Worker loop {
433*7eba2f3bSAndroid Build Coastguard Worker select! {
434*7eba2f3bSAndroid Build Coastguard Worker result = nci_listener.accept() => {
435*7eba2f3bSAndroid Build Coastguard Worker let (socket, addr) = result?;
436*7eba2f3bSAndroid Build Coastguard Worker info!("Incoming NCI connection from {}", addr);
437*7eba2f3bSAndroid Build Coastguard Worker match scene.add_device(|id| Device::nci(id, socket, rf_tx.clone())) {
438*7eba2f3bSAndroid Build Coastguard Worker Ok(id) => {
439*7eba2f3bSAndroid Build Coastguard Worker scene.context.lock().unwrap().insert(id, DeviceInformation {
440*7eba2f3bSAndroid Build Coastguard Worker id, position: id as u32, r#type: DeviceType::Nci
441*7eba2f3bSAndroid Build Coastguard Worker });
442*7eba2f3bSAndroid Build Coastguard Worker info!("Accepted NCI connection from {} with id {}", addr, id)
443*7eba2f3bSAndroid Build Coastguard Worker }
444*7eba2f3bSAndroid Build Coastguard Worker Err(err) => error!("Failed to accept NCI connection from {}: {}", addr, err)
445*7eba2f3bSAndroid Build Coastguard Worker }
446*7eba2f3bSAndroid Build Coastguard Worker },
447*7eba2f3bSAndroid Build Coastguard Worker result = rf_listener.accept() => {
448*7eba2f3bSAndroid Build Coastguard Worker let (socket, addr) = result?;
449*7eba2f3bSAndroid Build Coastguard Worker info!("Incoming RF connection from {}", addr);
450*7eba2f3bSAndroid Build Coastguard Worker match scene.add_device(|id| Device::rf(id, socket, rf_tx.clone())) {
451*7eba2f3bSAndroid Build Coastguard Worker Ok(id) => {
452*7eba2f3bSAndroid Build Coastguard Worker scene.context.lock().unwrap().insert(id, DeviceInformation {
453*7eba2f3bSAndroid Build Coastguard Worker id, position: id as u32, r#type: DeviceType::Rf
454*7eba2f3bSAndroid Build Coastguard Worker });
455*7eba2f3bSAndroid Build Coastguard Worker info!("Accepted RF connection from {} with id {}", addr, id)
456*7eba2f3bSAndroid Build Coastguard Worker }
457*7eba2f3bSAndroid Build Coastguard Worker Err(err) => error!("Failed to accept RF connection from {}: {}", addr, err)
458*7eba2f3bSAndroid Build Coastguard Worker }
459*7eba2f3bSAndroid Build Coastguard Worker },
460*7eba2f3bSAndroid Build Coastguard Worker _ = &mut scene => (),
461*7eba2f3bSAndroid Build Coastguard Worker result = rf_rx.recv() => {
462*7eba2f3bSAndroid Build Coastguard Worker let packet = result.ok_or(anyhow::anyhow!("rf_rx channel closed"))?;
463*7eba2f3bSAndroid Build Coastguard Worker scene.send(&packet)?
464*7eba2f3bSAndroid Build Coastguard Worker }
465*7eba2f3bSAndroid Build Coastguard Worker }
466*7eba2f3bSAndroid Build Coastguard Worker }
467*7eba2f3bSAndroid Build Coastguard Worker }
468*7eba2f3bSAndroid Build Coastguard Worker
469*7eba2f3bSAndroid Build Coastguard Worker #[tokio::main]
main() -> Result<()>470*7eba2f3bSAndroid Build Coastguard Worker async fn main() -> Result<()> {
471*7eba2f3bSAndroid Build Coastguard Worker run().await
472*7eba2f3bSAndroid Build Coastguard Worker }
473