use std::fs;
use std::path::{Path, PathBuf};
use cu29::bincode::{Decode, Encode};
use cu29::clock::RobotClock;
use cu29::prelude::app::CuSimApplication;
use cu29::prelude::memmap::{MmapSectionStorage, MmapUnifiedLoggerWrite};
use cu29::prelude::*;
use cu29::simulation::{CuTaskCallbackState, SimOverride};
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct MyMsg {
pub value: u32,
}
pub struct MySource {
next: u32,
}
impl Freezable for MySource {}
impl CuSrcTask for MySource {
type Output<'m> = output_msg!(MyMsg);
fn new(_config: Option<&ComponentConfig>) -> CuResult<Self> {
Ok(Self { next: 0 })
}
fn process(&mut self, _clock: &RobotClock, out: &mut Self::Output<'_>) -> CuResult<()> {
self.next += 1;
out.set_payload(MyMsg { value: self.next });
panic!("This source should never be called from the sim");
}
}
pub struct Doubler;
impl Freezable for Doubler {}
impl CuTask for Doubler {
type Input<'m> = input_msg!(MyMsg);
type Output<'m> = output_msg!(MyMsg);
fn new(_config: Option<&ComponentConfig>) -> CuResult<Self> {
Ok(Self)
}
fn process(
&mut self,
_clock: &RobotClock,
input: &Self::Input<'_>,
output: &mut Self::Output<'_>,
) -> CuResult<()> {
if let Some(m) = input.payload() {
output.set_payload(MyMsg { value: m.value * 2 });
} else {
output.clear_payload();
}
Ok(())
}
}
pub struct MySink;
impl Freezable for MySink {}
impl CuSinkTask for MySink {
type Input<'m> = input_msg!(MyMsg);
fn new(_config: Option<&ComponentConfig>) -> CuResult<Self> {
Ok(Self)
}
fn process(&mut self, _clock: &RobotClock, input: &Self::Input<'_>) -> CuResult<()> {
if let Some(m) = input.payload() {
println!("[MySink] got value = {}", m.value);
} else {
println!("[MySink] got no payload");
}
Ok(())
}
}
#[copper_runtime(config = "copperconfig.ron", sim_mode = true)]
struct App {}
fn main() -> CuResult<()> {
let mut sim_counter: u32 = 0;
let mut sim_callback = move |step: <App as CuSimApplication<
MmapSectionStorage,
MmapUnifiedLoggerWrite,
>>::Step<'_>|
-> SimOverride {
match step {
default::SimStep::Src(CuTaskCallbackState::New(_)) => SimOverride::ExecuteByRuntime,
default::SimStep::Src(CuTaskCallbackState::Process((), out)) => {
sim_counter += 1;
out.set_payload(MyMsg { value: sim_counter });
SimOverride::ExecutedBySim
}
default::SimStep::Proc(CuTaskCallbackState::Process(_, _)) => {
SimOverride::ExecuteByRuntime
}
default::SimStep::Sink(CuTaskCallbackState::Process(_, _)) => {
SimOverride::ExecuteByRuntime
}
_ => SimOverride::ExecuteByRuntime,
}
};
#[allow(clippy::identity_op)]
const LOG_SLAB_SIZE: Option<usize> = Some(1 * 1024 * 1024 * 1024);
let logger_path = "logs/run_in_sim.copper";
if let Some(parent) = Path::new(logger_path).parent() {
if !parent.exists() {
fs::create_dir_all(parent).expect("Failed to create logs directory");
}
}
let (robot_clock, _mock) = RobotClock::mock();
let copper_ctx = cu29_helpers::basic_copper_setup(
&PathBuf::from(logger_path),
LOG_SLAB_SIZE,
true,
Some(robot_clock.clone()),
)
.expect("Failed to setup logger.");
debug!(
"Logger created at {}. This is a simulation.",
path = logger_path
);
let mut copper_app = AppBuilder::new()
.with_context(&copper_ctx)
.with_sim_callback(&mut sim_callback)
.build()
.expect("Failed to create runtime.");
copper_app.start_all_tasks(&mut sim_callback)?;
for _ in 0..5 {
copper_app.run_one_iteration(&mut sim_callback)?;
}
copper_app.stop_all_tasks(&mut sim_callback)?;
Ok(())
}