Skip to content

Commit 46cb208

Browse files
Florian Guggiflorg-32
authored andcommitted
feat: Extend host CLI runner to work with a connected EDU
1 parent 1daa1ed commit 46cb208

File tree

3 files changed

+69
-32
lines changed

3 files changed

+69
-32
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scheduler/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ mock = []
2424
rpi = []
2525

2626
[dev-dependencies]
27+
clap = "4.5.47"
2728
file-per-thread-logger = "0.2.0"
2829
inquire = "0.7.5"
2930
test-case = "3.3.1"

scheduler/examples/cli.rs

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,60 @@
1+
use clap::Parser;
12
use std::{
23
error::Error,
34
io::{Read, Write},
45
path::{Path, PathBuf},
56
process::{Child, ChildStdin, ChildStdout, Stdio},
67
time::Duration,
78
};
8-
99
use STS1_EDU_Scheduler::communication::{CEPPacket, CommunicationHandle};
1010

11+
#[derive(clap::Parser)]
12+
enum Args {
13+
/// Simulate a serialport through socat, with the scheduler running on your host
14+
Simulate {
15+
#[arg(default_value = "target/release")]
16+
target_dir: PathBuf,
17+
},
18+
/// Connect serialport which has an EDU already running
19+
Serial {
20+
serialport: String,
21+
#[arg(long, short, default_value_t = 115200)]
22+
baudrate: u32,
23+
},
24+
}
25+
1126
fn main() {
12-
let scheduler_path = PathBuf::from(
13-
std::env::args().nth(1).expect("Pass in the directory containing the scheduler binary"),
14-
);
15-
16-
let mut serial = SocatSerialPort::new(&scheduler_path.join("virtualserial"));
17-
write_scheduler_config(&scheduler_path);
18-
let _scheduler = PoisonedChild(
19-
std::process::Command::new("./STS1_EDU_Scheduler")
20-
.current_dir(&scheduler_path)
21-
.spawn()
22-
.unwrap(),
23-
);
27+
let args = Args::parse();
2428

29+
match args {
30+
Args::Simulate { target_dir } => {
31+
write_scheduler_config(&target_dir);
32+
let mut handle = SimulationContext::new(&target_dir.join("virtualserial"));
33+
inquire_loop(&mut handle);
34+
}
35+
Args::Serial { serialport, baudrate } => {
36+
let mut serial = serialport::new(serialport, baudrate).open().unwrap();
37+
inquire_loop(&mut serial);
38+
}
39+
};
40+
}
41+
42+
fn inquire_loop(handle: &mut impl CommunicationHandle) -> ! {
2543
loop {
26-
inquire_and_send_command(&mut serial, &scheduler_path).unwrap();
44+
inquire_and_send_command(handle).unwrap();
2745
println!("------------------------");
2846
std::thread::sleep(Duration::from_millis(100));
2947
}
3048
}
3149

32-
pub struct SocatSerialPort<T: Read, U: Write> {
33-
child: Child,
50+
pub struct SimulationContext<T: Read, U: Write> {
51+
socat: Child,
52+
_scheduler: PoisonedChild,
3453
stdout: T,
3554
stdin: U,
3655
}
3756

38-
impl SocatSerialPort<ChildStdout, ChildStdin> {
57+
impl SimulationContext<ChildStdout, ChildStdin> {
3958
fn new(path: &Path) -> Self {
4059
let mut child = std::process::Command::new("socat")
4160
.arg("stdio")
@@ -52,9 +71,13 @@ impl SocatSerialPort<ChildStdout, ChildStdin> {
5271
std::thread::sleep(Duration::from_millis(50));
5372
}
5473

74+
let scheduler = PoisonedChild(
75+
std::process::Command::new("./STS1_EDU_Scheduler").current_dir(path).spawn().unwrap(),
76+
);
77+
5578
let stdout = child.stdout.take().unwrap();
5679
let stdin = child.stdin.take().unwrap();
57-
Self { child, stdout, stdin }
80+
Self { socat: child, _scheduler: scheduler, stdout, stdin }
5881
}
5982
}
6083

@@ -77,14 +100,8 @@ fn write_scheduler_config(path: &Path) {
77100
const COMMANDS: &[&str] =
78101
&["StoreArchive", "ExecuteProgram", "StopProgram", "GetStatus", "ReturnResult", "UpdateTime"];
79102

80-
fn inquire_and_send_command(
81-
edu: &mut impl CommunicationHandle,
82-
path: &Path,
83-
) -> Result<(), Box<dyn Error>> {
84-
let mut select = inquire::Select::new("Select command", COMMANDS.to_vec());
85-
if path.join("updatepin").exists() {
86-
select.help_message = Some("Update Pin is high");
87-
}
103+
fn inquire_and_send_command(edu: &mut impl CommunicationHandle) -> Result<(), Box<dyn Error>> {
104+
let select = inquire::Select::new("Select command", COMMANDS.to_vec());
88105
let command = select.prompt()?;
89106

90107
match command {
@@ -148,19 +165,30 @@ fn inquire_and_send_command(
148165
Err(e) => println!("Received {e:?}"),
149166
}
150167
}
151-
_ => (),
168+
"UpdateTime" => {
169+
let actual = std::time::SystemTime::now()
170+
.duration_since(std::time::UNIX_EPOCH)
171+
.unwrap()
172+
.as_secs();
173+
let since_epoch = inquire::prompt_u32("Seconds since epoch (empty for current time):")
174+
.unwrap_or(actual as u32);
175+
176+
edu.send_packet(&CEPPacket::Data(update_time(since_epoch)))?;
177+
println!("Received {:?}", edu.receive_packet()?);
178+
}
179+
c => unimplemented!("{c}"),
152180
}
153181

154182
Ok(())
155183
}
156184

157-
impl<T: Read, U: Write> Read for SocatSerialPort<T, U> {
185+
impl<T: Read, U: Write> Read for SimulationContext<T, U> {
158186
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
159187
self.stdout.read(buf)
160188
}
161189
}
162190

163-
impl<T: Read, U: Write> Write for SocatSerialPort<T, U> {
191+
impl<T: Read, U: Write> Write for SimulationContext<T, U> {
164192
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
165193
self.stdin.write(buf)
166194
}
@@ -170,13 +198,13 @@ impl<T: Read, U: Write> Write for SocatSerialPort<T, U> {
170198
}
171199
}
172200

173-
impl<T: Read, U: Write> Drop for SocatSerialPort<T, U> {
201+
impl<T: Read, U: Write> Drop for SimulationContext<T, U> {
174202
fn drop(&mut self) {
175-
self.child.kill().unwrap();
203+
self.socat.kill().unwrap();
176204
}
177205
}
178206

179-
impl<T: Read, U: Write> CommunicationHandle for SocatSerialPort<T, U> {
207+
impl<T: Read, U: Write> CommunicationHandle for SimulationContext<T, U> {
180208
const INTEGRITY_ACK_TIMEOUT: Duration = Duration::MAX;
181209
const UNLIMITED_TIMEOUT: Duration = Duration::MAX;
182210

@@ -223,3 +251,10 @@ pub fn return_result(program_id: u16, timestamp: u32) -> Vec<u8> {
223251
vec.extend(timestamp.to_le_bytes());
224252
vec
225253
}
254+
255+
#[must_use]
256+
pub fn update_time(since_epoch: u32) -> Vec<u8> {
257+
let mut vec = vec![6u8];
258+
vec.extend(since_epoch.to_le_bytes());
259+
vec
260+
}

0 commit comments

Comments
 (0)