cu-flight-controller 1.2.0

This is a basic quadcopter Flight Controller implemented end to end using Copper components
extern crate alloc;

mod autonomy_bridge;
mod compute_tasks;
mod messages;

mod tasks {
    pub use crate::compute_tasks::*;
}

use cu29::prelude::memmap::{MmapSectionStorage, MmapUnifiedLoggerWrite};
use cu29::prelude::*;
use cu29::remote_debug::SessionOpenParams;
use cu29::replay::{
    ReplayCli, ReplayDefaults, per_session_replay_log_base, remove_log_family, serve_remote_debug,
};
use std::error::Error;
use std::path::Path;

const DEFAULT_DEBUG_BASE: &str = "copper/examples/cu_flight_controller/compute/debug/v1";
const DEFAULT_LOG_BASE: &str = "logs/flight_compute_sim.copper";
const DEFAULT_REPLAY_LOG_BASE: &str = "logs/flight_compute_resim.copper";
const REPLAY_LOG_SLAB_SIZE: Option<usize> = Some(128 * 1024 * 1024);

#[copper_runtime(
    config = "compute_config.ron",
    sim_mode = true,
    ignore_resources = true
)]
struct FlightComputeReSim {}

type ReplayCopperList = CopperList<default::CuStampedDataSet>;
type ReplayBuildCallback =
    for<'a> fn(
        &'a ReplayCopperList,
        RobotClock,
        RobotClockMock,
    ) -> Box<dyn for<'z> FnMut(default::SimStep<'z>) -> SimOverride + 'a>;
type ReplayTimeExtractor = fn(&ReplayCopperList) -> Option<CuTime>;

fn main() -> Result<(), Box<dyn Error>> {
    let cli = ReplayCli::parse(
        ReplayDefaults::new(DEFAULT_LOG_BASE, DEFAULT_REPLAY_LOG_BASE)
            .with_debug_base(DEFAULT_DEBUG_BASE),
    );
    let replay_template = cli.replay_log_base.clone();
    serve_remote_debug::<
        default::FlightComputeReSim,
        default::CuStampedDataSet,
        ReplayBuildCallback,
        ReplayTimeExtractor,
        MmapSectionStorage,
        MmapUnifiedLoggerWrite,
        _,
    >(
        cli.debug_base
            .as_deref()
            .expect("default debug base is always set"),
        &cli.log_base,
        move |params| app_factory(params, &replay_template),
        build_callback,
        extract_time,
    )?;
    Ok(())
}

fn app_factory(
    params: &SessionOpenParams,
    replay_template: &Path,
) -> CuResult<(default::FlightComputeReSim, RobotClock, RobotClockMock)> {
    let (clock, clock_mock) = RobotClock::mock();
    let replay_log_base = per_session_replay_log_base(
        replay_template,
        [params.role.as_deref().unwrap_or("session")],
    );
    remove_log_family(&replay_log_base)?;

    let mut default_callback = |_step: default::SimStep<'_>| SimOverride::ExecuteByRuntime;
    let app = default::FlightComputeReSim::builder()
        .with_clock(clock.clone())
        .with_log_path(replay_log_base, REPLAY_LOG_SLAB_SIZE)?
        .with_sim_callback(&mut default_callback)
        .build()?;

    // The replay session engine drives the raw lifecycle itself.
    Ok((app.into_inner(), clock, clock_mock))
}

fn build_callback<'a>(
    copperlist: &'a ReplayCopperList,
    _process_clock: RobotClock,
    _clock_for_cb: RobotClockMock,
) -> Box<dyn for<'z> FnMut(default::SimStep<'z>) -> SimOverride + 'a> {
    Box::new(move |step: default::SimStep<'_>| {
        default::recorded_debug_replay_step(step, copperlist)
    })
}

fn extract_time(copperlist: &ReplayCopperList) -> Option<CuTime> {
    cu29::simulation::recorded_copperlist_timestamp(copperlist)
}