// If rust-analyzer says it can't find `test`, you need to disable `allTargets` in it's
// configuration. This project has a `.cargo/config.toml` file that explicitly sets targets.
// See https://github.com/rust-lang/rust-analyzer/issues/3297
#![no_std]
#![no_main]

#[cfg(not(all(target_os = "none", target_pointer_width = "32", target_arch = "arm")))]
compile_error!("This program can only be compiled for arm32 bare metal");

use defmt::{debug, info};
use panic_probe as _;

use defmt_rtt as _; // global logger

use cortex_m_rt::entry;
use hal::{
    pac::{self},
    prelude::*,
    rcc::Config,
};

use crate::bench::MeasurePins;

mod bench;
mod error_handlers; // defines a handler for evil hardfaults

#[entry]
fn main() -> ! {
    let dp = pac::Peripherals::take().unwrap();
    let mut cp = cortex_m::Peripherals::take().unwrap();

    // Configure the clock.
    let mut rcc = dp.RCC.freeze(Config::hsi16());

    // Acquire the GPIOA peripheral. This also enables the clock for GPIOA in
    // the RCC register.
    let gpioa = dp.GPIOA.split(&mut rcc);
    let gpiob = dp.GPIOB.split(&mut rcc);

    // This is D4 on CN19 for the NCLEO L053R8 according to the user manual:
    // "UM1724"
    let mut measurepin_0 = gpiob.pb5.into_push_pull_output().downgrade();
    // This is D5 on CN19 for the NCLEO L053R8
    let mut measurepin_1 = gpiob.pb4.into_push_pull_output().downgrade();
    let mut led = gpioa.pa5.into_push_pull_output().downgrade(); // this is the led

    measurepin_0.set_low().unwrap();
    led.set_low().unwrap();

    // setup timer for measuring time of benchmarks
    cp.SYST.set_reload(0x00ffffff); // max
    cp.SYST.clear_current();
    cp.SYST.enable_counter();

    let mut delay = cp.SYST.delay(rcc.clocks);

    debug!("Asserting that libalgorithms is correctly loaded");
    assert!(algorithms::ffi_is_loaded(), "ffi is not loaded?");

    let mut measurepins = bench::MeasurePins {
        c: &mut measurepin_0,
        rs: &mut measurepin_1,
        led: &mut led,
    };

    info!("Starting the Rust vs C benchmark");
    bench::bench(&mut measurepins, &mut delay);
    info!("Benchmark done");

    measurepins.set_all(PinState::Low);

    loop {
        delay.delay_ms(5000u32);
    }
}
