// src/software_uart/runtime.rs
use embassy_executor::task;
use embassy_stm32::{
    dma::Request,
    peripherals::GPDMA1_CH1,
    Peri,
};
use crate::config::RX_PIN_BIT;
use embassy_stm32::dma::{
    ReadableRingBuffer,
    TransferOptions,
};
use crate::config::{RX_OVERSAMPLE, UART_CFG};
use crate::software_uart::decode_uart_samples;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe};
use embassy_futures::yield_now;
use defmt::info;

// datasheet tabulka 137
pub const TIM7_UP_REQ: Request = 5;

/// RX DMA task: reads GPIO samples paced by TIM7 and fills PIPE_RX
#[task]
pub async fn rx_dma_task(
    ch: Peri<'static, GPDMA1_CH1>,
    ring: &'static mut [u8],
    pipe_rx: &'static Pipe<CriticalSectionRawMutex, 1024>,
) {
    let gpioa_idr = embassy_stm32::pac::GPIOA.idr().as_ptr() as *mut u8;

    let mut opts = TransferOptions::default();
    opts.half_transfer_ir = true;
    opts.complete_transfer_ir = true;

    // SAFETY: ring is exclusive to this task
    let mut rx = unsafe { ReadableRingBuffer::new(ch, TIM7_UP_REQ, gpioa_idr, ring, opts) };
    rx.start();

    let mut raw_chunk = [0u8; 256];
    let mut levels = [0u8; 256];
    loop {
        info!("rx_dma_task waiting for DMA data...");
        let _ = rx.read_exact(&mut raw_chunk).await;

        for (i, b) in raw_chunk.iter().enumerate() {
            levels[i] = ((*b >> RX_PIN_BIT) & 1) as u8;
        }

        let decoded = decode_uart_samples(&levels, RX_OVERSAMPLE, &UART_CFG);
        if !decoded.is_empty() {
            info!("SW RX raw samples (first 32): {:a}", &levels[..32]);
            info!(
                "SW RX decoded {} bytes: {:a}",
                decoded.len(),
                decoded.as_slice()
            );
        }
        pipe_rx.write(&decoded).await;
        yield_now().await;
    }
}
