//! SPI slave loopback test using DMA
//!
//! The following wiring is assumed for the (bitbang) slave:
//!
//! - SCLK => GPIO10
//! - MISO => GPIO11
//! - MOSI => GPIO12
//! - CS   => GPIO13
//!
//! 13 -> 21
//! 12 -> 22
//! 11 -> 35
//! 10 -> 27
//!
//! The following wiring is assumed for the (bitbang) master:
//! - SCLK => GPIO27
//! - MISO => GPIO35
//! - MOSI => GPIO22
//! - CS   => GPIO21
//!
//! Depending on your target and the board you are using you have to change the
//! pins.
//!
//! This example transfers data via SPI.
//!
//! Connect corresponding master and slave pins to see the outgoing data is read
//! as incoming data. The master-side pins are chosen to make these connections
//! easy for the barebones chip; all are immediate neighbors of the slave-side
//! pins except SCLK. SCLK is between MOSI and VDD3P3_RTC on the barebones chip,
//! so no immediate neighbor is available.

//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: esp-hal/unstable

#![no_std]
#![no_main]

use embassy_executor::Spawner;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, watch::Watch};
use embassy_time::{Duration, Timer};
use embedded_hal::digital::OutputPin;
use esp_backtrace as _;
use esp_hal::{
    gpio::{Event, Io},
    handler,
    peripheral::Peripheral,
    ram,
    spi::master::Spi,
    timer::timg::TimerGroup,
};

use esp_backtrace as _;
use esp_hal::{
    delay::Delay,
    dma_buffers,
    gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull},
    main, spi,
};
use esp_println::println;

static mut MASTER_RECEIVE: [u8; 32000] = [0; 32000];
static mut MASTER_SEND: [u8; 32000] = [0; 32000];

#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
    println!("SPI slave loopback test using DMA");
    println!("This example transfers data via SPI.");

    let peripherals = esp_hal::init(esp_hal::Config::default());

    let timg0 = TimerGroup::new(peripherals.TIMG0);
    esp_hal_embassy::init(timg0.timer0);
    /*
        let mut master_sclk = Output::new(peripherals.GPIO27, Level::Low, OutputConfig::default());
        let master_miso = Input::new(
            peripherals.GPIO35,
            InputConfig::default().with_pull(Pull::None),
        );
        let mut master_mosi = Output::new(peripherals.GPIO22, Level::Low, OutputConfig::default());

        */
    let mut master_cs = Output::new(peripherals.GPIO21, Level::High, OutputConfig::default());
    
    let mut master_send = unsafe { &mut MASTER_SEND };
    let mut master_receive = unsafe { &mut MASTER_RECEIVE };

    let mut i = 0;

    // Initialize master_send with a simple pattern
    master_send.fill(0xAA); // Fill with pattern 10101010

    // Set up the CS interrupt
    spawner.spawn(background_task()).unwrap();

    let mut master_spi = Spi::new(
        peripherals.SPI3,
        esp_hal::spi::master::Config::default()
            .with_frequency(esp_hal::time::Rate::from_khz(100))
            .with_mode(esp_hal::spi::Mode::_0),
    )
    .unwrap()
    .with_sck(peripherals.GPIO27)
    .with_mosi(peripherals.GPIO22)
    .with_miso(peripherals.GPIO35)
    .with_cs(master_cs)
    .into_async();

    loop {
        // Update a few key positions to track iterations
        master_send[0] = i; // First byte shows iteration count
        master_send[1] = 0xBB; // Fixed marker
        master_send[2] = 0xCC; // Fixed marker
        master_send[master_send.len() - 1] = i; // Last byte also shows iteration count

        i = i.wrapping_add(1); // Increment counter, wrapping at 255

        write_data_spi_async(&mut master_spi, master_send, /*&mut master_cs*/).await.unwrap();
        // Write data to SPI
        println!(
            "sent stuff {:x?} .. {:x?}",
            &master_send[..10],
            &master_send[master_send.len() - 10..],
        );
        //Timer::after(Duration::from_millis(1000)).await;
    }
}

async fn write_data_spi_async(
    spi: &mut Spi<'_, esp_hal::Async>,
    data: &[u8],/* cs: &mut Output<'_>*/,
) -> Result<(), spi::Error> {
    // Write data to SPI
    println!("cs is low now");
    //cs.set_low(); // Set CS low to start transmission
    embedded_hal_async::spi::SpiBus::write(spi, data).await?;
    //cs.set_high(); // Set CS high to end transmission
    Ok(()) // Return Ok to satisfy the Result return type
}

// This task runs in the background and can be used to perform other operations
#[embassy_executor::task]
async fn background_task() {
    loop {
        // Wait for a short duration between checks
        Timer::after(Duration::from_millis(1000)).await;

        // Print a message to show the task is running
        println!("Just some background task...");
    }
}
$abcdeabcde151015202530354045505560fghijfghij
esp:0
esp:2
esp:4
esp:5
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:21
esp:22
esp:23
esp:25
esp:26
esp:27
esp:32
esp:33
esp:34
esp:35
esp:3V3
esp:EN
esp:VP
esp:VN
esp:GND.1
esp:D2
esp:D3
esp:CMD
esp:5V
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:D1
esp:D0
esp:CLK
led1:A
led1:C
r1:1
r1:2