use semtech_udp::{
pull_resp,
server_runtime::{Event, UdpRuntime},
MacAddress, StringOrNum,
};
use std::net::SocketAddr;
use structopt::StructOpt;
use tokio::sync::oneshot::{self, Receiver, Sender};
use tokio::time::{delay_for as sleep, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Opt::from_args();
let addr = SocketAddr::from(([0, 0, 0, 0], cli.port));
println!("Starting server: {}", addr);
let (mut client_rx, mut client_tx) = UdpRuntime::new(addr).await?.split();
let (tx, rx): (Sender<MacAddress>, Receiver<MacAddress>) = oneshot::channel();
let mut tx = Some(tx);
tokio::spawn(async move {
let gateway_mac = rx.await.unwrap();
let mut first_shot = true;
while cli.delay != 0 || first_shot {
first_shot = false;
let buffer = vec![0; cli.length];
let size = buffer.len() as u64;
let data = base64::encode(buffer);
let tmst = StringOrNum::N(0);
let txpk = pull_resp::TxPk {
imme: true,
tmst,
freq: cli.frequency,
rfch: 0,
powe: cli.power as u64,
modu: "LORA".to_string(),
datr: cli.data_rate.clone(),
codr: "4/5".to_string(),
ipol: cli.polarization_inversion,
size,
data,
tmms: None,
fdev: None,
prea: None,
ncrc: None,
};
println!("Sending: {:?}", txpk);
let prepared_send = client_tx.prepare_downlink(Some(txpk), gateway_mac);
tokio::spawn(async move {
if let Err(e) = prepared_send.dispatch(Some(Duration::from_secs(5))).await {
panic!("Transmit Dispatch threw error: {:?}", e)
} else {
println!("Send complete");
}
});
sleep(Duration::from_secs(cli.delay)).await;
}
});
println!("Ready for clients");
loop {
match client_rx.recv().await {
Event::UnableToParseUdpFrame(buf) => {
println!("Semtech UDP Parsing Error");
println!("UDP data: {:?}", buf);
}
Event::NewClient((mac, addr)) => {
println!("New packet forwarder client: {}, {}", mac, addr);
if let Some(tx) = tx.take() {
tx.send(mac).unwrap();
}
}
Event::UpdateClient((mac, addr)) => {
println!("Mac existed, but IP updated: {}, {}", mac, addr);
}
Event::PacketReceived(rxpk, addr) => {
println!("Packet Receveived from {}:", addr);
println!("{:?}", rxpk);
}
Event::NoClientWithMac(_packet, mac) => {
println!("Tried to send to client with unknown MAC: {:?}", mac)
}
Event::RawPacket(_) => (),
}
}
}
#[derive(Debug, StructOpt)]
#[structopt(name = "semtech-server", about = "LoRa test device utility")]
pub struct Opt {
#[structopt(long, default_value = "1680")]
port: u16,
#[structopt(long, default_value = "27")]
power: u8,
#[structopt(long, default_value = "52")]
length: usize,
#[structopt(long, default_value = "0")]
delay: u64,
#[structopt(long, default_value = "868.1")]
frequency: f64,
#[structopt(long, default_value = "SF12BW125")]
data_rate: String,
#[structopt(long)]
polarization_inversion: bool,
}