use std::env;
use mendi::simulate::{SimConfig, SimulatedDevice};
use mendi::types::MendiEvent;
fn parse_arg(args: &[String], flag: &str) -> Option<String> {
args.windows(2)
.find(|w| w[0] == flag)
.map(|w| w[1].clone())
}
#[tokio::main]
async fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let args: Vec<String> = env::args().collect();
let mut config = SimConfig::default();
if let Some(hz) = parse_arg(&args, "--hz") {
config.frame_rate_hz = hz.parse().expect("--hz must be a number");
}
if let Some(n) = parse_arg(&args, "--frames").or_else(|| parse_arg(&args, "--disconnect")) {
config.disconnect_after_frames = Some(n.parse().expect("--frames must be a number"));
}
if let Some(v) = parse_arg(&args, "--voltage") {
config.battery_voltage_mv = v.parse().expect("--voltage must be a number");
}
if args.contains(&"--charging".to_string()) {
config.charging = true;
config.usb_connected = true;
}
eprintln!("Mendi Simulator");
eprintln!(" Frame rate: {} Hz", config.frame_rate_hz);
eprintln!(
" Disconnect: {}",
config
.disconnect_after_frames
.map(|n| format!("after {n} frames"))
.unwrap_or_else(|| "manual (Ctrl-C)".into())
);
eprintln!(" Battery: {} mV ({}%)", config.battery_voltage_mv, {
use mendi::types::{BATTERY_VOLTAGE_MIN_MV, BATTERY_VOLTAGE_MAX_MV};
let v = config.battery_voltage_mv;
if v <= BATTERY_VOLTAGE_MIN_MV {
0
} else if v >= BATTERY_VOLTAGE_MAX_MV {
100
} else {
((v - BATTERY_VOLTAGE_MIN_MV) as f32
/ (BATTERY_VOLTAGE_MAX_MV - BATTERY_VOLTAGE_MIN_MV) as f32
* 100.0)
.round() as u32
}
});
eprintln!();
let (mut rx, handle) = SimulatedDevice::start(config);
let running = handle.running_flag();
tokio::spawn(async move {
tokio::signal::ctrl_c().await.ok();
eprintln!("\nCtrl-C received, stopping simulation …");
running.store(false, std::sync::atomic::Ordering::SeqCst);
});
let mut frame_count: u64 = 0;
while let Some(event) = rx.recv().await {
match event {
MendiEvent::Connected(info) => {
println!("✅ Connected: {info}");
}
MendiEvent::Disconnected => {
println!("❌ Disconnected after {frame_count} frames.");
break;
}
MendiEvent::Frame(f) => {
frame_count += 1;
if frame_count <= 3 || frame_count.is_multiple_of(25) {
println!(
"[FRAME #{frame_count}] temp={:.1}°C \
L(ir={:6} red={:6}) R(ir={:6} red={:6}) P(ir={:6} red={:6})",
f.temperature,
f.ir_left, f.red_left,
f.ir_right, f.red_right,
f.ir_pulse, f.red_pulse,
);
}
}
MendiEvent::Battery(b) => {
println!(
"[BATTERY] {:.2}V {}% charging={}",
b.voltage(),
b.percentage(),
b.charging,
);
}
MendiEvent::Calibration(c) => {
println!(
"[CALIBRATION] L={:.1} R={:.1} P={:.1} auto={}",
c.offset_left, c.offset_right, c.offset_pulse, c.auto_calibration,
);
}
MendiEvent::Diagnostics(d) => {
println!(
"[DIAGNOSTICS] imu={} sensor={}",
d.imu_ok, d.sensor_ok,
);
}
MendiEvent::SensorRead(s) => {
println!("[SENSOR] addr=0x{:02X} data=0x{:06X}", s.address, s.data);
}
}
}
handle.join().await;
}