#include <stdio.h>
#include <string.h>
#include <nrf.h>

#include "nrf_drv_gpiote.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "boards.h"
#include "bsp.h"
#include "nrf_delay.h"
#include "nrf_drv_timer.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "app_pwm.h"


#define    Period    20000 //20ms
#define    PIN_IN    22
#define    PWM_PIN  (11UL)

const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(0);

APP_PWM_INSTANCE(PWM1,1);                   // Create the instance "PWM1" using TIMER1.


static int16_t buf[] = {(1 << 15) | 10000}; // Inverse polarity (bit 15), 10000us duty cycle
unsigned int duty_1= 50;
uint32_t duty_cyc = 50;
uint32_t time_us = 500; 
uint32_t time_ticks;

static volatile bool ready_flag;            // A flag indicating PWM status.
static int gpio_flag =0;
static int timer_flg =0;

void pwm_ready_callback(uint32_t pwm_id)    // PWM callback function
{
    ready_flag = true;
}



void pwm_update(void)
{
      uint32_t value;
      value = duty_1;
      ready_flag = false;
      /* Set the duty cycle - keep trying until PWM is ready... */
      
      

      while ((app_pwm_channel_duty_set(&PWM1, 0, value))&(app_pwm_channel_duty_set(&PWM1, 1, value)) == NRF_ERROR_BUSY);
 
      /* ... or wait for callback. */
      while (!ready_flag);
      APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, value));
      APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 0, value));

}


void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
   gpio_flag =1;
   timer_flg=0;
   nrf_drv_timer_enable(&TIMER_LED); 
   
}

void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    

    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
             timer_flg=1;
             gpio_flag=0;
             nrf_drv_timer_clear(&TIMER_LED); 
             pwm_update();
            break;

        default:
            //Do nothing.
            break;
    }
}


static void pwm_pin_init(void)
{
 ret_code_t err_code;

    /* 2-channel PWM, 200Hz, output on DK LED pins. */
    app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(Period, BSP_LED_0,BSP_LED_1);
    

    /* Switch the polarity of the second channel. */
    pwm1_cfg.pin_polarity [1]= APP_PWM_POLARITY_ACTIVE_HIGH;
    


    /* Initialize and enable PWM. */
    err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback);

    APP_ERROR_CHECK(err_code);

   
    app_pwm_enable(&PWM1);
    


} 


static void gpio_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    in_config.pull = NRF_GPIO_PIN_PULLDOWN;

    err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(PIN_IN, true);
}


 
void set_low(void)
{
 NRF_GPIO->OUTCLR = (1 << BSP_LED_0);
 NRF_GPIO->OUTCLR = (1 << BSP_LED_1);
}

void timer_init(void)
{
    uint32_t err_code = NRF_SUCCESS;
  //Configure TIMER_LED for generating simple light effect - leds on board will invert his state one after the other.
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    err_code = nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer_event_handler);
    APP_ERROR_CHECK(err_code);

    time_ticks = nrf_drv_timer_us_to_ticks(&TIMER_LED, time_us);

    nrf_drv_timer_extended_compare(
         &TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

   // nrf_drv_timer_enable(&TIMER_LED);  
  
    
}


int main(void)
{

   // Start accurate HFCLK (XOSC)
  NRF_CLOCK->TASKS_HFCLKSTART = 1;
  while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
  NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
  
  // Configure PWM_PIN as output, and set it to 0
  NRF_GPIO->DIRSET = (1 << PWM_PIN);
  NRF_GPIO->OUTCLR = (1 << PWM_PIN);
  
  
  NRF_PWM0->PRESCALER   = PWM_PRESCALER_PRESCALER_DIV_16; // 1 us
  NRF_PWM0->PSEL.OUT[0] = PWM_PIN;
  NRF_PWM0->MODE        = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
  NRF_PWM0->DECODER     = (PWM_DECODER_LOAD_Common       << PWM_DECODER_LOAD_Pos) | 
                          (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
  NRF_PWM0->LOOP        = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
  
  NRF_PWM0->COUNTERTOP = 20000; // 20ms period
  
  
  NRF_PWM0->SEQ[0].CNT = ((sizeof(buf) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
  NRF_PWM0->SEQ[0].ENDDELAY = 0;
  NRF_PWM0->SEQ[0].PTR = (uint32_t)&buf[0];
  NRF_PWM0->SEQ[0].REFRESH = 0;
  NRF_PWM0->SHORTS = 0;
  
  NRF_PWM0->ENABLE = 1;
  NRF_PWM0->TASKS_SEQSTART[0] = 1;
   
    bsp_board_init(BSP_INIT_LEDS);

    
    timer_init();
    gpio_init();

    pwm_pin_init();
   

  while(true)
  { 
   
     
    
   
  }
 
}


/** @} */
