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

use defmt::*;
use embassy_stm32::pac;
use embassy_stm32::Config as CPUConfig;
use embassy_stm32::rcc::PllDiv;
use embassy_stm32::rcc::PllMul;
use embassy_stm32::rcc::PllPreDiv;
use embassy_stm32::rcc::PllSource;
use embassy_stm32::rcc::Pll;
use embassy_stm32::rcc::Sysclk;
use embassy_executor::{Spawner, task};
use embassy_stm32::Config;
use embassy_stm32::gpio::{Output, Level, Speed};
use embassy_time::{Duration, Timer};

use dma_gpio::config::BAUD;
use dma_gpio::wakeup::iwdg::clear_wakeup_flags;
use dma_gpio::wakeup::gpio::gpio_wakeup;
use dma_gpio::logic::handler::execute_low_power;
use dma_gpio::hw_uart_pc::init::init_hw_uart_to_pc;
use dma_gpio::logic::uart_cmd::CMD_CH;
use {defmt_rtt as _, panic_probe as _};

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    info!("boot");
    let mut config = CPUConfig::default();
    config.rcc.hsi = true;
    config.rcc.sys = Sysclk::PLL1_R;
    config.rcc.pll1 = Some(Pll {
        source: PllSource::HSI,
        // 16 MHz / 1 × 20 / 2 = 160 MHz
        prediv: PllPreDiv::DIV1,
        mul:    PllMul::MUL20,
        divp:   None,
        divq:   None,
        divr:   Some(PllDiv::DIV2),
    });
    config.enable_independent_io_supply = true;
    config.enable_independent_analog_supply = true;

    let p = embassy_stm32::init(config);
    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)");

    // LED BLINK
    // spawner.spawn(led_blink(led).unwrap());
    
    // INIT HW UART
    init_hw_uart_to_pc(p.USART1, p.PA10, p.PA9, &spawner);

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

    use dma_gpio::config::WATCHDOG_TIMEOUT_US;
    info!(
        "Baud: {} bps | Watchdog: {}s\n\
         UART1 TX=PA9 RX=PA10\n\
         Modes via UART input:\n\
         [1] Standby + 8 KB SRAM2 retention\n\
         [2] Standby + full SRAM2 retention\n\
         [3] Standby — minimal power, SRAM2 lost\n\
         [4] Shutdown — lowest power, full reset on wake\n\
         [5] STOP mode (then choose: 0-3 for mode, 1-3 for entry method)",
         BAUD, WATCHDOG_TIMEOUT_US / 1_000_000
    );

    // disabling st-link debug
    dbg.cr().modify(|w| {
        w.set_dbg_standby(false);
        w.set_dbg_stop(false);
    });
    // END OF DEBUG INFO

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

    info!("ready for uart");
    let mut iwdg = Some(p.IWDG);
    
    spawner.spawn(gpio_wakeup(p.PA0, p.EXTI0).unwrap()); // exti wake up
    loop {
        let cmd = CMD_CH.receive().await;
        execute_low_power(cmd, &mut iwdg).await;
    }
}

#[task]
async fn led_blink(mut led: Output<'static>) {
    loop {
        led.toggle();
        Timer::after(Duration::from_millis(300)).await;
    }
}
