//! This module demonstrates basic reads and writes to and from onboard flash memory.

#![no_main]
#![no_std]

use core::cell::{Cell, RefCell};

use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry;
use critical_section::{Mutex, with};
use hal::{
    clocks::Clocks,
    flash::{Bank, Flash},
    low_power,
};

// Make sure the starting page isn't outside the available page range, and isn't in part of the
// flash memory taken up by your program. If you're not sure what to do, put something towards the end.
// Check your Reference Manual, FLASH section near the top for info on flash page size, and number
// of pages. Called "sector" on H7 and F4.
const FLASH_PAGE: usize = 254;

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

    let clock_cfg = Clocks::Default();
    clock_cfg.setup().unwrap();

    let mut flash = Flash::new(dp.FLASH);

    // Before any writes take place, you must erase the page the writes will take place on.
    // On H7, replace `page` with `sector`.
    flash.erase_page(Bank::B1, FLASH_PAGE).ok();

    // Note that if using L5, or some variants of G4 or L4, you can configure FLASH to operate in
    // dual bank mode by setting the DBANK option bit. This library won't set that for you, but you
    // can set it manually, then configure the `Flash` struct with the `dual_bank` field. By default,
    // it assumes single-bank config. Note that H7 is always dual bank, and other variants are always
    // single-bank. (F4 excepted)

    // Once a page is erased, we can write to it. Writes take place internally in 32-bit intervals
    // (H7 excepted; uses varying write sizes), but our API uses 8-bit buffers.
    flash.write_page(Bank::B1, FLASH_PAGE, &[1, 2, 3, 4]);

    // Alternatively, we can erase and write together using this function:
    flash.erase_write_page(Bank::B1, FLASH_PAGE, &[1, 2, 3, 4]);

    // We can read to a u8 buffer using the `read` method:
    let mut read_buf = [u8; 4];
    flash.read(Bank::B1, FLASH_PAGE, 0, read_buf);

    // Note: Some debugging setups will crash during flash page erases or writes. You can check if
    // this is the case (after receieving an `SwdAPWait` message etc by inspecing the FLASH written
    // using `Stm32CubeProgrammer`, and verifying that your program is still running through other means.

    loop {
        low_power::sleep_now();
    }
}

// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
fn panic() -> ! {
    cortex_m::asm::udf()
}
