cu-flight-controller 1.0.0

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

mod messages;
mod sim_support;
mod 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/debug/v1";
const DEFAULT_LOG_BASE: &str = "logs/flight_controller_sim.copper";
const DEFAULT_REPLAY_LOG_BASE: &str = "logs/flight_controller_resim.copper";
const REPLAY_LOG_SLAB_SIZE: Option<usize> = Some(128 * 1024 * 1024);

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

type ReplayCopperList = CopperList<gnss::CuStampedDataSet>;
type ReplayBuildCallback =
    for<'a> fn(
        &'a ReplayCopperList,
        RobotClock,
        RobotClockMock,
    ) -> Box<dyn for<'z> FnMut(gnss::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::<
        gnss::FlightControllerReSim,
        gnss::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<(gnss::FlightControllerReSim, 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: gnss::SimStep<'_>| SimOverride::ExecuteByRuntime;
    let app = gnss::FlightControllerReSim::builder()
        .with_clock(clock.clone())
        .with_log_path(replay_log_base, REPLAY_LOG_SLAB_SIZE)?
        .with_sim_callback(&mut default_callback)
        .build()?;

    Ok((app, clock, clock_mock))
}

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

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