//! Button Interrupt
//!
//! Solution

// Reference: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html
use anyhow::Result;
use esp_idf_hal::prelude::Peripherals;
use esp_idf_sys::*; //{
    //esp, esp_random, gpio_config, gpio_config_t, gpio_install_isr_service,
    //gpio_int_type_t_GPIO_INTR_POSEDGE, gpio_isr_handler_add, gpio_mode_t_GPIO_MODE_INPUT,
    //xQueueGenericCreate, xQueueReceive, QueueHandle_t, ESP_INTR_FLAG_IRAM,
//};
//use esp_idf_bindgen::{xQueueSendFromISR};
use std::ptr;

// This `static mut` holds the queue handle we are going to get from `xQueueGenericCreate`.
// This is unsafe, but we are careful not to enable our GPIO interrupt handler until after this value has been initialised, and then never modify it again
static mut EVENT_QUEUE: Option<QueueHandle_t> = None;
static mut int_counter: i32 = 00;
static mut w: BaseType_t = 0;
#[link_section = ".iram0.text"]
unsafe extern "C" fn button_interrupt(_: *mut core::ffi::c_void) {
    xQueueGenericSendFromISR(EVENT_QUEUE.unwrap(), 
    (&mut int_counter as *mut std::ffi::c_int) as *mut std::ffi::c_void, 
    &mut w,
    1); //queueSEND_TO_BACK);
    int_counter += 1;
    //if( w ) { taskYIELD_YIELD_FROM_ISR(); }
}

fn main() -> Result<()> {
    let peripherals = Peripherals::take().unwrap();

    const GPIO_NUM: i32 = 25;

    // Configures the button
    let io_conf = gpio_config_t {
        pin_bit_mask: 1 << GPIO_NUM,
        mode: gpio_mode_t_GPIO_MODE_INPUT,
        pull_up_en: true.into(),
        pull_down_en: false.into(),
        intr_type: gpio_int_type_t_GPIO_INTR_POSEDGE, // Positive edge trigger = button down
    };

    // Queue configurations
    const QUEUE_TYPE_BASE: u8 = 0;
    const ITEM_SIZE: u32 = 4; //std::mem::size_of::<i32>(); // We're not posting any actual data, just notifying
    const QUEUE_SIZE: u32 = 10;

    unsafe {
        // Writes the button configuration to the registers
        esp!(gpio_config(&io_conf))?;

        // Installs the generic GPIO interrupt handler
        esp!(gpio_install_isr_service(ESP_INTR_FLAG_IRAM as i32))?;

        // Instantiates the event queue
        EVENT_QUEUE = Some(xQueueGenericCreate(QUEUE_SIZE, ITEM_SIZE, QUEUE_TYPE_BASE));

        // Registers our function with the generic GPIO interrupt handler we installed earlier.
        esp!(gpio_isr_handler_add(
            GPIO_NUM,
            Some(button_interrupt),
            std::ptr::null_mut()
        ))?;
    }
    let mut rcv_count : i32 = 0;
    // Reads the queue in a loop.
    loop {
        unsafe {
            // Maximum delay
            const QUEUE_WAIT_TICKS: u32 = 1000;
        
            // Reads the event item out of the queue
            let res = xQueueReceive(EVENT_QUEUE.unwrap(), (&mut rcv_count as *mut std::ffi::c_int) as *mut std::ffi::c_void, QUEUE_WAIT_TICKS);

            // If the event has the value 0, nothing happens. if it has a different value, the button was pressed.
            // If the button was pressed, a function that changes the state of the LED is called.

            match res {
                1 => {
                    println!("Counter:{}", rcv_count);
                }
                _ => {}
            };
        }
    }
}