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

use defmt::*;
use embassy_executor::Spawner;
use embassy_time::Instant;
use embassy_stm32::dma::Request;
use embassy_stm32::gpio::{Input, Output, Level, Pull, Speed};
use dma_gpio::software_uart::{
    dma_timer::{init_tim6_for_uart, init_tim7_for_uart},
    debug::dump_tim6_regs,
};
use dma_gpio::config::{BAUD, RX_OVERSAMPLE, TX_OVERSAMPLE};
use dma_gpio::config::{TX_RING_BYTES, RX_RING_BYTES};
use static_cell::StaticCell;
use embassy_futures::yield_now;
use embassy_stm32::pac;
use embassy_stm32::interrupt;
use embassy_time::{Duration, Timer};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel};
use core::cell::RefCell;
use cortex_m::interrupt::Mutex;
use {defmt_rtt as _, panic_probe as _};

static RAW_BITS_CHANNEL: Channel<CriticalSectionRawMutex, u8, 1024> = Channel::new();

// ** NEW GLOBAL for TX pin (PB0) **
static TX_PIN_GLOBAL: Mutex<RefCell<Option<&'static mut Output<'static>>>> = Mutex::new(RefCell::new(None));
static RX_PIN_GLOBAL: Mutex<RefCell<Option<&'static Input<'static>>>> = Mutex::new(RefCell::new(None));

// Software uart
pub const TIM6_UP_REQ: Request = 4;
static SW_TX_RING: StaticCell<[u32; TX_RING_BYTES]> = StaticCell::new();
static SW_RX_RING: StaticCell<[u8; RX_RING_BYTES]> = StaticCell::new();

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    info!("boot");
    let p = embassy_stm32::init(Default::default());
    info!("init m8");

    // SOFTWARE UART
    let rx_pin = Input::new(p.PD6, Pull::Up);

    // Configure TX as output (PB0)
    let mut tx_pin = Output::new(p.PB0, Level::High, Speed::VeryHigh);

    // Make pins global so ISR can use them
    use cortex_m::interrupt::free;
    let tx_pin_ref: &'static mut Output<'static> = unsafe { core::mem::transmute(&mut tx_pin) };
    free(|cs| TX_PIN_GLOBAL.borrow(cs).replace(Some(tx_pin_ref)));
    let rx_pin_ref: &'static Input<'static> = unsafe { core::mem::transmute(&rx_pin) };
    free(|cs| RX_PIN_GLOBAL.borrow(cs).replace(Some(rx_pin_ref)));

    init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE);
    init_tim7_for_uart(p.TIM7, BAUD, RX_OVERSAMPLE);
    dump_tim6_regs();

    unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::TIM7) };

    let mut buf = [0u8; 32];

    loop {
        Timer::after(Duration::from_millis(1)).await;
        yield_now().await;
    }
}

#[interrupt]
fn TIM7() {
    let tim = unsafe { pac::TIM7 };
    if tim.sr().read().uif() {
        tim.sr().modify(|w| w.set_uif(false));

        cortex_m::interrupt::free(|cs| {
            if let Some(tx_pin) = TX_PIN_GLOBAL.borrow(cs).borrow_mut().as_mut() {
                tx_pin.toggle();
            }

            if let Some(rx_pin) = RX_PIN_GLOBAL.borrow(cs).borrow().as_ref() {
                if rx_pin.is_high() {
                    info!("1");
                } else {
                    info!("0");
                }
            }
        });
    }
}
