radomctld/src/main.rs

162 lines
4.5 KiB
Rust
Raw Normal View History

2024-05-03 16:16:24 +02:00
mod rotctl;
2024-06-22 23:19:04 +02:00
use anyhow::Result;
use fern::colors::{Color, ColoredLevelConfig};
use log::{debug, error, info, warn};
use std::io;
2024-05-05 14:42:25 +02:00
use tokio::{
self,
io::{AsyncBufReadExt, AsyncWriteExt, BufStream},
net::{TcpListener, TcpStream},
sync::{self, mpsc, watch},
time,
2024-05-05 14:42:25 +02:00
};
use rotctl::Command;
async fn process_socket(
socket: TcpStream,
cmd_tx: mpsc::Sender<Command>,
mut pos_rx: watch::Receiver<(f32, f32)>,
) {
2024-05-05 14:42:25 +02:00
let mut stream = BufStream::new(socket);
let mut line = String::new();
loop {
if let Ok(n) = stream.read_line(&mut line).await {
if n == 0 {
return;
}
2024-06-22 23:19:04 +02:00
debug!("Received: {}", line.strip_suffix("\n").unwrap());
2024-05-05 14:42:25 +02:00
match rotctl::parse_command(&line) {
Ok(cmd) => match cmd {
Command::GetPos => {
let (az, el) = pos_rx.borrow().clone();
stream
.write_all(format!("{}\n{}\n", az, el).as_bytes())
.await
.unwrap();
stream.flush().await.unwrap();
}
Command::Exit => {
stream.write_all("RPRT 0\n".as_bytes()).await.unwrap();
stream.flush().await.unwrap();
return;
}
cmd => {
cmd_tx.send(cmd).await.unwrap();
stream.write_all("RPRT 0\n".as_bytes()).await.unwrap();
stream.flush().await.unwrap();
}
},
2024-05-05 14:42:25 +02:00
Err(msg) => {
2024-06-22 23:19:04 +02:00
error!("Unable to parse input:\n{}", msg);
stream.write_all("RPRT 6\n".as_bytes()).await.unwrap();
2024-05-05 14:42:25 +02:00
stream.flush().await.unwrap();
}
}
line.clear();
} else {
return;
}
}
}
async fn control_rotor(mut rx_cmd: mpsc::Receiver<Command>, pos_tx: watch::Sender<(f32, f32)>) {
let mut actual_az = 0.0;
let mut actual_el = 0.0;
let mut target_az = 0.0;
let mut target_el = 0.0;
loop {
tokio::select! {
Some(command) = rx_cmd.recv() => {
match command {
Command::SetPos(az, el) => {
2024-06-22 23:19:04 +02:00
info!("Received set pos {} {}", az, el);
target_az = az;
target_el = el;
}
_ => {}
}
},
_ = time::sleep(time::Duration::from_millis(100)) => {
if target_az < actual_az {
actual_az -= 1.0;
} else if target_az > actual_az {
actual_az += 1.0;
}
if target_el < actual_el {
actual_el -= 1.0;
} else if target_el > actual_el {
actual_el += 1.0;
}
pos_tx.send((actual_az, actual_el)).unwrap();
},
else => return
};
}
}
2024-06-22 23:19:04 +02:00
fn setup_logger() -> Result<()> {
let colors = ColoredLevelConfig::new()
.info(Color::Green)
.error(Color::Red)
.warn(Color::Yellow)
.debug(Color::Blue);
fern::Dispatch::new()
// Perform allocation-free log formatting
.format(move |out, message, record| {
out.finish(format_args!(
"[{} {} {}] {}",
humantime::format_rfc3339_millis(std::time::SystemTime::now()),
colors.color(record.level()),
record.target(),
message
))
})
// Add blanket level filter -
.level(log::LevelFilter::Debug)
// - and per-module overrides
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
// Apply globally
.apply()?;
Ok(())
}
2024-05-05 14:42:25 +02:00
#[tokio::main]
2024-06-22 23:19:04 +02:00
async fn main() -> Result<()> {
setup_logger()?;
let (cmd_tx, cmd_rx) = mpsc::channel::<Command>(16);
let (pos_tx, pos_rx) = watch::channel::<(f32, f32)>((0.0, 0.0));
tokio::spawn(async move {
control_rotor(cmd_rx, pos_tx).await;
});
2024-05-05 14:42:25 +02:00
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (socket, _) = listener.accept().await?;
let cmd_tx = cmd_tx.clone();
let pos_rx = pos_rx.clone();
2024-05-05 14:42:25 +02:00
tokio::spawn(async move {
process_socket(socket, cmd_tx, pos_rx).await;
2024-05-05 14:42:25 +02:00
});
}
2024-05-03 16:16:24 +02:00
}