WIP: Simple start project for mini simulator #126

Closed
muellerr wants to merge 12 commits from lets-get-this-minsim-started into main
Showing only changes of commit b622e83731 - Show all commits

View File

@ -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();
});