// src/bin/main.rs
#![no_std]
#![no_main]

use defmt::*;
use embassy_stm32::pac;
use embassy_executor::Spawner;
use embassy_futures::yield_now;
use embassy_stm32::bind_interrupts;
use embassy_stm32::peripherals;
use embassy_stm32::Config;
use embassy_stm32::usart::{BufferedUart, Config as UsartConfig, BufferedInterruptHandler};
use embassy_stm32::gpio::{Output, Level, Speed};
use embassy_time::{Duration, Timer};

use static_cell::StaticCell;
use dma_gpio::config::{
    BAUD, PIPE_HW_RX, PIPE_HW_TX,
};
use dma_gpio::hw_uart_pc::{driver::uart_task, usart1};
use dma_gpio::wakeup::iwdg::{clear_wakeup_flags, init_watchdog};
use dma_gpio::sleep::shutdown::enter_shutdown;
use dma_gpio::sleep::standby;
use {defmt_rtt as _, panic_probe as _};

bind_interrupts!(struct Irqs {
    USART1 => BufferedInterruptHandler<peripherals::USART1>;
});

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    info!("boot");
    let p = embassy_stm32::init(Config::default());
    let mut led = Output::new(p.PA3, Level::Low, Speed::Low);
    let _led_ground = Output::new(p.PB0, Level::Low, Speed::Low);
    info!("init m8");

    clear_wakeup_flags();

    led.set_high();
    info!("LED ON (MCU awake)");

    // HARDWARE UART to the PC
    let mut cfg = UsartConfig::default();
    cfg.baudrate = BAUD;
    static TX_BUF: StaticCell<[u8; 256]> = StaticCell::new();
    static RX_BUF: StaticCell<[u8; 256]> = StaticCell::new();
    let uart = BufferedUart::new(
        p.USART1,
        p.PA10, // RX pin
        p.PA9,  // TX pin
        TX_BUF.init([0; 256]),
        RX_BUF.init([0; 256]),
        Irqs,
        cfg,
    ).unwrap();
    // let yield_period = usart1::setup_and_spawn(BAUD);
    spawner.spawn(uart_task(uart, &PIPE_HW_TX, &PIPE_HW_RX).unwrap());
    // END OF HARDWARE UART to the PC

    let dbg = pac::DBGMCU;
    let cr = dbg.cr().read();
    info!("DBGMCU CR: dbg_stop={}, dbg_standby={}", cr.dbg_stop(), cr.dbg_standby());

    // MAIN LOOP
    Timer::after(Duration::from_millis(500)).await;

    init_watchdog(p.IWDG).await;
    Timer::after(Duration::from_millis(10)).await;

    loop {
        info!("entering shutdown");
        // enter_shutdown();
        info!("shutdown");
        standby::enter_standby_with_sram2_full();
        cortex_m::asm::wfi();
        yield_now().await;
    }
}
