blob: bfa0bdbfed8af13f0bf5912f636eb16dcfbecba4 [file] [log] [blame] [edit]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate bytes;
extern crate num_derive;
extern crate num_traits;
extern crate thiserror;
#[cfg(feature = "web")]
mod web;
use anyhow::Result;
use clap::Parser;
use pica::{Pica, PicaCommand};
use std::net::{Ipv4Addr, SocketAddrV4};
use std::path::PathBuf;
use tokio::net::TcpListener;
use tokio::sync::{broadcast, mpsc};
use tokio::try_join;
const DEFAULT_UCI_PORT: u16 = 7000;
const DEFAULT_WEB_PORT: u16 = 3000;
async fn accept_incoming(tx: mpsc::Sender<PicaCommand>, uci_port: u16) -> Result<()> {
let uci_socket = SocketAddrV4::new(Ipv4Addr::LOCALHOST, uci_port);
let uci_listener = TcpListener::bind(uci_socket).await?;
println!("Pica: Listening on: {}", uci_port);
loop {
let (socket, addr) = uci_listener.accept().await?;
println!("Uwb host addr: {}", addr);
tx.send(PicaCommand::Connect(socket)).await?
}
}
#[derive(Parser, Debug)]
#[command(name = "pica", about = "Virtual UWB subsystem")]
struct Args {
/// Output directory for storing .pcapng traces.
/// If provided, .pcapng traces of client connections are automatically
/// saved under the name `device-{handle}.pcapng`.
#[arg(short, long, value_name = "PCAPNG_DIR")]
pcapng_dir: Option<PathBuf>,
/// Configure the TCP port for the UCI server.
#[arg(short, long, value_name = "UCI_PORT", default_value_t = DEFAULT_UCI_PORT)]
uci_port: u16,
/// Configure the HTTP port for the web interface.
#[arg(short, long, value_name = "WEB_PORT", default_value_t = DEFAULT_WEB_PORT)]
web_port: u16,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();
assert_ne!(
args.uci_port, args.web_port,
"UCI port and Web port shall be different."
);
let (event_tx, _) = broadcast::channel(16);
let mut pica = Pica::new(event_tx.clone(), args.pcapng_dir);
let pica_tx = pica.tx();
#[cfg(feature = "web")]
try_join!(
accept_incoming(pica_tx.clone(), args.uci_port),
pica.run(),
web::serve(pica_tx, event_tx, args.web_port)
)?;
#[cfg(not(feature = "web"))]
try_join!(accept_incoming(pica_tx.clone(), args.uci_port), pica.run(),)?;
Ok(())
}