#include <stdio.h>
#include <string.h>
#include "nrf_drv_pwm.h"
#include "nrf_drv_gpiote.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "boards.h"
#include "app_uart.h"
#include "bsp.h"
#include "app_timer.h"
#include "nrf_drv_clock.h"


static  nrf_drv_pwm_t             m_pwm                     = NRF_DRV_PWM_INSTANCE(0);
static  nrf_pwm_values_common_t   m_nrf_pwm_values_common[] = {1, 6, 0, 4};

/** @brief PWM initialization
  */
void pwm_init(void)
{
    uint32_t err_code;
    nrf_drv_pwm_config_t const nrf_drv_pwm_config =
    {
        .output_pins =
        {
//            25,                                   // channel 0
            25 | NRF_DRV_PWM_PIN_INVERTED,        // channel 0
            LED_1,                                // channel 1
//            LED_1 | NRF_DRV_PWM_PIN_INVERTED,     // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOW,
        .base_clock   = NRF_PWM_CLK_250kHz,       // Need 250 clock to get 41kHz PWM that could have 50% duty cycle
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 6,
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_TRIGGERED
    };

    err_code = nrf_drv_pwm_init(&m_pwm, &nrf_drv_pwm_config, NULL);
    APP_ERROR_CHECK(err_code);
    
    nrf_pwm_sequence_t  const nrf_pwm_sequence =
    {
        .values.p_common  = m_nrf_pwm_values_common,
        .length           = 4,
        .repeats          = 0,
        .end_delay        = 0
    };
    
    nrf_drv_pwm_simple_playback(&m_pwm, &nrf_pwm_sequence, 1, NRF_DRV_PWM_FLAG_LOOP);
}

// GPIO --------------------------------------------------------------------------------------------

static bool                             m_btn3_it_flag  = false;
static bool                             m_btn4_it_flag  = false;

/** @brief  Button 1 interrupt handler
  */
void button3_interrupt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    m_btn3_it_flag = true;
}

/** @brief  Button 2 interrupt handler
  */
void button4_interrupt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    m_btn4_it_flag = true;
}

/** @brief GPIO initializations
  */
void gpio_init(void)
{
    nrf_gpio_cfg_output(LED_3);
    nrf_gpio_cfg_output(LED_4);
    nrf_gpio_pin_clear(LED_3);
    nrf_gpio_pin_set(LED_4);
    
    nrf_drv_gpiote_in_config_t  nrf_drv_gpiote_in_config;
    
    // This could return either NRF_SUCCESS or NRF_ERROR_INVALID_STATE. However, NRF_ERROR_INVALID_STATE
    // simply means the GPIOTE module is already initialized, so that error could be ignored.
    nrf_drv_gpiote_init();
    
    memset(&nrf_drv_gpiote_in_config, 0, sizeof(nrf_drv_gpiote_in_config_t));
    nrf_drv_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    nrf_drv_gpiote_in_config.pull = NRF_GPIO_PIN_PULLUP;
    nrf_drv_gpiote_in_config.hi_accuracy = false;
    nrf_drv_gpiote_in_config.is_watcher = false;
    
    nrf_drv_gpiote_in_init(BUTTON_3, &nrf_drv_gpiote_in_config, button3_interrupt_handler);
    nrf_drv_gpiote_in_event_enable(BUTTON_3, true);
    
    nrf_drv_gpiote_in_init(BUTTON_4, &nrf_drv_gpiote_in_config, button4_interrupt_handler);
    nrf_drv_gpiote_in_event_enable(BUTTON_4, true);
    
}


// /GPIO -------------------------------------------------------------------------------------------

int main(void)
{
    uint32_t err_code;
    
    err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_clock_lfclk_request(NULL);
    
    gpio_init();
    pwm_init();
    
    for (;;)
    {
        if (m_btn3_it_flag)
        {
            nrf_gpio_pin_toggle(LED_3);
            nrf_pwm_task_trigger(m_pwm.p_registers, NRF_PWM_TASK_NEXTSTEP);
            m_btn3_it_flag = false;
        }
        if (m_btn4_it_flag)
        {
            nrf_gpio_pin_toggle(LED_4);
            nrf_pwm_task_trigger(m_pwm.p_registers, NRF_PWM_TASK_NEXTSTEP);
            m_btn4_it_flag = false; 
        }
        
        // Wait for an event.
        __WFE();

        // Clear the event register.
        __SEV();
        __WFE();
    }
}

