// 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>,
    register: *mut u8,
    ring: &'static mut [u8],
    pipe_rx: &'static Pipe<CriticalSectionRawMutex, 1024>,
) {
    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, register, ring, opts) };
    rx.start();

    let mut raw_chunk = [0u8; 256];
    let mut levels = [0u8; 256];
    let mut last_bytes: [u8; 16] = [0; 16];   // remember previous 16 samples
    let mut last_value: u8 = 0;              // remember previous single IDR sample (optional)

    loop {
        let _ = rx.read_exact(&mut raw_chunk).await;

        // If nothing has changed (all bytes same as previous), skip logging
        if raw_chunk[..16] == last_bytes[..] {
            continue;
        }

        // Save for next comparison
        last_bytes.copy_from_slice(&raw_chunk[..16]);
        let current_avg = raw_chunk[0];

        // Optionally only if single sample changed
        if current_avg != last_value {
            last_value = current_avg;

            info!(
                "DMA change detected: IDR[0..16]={=[u8]:02X} bit{}={}",
                &raw_chunk[..16],
                RX_PIN_BIT,
                (current_avg >> RX_PIN_BIT) & 1
            );
        }

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

        let (decoded, consumed) = decode_uart_samples(&levels, RX_OVERSAMPLE, &UART_CFG);
        if !decoded.is_empty() {
            info!("SW RX decoded {:a}", decoded.as_slice());
            pipe_rx.write(decoded.as_slice()).await;
        }

        yield_now().await;
    }
}
