mod bridge;
mod cli;
mod message;
mod pty;
mod serial;
mod transport;
use anyhow::Result;
use clap::Parser;
use cli::{Cli, Commands};
use tracing::info;
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
)
.init();
let cli = Cli::parse();
match cli.command {
Commands::Serve {
port,
baud,
channel,
domain,
} => run_serve(port, baud, channel, domain).await,
Commands::Attach {
channel,
link,
domain,
} => run_attach(channel, link, domain).await,
Commands::List { domain, wait } => run_list(domain, wait).await,
}
}
async fn run_serve(
port: std::path::PathBuf,
baud: u32,
channel: String,
domain: u16,
) -> Result<()> {
info!(
port = %port.display(),
baud,
channel,
domain,
"starting serve"
);
let participant = transport::DdsParticipant::new(domain)?;
let dds_channel = transport::DdsChannel::open(&participant.participant, &channel)?;
let serial = serial::open_serial(&port, baud).await?;
tokio::select! {
res = bridge::run_serve_bridge(serial, dds_channel) => res?,
res = transport::wait_for_shutdown() => {
res?;
}
}
Ok(())
}
async fn run_attach(
channel: String,
link: std::path::PathBuf,
domain: u16,
) -> Result<()> {
info!(channel, link = %link.display(), domain, "starting attach");
let endpoint = pty::create_pty_endpoint(&link)?;
let link_path = endpoint.link_path.clone();
let participant = transport::DdsParticipant::new(domain)?;
let dds_channel = transport::DdsChannel::open(&participant.participant, &channel)?;
let bridge_result = tokio::select! {
res = bridge::run_attach_bridge(endpoint.async_io, dds_channel) => res,
res = transport::wait_for_shutdown() => {
res?;
pty::cleanup_link(&link_path).await?;
return Ok(());
}
};
bridge_result?;
pty::cleanup_link(&link_path).await?;
Ok(())
}
async fn run_list(domain: u16, wait: u64) -> Result<()> {
let participant = transport::DdsParticipant::new(domain)?;
let channels = transport::discover_channels(&participant.participant, wait).await?;
if channels.is_empty() {
println!("No super_cereal channels discovered.");
} else {
for channel in channels {
println!("{channel}");
}
}
Ok(())
}