mod web;
use crate::web::index_json_identification;
use crate::web::{index_handler, read_tag_handler};
use anyhow::anyhow;
use axum::{Router, routing::get};
use log::{debug, error, info, warn, LevelFilter};
use r200_uhf::Rfid;
use r200_uhf::connector::{AsyncIO, Connector};
use std::env;
use std::io::Write;
use std::sync::{Arc, RwLock};
use std::time::Duration;
use tokio::time::sleep;
use tokio_serial::{DataBits, FlowControl, Parity, SerialPortBuilderExt, StopBits};
use tower_http::cors::{Any, CorsLayer};
const POWER_TRANSMISSION: f64 = 15.0;
#[tokio::main]
async fn main() {
env_logger::builder()
.filter_level(LevelFilter::Info)
.init();
info!("Starting up");
let (port_name, baud, power) = get_args().unwrap();
let card_state = Arc::new(RwLock::new(None::<Rfid>));
let card_state_clone = Arc::clone(&card_state);
tokio::spawn(async move {
monitor_rfid(
move |data| {
let state = Arc::clone(&card_state_clone);
async move {
debug!("Dati letti:");
debug!(" rssi: {}", data.rssi);
debug!(" pc: {}", data.pc);
debug!(" epc: {}", data.epc);
debug!(" crc: {}", data.crc);
let mut current = state.write().unwrap();
*current = Some(data);
}
},
port_name,
baud,
power,
)
.await;
});
run_webservice(card_state).await;
}
async fn run_webservice(card_state: Arc<RwLock<Option<Rfid>>>) {
info!("Starting webservice");
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
let app = Router::new()
.route("/", get(index_handler))
.route("/index.json", get(index_json_identification))
.route("/read-tag.json", get(read_tag_handler))
.layer(cors)
.with_state(card_state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
info!("Server in ascolto su http://0.0.0.0:3001");
info!("Endpoint disponibili:");
info!(" GET / - Pagina principale");
info!(" GET /read-tag.json - Dati carta (JSON)");
axum::serve(listener, app).await.unwrap();
}
pub fn get_args() -> anyhow::Result<(String, u32, f64)> {
debug!("Lettura args");
let args: Vec<String> = env::args().collect();
let port_name = if args.len() < 2 {
warn!("Porta non specificata, avvio selezione manuale.");
select_port()?
} else {
args[1].clone()
};
let baud: u32 = if args.len() > 2 {
args[2]
.parse()
.map_err(|_| anyhow!("Invalid baud rate".to_string()))?
} else {
115200
};
let power: f64 = if args.len() == 4 {
args[3]
.parse()
.map_err(|_| anyhow!("Invalid power 15 -> 23.6".to_string()))?
} else {
POWER_TRANSMISSION
};
debug!("{} - {} - {}", port_name, baud, power);
Ok((port_name, baud, power))
}
fn select_port() -> anyhow::Result<String> {
let all_ports = tokio_serial::available_ports()?;
let ports: Vec<_> = all_ports
.into_iter()
.filter(|p| p.port_name.contains("ttyUSB"))
.collect();
if ports.is_empty() {
return Err(anyhow!("Nessuna porta seriale ttyUSB trovata."));
}
let index;
if ports.len() > 1 {
println!("Porte seriali disponibili (filtrate per ttyUSB):");
for (i, p) in ports.iter().enumerate() {
println!("{}: {}", i, p.port_name);
}
print!("Seleziona il numero della porta: ");
std::io::stdout().flush()?;
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
index = input
.trim()
.parse()
.map_err(|_| anyhow!("Selezione non valida"))?;
if index >= ports.len() {
return Err(anyhow!("Indice fuori intervallo"));
}
}else {
index = 0;
}
Ok(ports[index].port_name.clone())
}
pub async fn monitor_rfid<F, Fut>(mut handler: F, port_name: String, baud: u32, power: f64)
where
F: FnMut(Rfid) -> Fut + Send + 'static,
Fut: std::future::Future<Output = ()> + Send,
{
info!("Opening port {} at {} baud...", port_name, baud);
let port = tokio_serial::new(&*port_name, baud)
.data_bits(DataBits::Eight)
.parity(Parity::None)
.stop_bits(StopBits::One)
.flow_control(FlowControl::None)
.open_native_async()
.unwrap();
let mut connector = Connector::new(port);
loop {
if connector
.stop_multiple_polling_instructions()
.await
.is_err()
{
error!("FAIL: Connector stop multiple polling");
sleep(Duration::from_millis(500)).await;
} else {
break;
}
}
let transmission_power = connector
.get_transmit_power()
.await
.map_err(|e| anyhow!(e.to_string()))
.unwrap();
info!("Transmission power {:?}", transmission_power);
if transmission_power != power {
info!(
"Set transmission power {:?}",
connector
.set_transmission_power(power)
.await
.map_err(|e| anyhow!(e.to_string()))
.unwrap()
);
}
info!("Background worker: Monitoraggio lettori avviato.");
loop {
if let Ok(i) = connector.single_polling_instruction().await {
if i.len() >= 1 {
let rfid = i.first().unwrap();
handler(rfid.clone()).await;
}
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
}