WIP: Simple start project for mini simulator #126
@ -1,12 +1,13 @@
|
||||
use asynchronix::model::{Model, Output};
|
||||
use asynchronix::simulation::{EventSlot, Mailbox, SimInit};
|
||||
use asynchronix::time::{MonotonicTime, Scheduler};
|
||||
use log::warn;
|
||||
use log::{info, warn};
|
||||
use satrs::power::{SwitchState, SwitchStateBinary};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::f64::consts::PI;
|
||||
use std::future::Future;
|
||||
use std::net::UdpSocket;
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::sync::{mpsc, Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
|
||||
@ -127,6 +128,11 @@ pub enum PcduSwitches {
|
||||
Mgt = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum PcduRequest {
|
||||
RequestSwitchInfo,
|
||||
}
|
||||
|
||||
pub struct PcduModel {
|
||||
pub switcher_list: Output<Vec<SwitchStateBinary>>,
|
||||
pub mgm_switch: Output<SwitchState>,
|
||||
@ -213,29 +219,50 @@ impl MagnetorquerModel {
|
||||
|
||||
impl Model for MagnetorquerModel {}
|
||||
|
||||
// A UDP server which exposes all values generated by the simulator.
|
||||
pub struct UdpServer {
|
||||
// A UDP server which handles all TC received by a client application.
|
||||
pub struct UdpTcServer {
|
||||
socket: UdpSocket,
|
||||
mgm_out: EventSlot<MgmTuple>,
|
||||
last_sender: Arc<Mutex<Option<SocketAddr>>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ValueRequest {
|
||||
device: String,
|
||||
// A helper object which sends back all replies to the UDP client.
|
||||
//
|
||||
// This helper is scheduled separately to minimize the delay between the requests and replies.
|
||||
pub struct UdpTmSender {
|
||||
reply_receiver: mpsc::Receiver<ValueReply>,
|
||||
last_sender: Arc<Mutex<Option<SocketAddr>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum SimDevice {
|
||||
Mgm,
|
||||
Mgt,
|
||||
Pcdu,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SimRequest {
|
||||
device: SimDevice,
|
||||
request: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ValueReply {
|
||||
device: String,
|
||||
device: SimDevice,
|
||||
reply: String,
|
||||
}
|
||||
|
||||
const MGM_DEV_STR: &str = "mgm";
|
||||
struct ReplyHandler {
|
||||
reply_sender: mpsc::Sender<ValueReply>,
|
||||
}
|
||||
|
||||
impl UdpServer {
|
||||
pub fn new(mgm_out: EventSlot<MgmTuple>) -> io::Result<Self> {
|
||||
impl UdpTcServer {
|
||||
pub fn new(reply_receiver: mpsc::Receiver<ValueReply>) -> io::Result<Self> {
|
||||
let socket = UdpSocket::bind("0.0.0.0:7303")?;
|
||||
Ok(Self { socket, mgm_out })
|
||||
Ok(Self {
|
||||
socket,
|
||||
// reply_receiver,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
@ -253,28 +280,51 @@ impl UdpServer {
|
||||
let req_string = std::str::from_utf8(&buffer[..bytes_read])
|
||||
.expect("Could not write buffer as string");
|
||||
println!("Received from {}: {}", src, req_string);
|
||||
let value_result: serde_json::Result<ValueRequest> = serde_json::from_str(req_string);
|
||||
match value_result {
|
||||
Ok(value) => {
|
||||
if value.device == MGM_DEV_STR {
|
||||
let tuple = self.mgm_out.take().expect("expected output");
|
||||
let reply = ValueReply {
|
||||
device: MGM_DEV_STR.to_string(),
|
||||
reply: serde_json::to_string(&tuple).unwrap(),
|
||||
};
|
||||
let reply_string =
|
||||
serde_json::to_string(&reply).expect("generating reply string failed");
|
||||
self.socket
|
||||
.send_to(reply_string.as_bytes(), src)
|
||||
.expect("could not send data");
|
||||
}
|
||||
let sim_req: serde_json::Result<SimRequest> = serde_json::from_str(req_string);
|
||||
if sim_req.is_err() {
|
||||
warn!(
|
||||
"received UDP request with invalid format: {}",
|
||||
sim_req.unwrap_err()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let sim_req = sim_req.unwrap();
|
||||
match sim_req.device {
|
||||
SimDevice::Mgm => {
|
||||
self.handle_mgm_request(&src, &sim_req);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("received UDP request with invalid format: {e}");
|
||||
SimDevice::Mgt => {}
|
||||
SimDevice::Pcdu => {
|
||||
self.handle_pcdu_request(&src, &sim_req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_mgm_request(&mut self, sender: &SocketAddr, sim_req: &SimRequest) {
|
||||
/*
|
||||
let tuple = self.mgm_out.take().expect("expected output");
|
||||
let reply = ValueReply {
|
||||
device: sim_req.device,
|
||||
reply: serde_json::to_string(&tuple).unwrap(),
|
||||
};
|
||||
let reply_string = serde_json::to_string(&reply).expect("generating reply string failed");
|
||||
self.socket
|
||||
.send_to(reply_string.as_bytes(), sender)
|
||||
.expect("could not send data");
|
||||
*/
|
||||
}
|
||||
|
||||
fn handle_pcdu_request(&mut self, sender: &SocketAddr, sim_req: &SimRequest) {
|
||||
let pcdu_request: serde_json::Result<PcduRequest> = serde_json::from_str(&sim_req.request);
|
||||
if pcdu_request.is_err() {
|
||||
warn!(
|
||||
"received invalid PCDU request: {}",
|
||||
pcdu_request.unwrap_err()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_millis(time: MonotonicTime) -> u64 {
|
||||
@ -314,7 +364,7 @@ fn main() {
|
||||
|
||||
// This thread manages the simulator UDP server.
|
||||
let udp_thread = thread::spawn(move || {
|
||||
let mut server = UdpServer::new(output_slot).unwrap();
|
||||
let mut server = UdpTcServer::new(output_slot).unwrap();
|
||||
server.run();
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user