/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 *
 */

#include "nrf.h"
#include <stdbool.h>
#include <stdint.h>
#include "bsp.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "math.h"

// Peripheral channel assignments
#define TIMER3_GPIOTE_CH      0
#define TIMER3_PPI_CH_A       0
#define TIMER3_PPI_CH_B       1
#define TIMER3_TIMER_CC_NUM   0

#define TIMER2_GPIOTE_CH     2
#define TIMER2_PPI_CH_A      3
#define TIMER2_PPI_CH_B      4
#define TIMER2_TIMER_CC_NUM  0




#define TIMER3_RELOAD        16

#define TIMER2_TIMER_RELOAD 1000000
// The timer CC register used to reset the timer. Be aware that not all timers in the nRF52 have 6 CC registers.
#define TIMER3_RELOAD_CC_NUM 5
#define TIMER2_TIMER_RELOAD_CC_NUM 3


// This function initializes timer 3 with the following configuration:
// 24-bit, base frequency 16 MHz, auto clear on COMPARE5 match (CC5 = TIMER_RELOAD)
void timer_init()
{
    NRF_TIMER3->BITMODE                 = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos;
    NRF_TIMER3->PRESCALER               = 0;
    NRF_TIMER3->SHORTS                  = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER3_RELOAD_CC_NUM;
    NRF_TIMER3->MODE                    = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
    NRF_TIMER3->CC[TIMER3_RELOAD_CC_NUM] = TIMER3_RELOAD;   

    NRF_TIMER2->BITMODE                 = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos;
    NRF_TIMER2->PRESCALER               = 0;
    NRF_TIMER2->SHORTS                  = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER2_TIMER_RELOAD_CC_NUM;
    NRF_TIMER2->MODE                    = TIMER_MODE_MODE_Counter << TIMER_MODE_MODE_Pos;
    NRF_TIMER2->CC[TIMER2_TIMER_RELOAD_CC_NUM] = TIMER2_TIMER_RELOAD;       
    
    NRF_TIMER3->CC[TIMER3_TIMER_CC_NUM] = 6;        //This variable is not too important. Only used to trigger the "first" pin. Not needed, as TIMER2 only needs the TIMER3_RELOAD to trigger/count.
    NRF_TIMER2->CC[TIMER2_TIMER_CC_NUM] = 512;      //This variable is not too important. Only used to trigger the "second" pin. Not needed, as the timeout handler only needs TIMER2_RELOAD to trigger.
}


// Starts TIMER3
void timer_start()
{
    NRF_TIMER3->TASKS_START = 1;
    NRF_TIMER2->TASKS_START = 1;
}

void SWI0_EGU0_IRQHandler(void)
{
    if(NRF_EGU0->EVENTS_TRIGGERED[0])
    {
        // This is the timeout handler that triggers after TIMER3_RELOAD number of µs.
        NRF_EGU0->EVENTS_TRIGGERED[0] = 0;
    }
}


void gpiote_init(void)      // this function sets up the gpiotes. Although the gpiote toggles are not nesescarry, it also connects TIMER2 in Counter mode to TIMER3.
{  
    NRF_GPIOTE->CONFIG[TIMER3_GPIOTE_CH] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos | 
                                         GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos | 
                                         17 << GPIOTE_CONFIG_PSEL_Pos | 
                                         GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;
    
    NRF_GPIOTE->CONFIG[TIMER2_GPIOTE_CH] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos | 
                                         GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos | 
                                         18 << GPIOTE_CONFIG_PSEL_Pos | 
                                         GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;
        

    NRF_PPI->CH[TIMER3_PPI_CH_A].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[TIMER3_TIMER_CC_NUM];
    NRF_PPI->CH[TIMER3_PPI_CH_A].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[TIMER3_GPIOTE_CH];
    NRF_PPI->FORK[TIMER3_PPI_CH_A].TEP = (uint32_t)&NRF_TIMER2->TASKS_COUNT;            // TIMER2 gets incremented every time TIMER3 reaches TIMER3_RELOAD_CC_NUM
    
    NRF_PPI->CH[TIMER3_PPI_CH_B].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[TIMER3_RELOAD_CC_NUM];
    NRF_PPI->CH[TIMER3_PPI_CH_B].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[TIMER3_GPIOTE_CH];    
    
    NRF_PPI->CH[TIMER2_PPI_CH_A].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[TIMER2_TIMER_CC_NUM];
    NRF_PPI->CH[TIMER2_PPI_CH_A].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[TIMER2_GPIOTE_CH];
    
    NRF_PPI->CH[TIMER2_PPI_CH_B].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[TIMER2_TIMER_RELOAD_CC_NUM];
    NRF_PPI->CH[TIMER2_PPI_CH_B].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[TIMER2_GPIOTE_CH];
    NRF_PPI->FORK[TIMER2_PPI_CH_B].TEP = (uint32_t)&NRF_EGU0->TASKS_TRIGGER[0];         // TIMER2 times out after TIMER2 reaches TIMER2_TIMER_RELOAD_CC_NUM
    
    
    NRF_EGU0->INTENSET = EGU_INTENSET_TRIGGERED0_Msk;
    NVIC_EnableIRQ(SWI0_EGU0_IRQn);
    
    NRF_PPI->CHENSET               = (1 << TIMER3_PPI_CH_A) | (1 << TIMER3_PPI_CH_B) | (1 << TIMER2_PPI_CH_A) | (1 << TIMER2_PPI_CH_B);
}



int main(void)
{
    timer_init();
    gpiote_init();
    timer_start();
    while (true)
    {
        //do nothing
    }
}
