//! DMA interleaved transfer example for MCXA276.
//!
//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
//! a high-level and safe API for. It should not be taken as typical, recommended, or
//! stable usage!
//!
//! This example demonstrates using DMA with custom source/destination offsets
//! to interleave data during transfer.
//!
//! # Embassy-style features demonstrated:
//! - `TransferOptions::default()` for configuration (used internally)
//! - DMA channel with `DmaChannel::new()`

#![no_std]
#![no_main]

use embassy_executor::Spawner;
use embassy_mcxa::clocks::config::Div8;
use embassy_mcxa::dma::DmaChannel;
use static_cell::ConstStaticCell;
use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};

const BUFFER_LENGTH: usize = 16;
const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2;

// Buffers in RAM
static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]);
static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]);

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    // Small delay to allow probe-rs to attach after reset
    for _ in 0..100_000 {
        cortex_m::asm::nop();
    }

    let mut cfg = hal::config::Config::default();
    cfg.clock_cfg.sirc.fro_12m_enabled = true;
    cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
    let p = hal::init(cfg);

    defmt::info!("DMA interleave transfer example starting...");

    defmt::info!("EDMA interleave transfer example begin.");

    // Initialize buffers
    let src = SRC_BUFFER.take();
    *src = [1, 2, 3, 4, 5, 6, 7, 8];
    let dst = DEST_BUFFER.take();

    defmt::info!("Source Buffer: {=[?]}", src.as_slice());
    defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());

    defmt::info!("Configuring DMA with Embassy-style API...");

    // Create DMA channel using Embassy-style API
    let dma_ch0 = DmaChannel::new(p.DMA_CH0);

    // Configure interleaved transfer using direct TCD access:
    // - src_offset = 4: advance source by 4 bytes after each read
    // - dst_offset = 8: advance dest by 8 bytes after each write
    // This spreads source data across every other word in destination
    unsafe {
        let t = dma_ch0.tcd();

        // Reset channel state
        t.ch_csr().write(|w| {
            w.erq()
                .disable()
                .earq()
                .disable()
                .eei()
                .no_error()
                .ebw()
                .disable()
                .done()
                .clear_bit_by_one()
        });
        t.ch_es().write(|w| w.bits(0));
        t.ch_int().write(|w| w.int().clear_bit_by_one());

        // Source/destination addresses
        t.tcd_saddr().write(|w| w.saddr().bits(src.as_ptr() as u32));
        t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32));

        // Custom offsets for interleaving
        t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read
        t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write

        // Attributes: 32-bit transfers (size = 2)
        t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2));

        // Transfer entire source buffer in one minor loop
        let nbytes = (HALF_BUFF_LENGTH * 4) as u32;
        t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));

        // Reset source address after major loop
        t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32));
        // Destination uses 2x offset, so adjust accordingly
        let dst_total = (HALF_BUFF_LENGTH * 8) as u32;
        t.tcd_dlast_sga()
            .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32));

        // Major loop count = 1
        t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
        t.tcd_citer_elinkno().write(|w| w.citer().bits(1));

        // Enable interrupt on major loop completion
        t.tcd_csr().write(|w| w.intmajor().set_bit());

        cortex_m::asm::dsb();

        defmt::info!("Triggering transfer...");
        dma_ch0.trigger_start();
    }

    // Wait for completion using channel helper method
    while !dma_ch0.is_done() {
        cortex_m::asm::nop();
    }
    unsafe {
        dma_ch0.clear_done();
    }

    defmt::info!("EDMA interleave transfer example finish.");
    defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());

    // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0
    let mut mismatch = false;
    let diter = dst.chunks_exact(2);
    let siter = src.iter();
    for (ch, src) in diter.zip(siter) {
        mismatch |= !matches!(ch, [a, 0] if a == src);
    }

    if mismatch {
        defmt::error!("FAIL: Mismatch detected!");
    } else {
        defmt::info!("PASS: Data verified.");
    }
}
