#include "timer_count.h"

#define MEAS_PIN 11
#define OSCILLATOR_INIT_DELAY_MS 5
#define USER_NODE DT_PATH(zephyr_user)
static const struct gpio_dt_spec hum_en = GPIO_DT_SPEC_GET(USER_NODE, hum_en_gpios);

uint32_t count = 0;
uint32_t timer_status = 0;

void configure_clock_pin(uint32_t pin_number){
    nrf_gpio_cfg(
        pin_number,
        NRF_GPIO_PIN_DIR_INPUT,
        NRF_GPIO_PIN_INPUT_CONNECT,
        NRF_GPIO_PIN_PULLUP,
        NRF_GPIO_PIN_S0S1,
        NRF_GPIO_PIN_NOSENSE);
		*(volatile uint32_t *)(NRF_GPIOTE_BASE + 0x600 + (4 * pin_number)) = 1;
}

void timer_init() //gate timer
{
	NRF_TIMER1->TASKS_STOP = 1; //trigger stop
	NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer; //mode timer
	NRF_TIMER1->PRESCALER = 4;	// Fhck / 2^8 -1MHz
	//total gate time of timer 10000 - 100mS
	NRF_TIMER1->CC[0] = 50000;	//end gate count
	NRF_TIMER1->CC[1] = 1;	//start gate count. don't start at 0 to no start on clear.
	
	NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos);	
	
	NRF_TIMER1->TASKS_CLEAR = 1; //trigger zero timer
	NRF_TIMER1->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos); //interrupt on end gate count
	
	NRF_TIMER1->EVENTS_COMPARE[0] = 0; //rest event flag for gate end
	NRF_TIMER1->EVENTS_COMPARE[1] = 0; //rest event flag for gate start
}

static void counter_init() //actual counter
{
	NRF_TIMER2->TASKS_STOP = 1;	//trigger stop
	NRF_TIMER2->MODE = TIMER_MODE_MODE_Counter; //counter
	NRF_TIMER2->BITMODE = (TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos);
	NRF_TIMER2->TASKS_CLEAR = 1; //trigger zero counter
	NRF_TIMER2->EVENTS_COMPARE[0] = 0; //reset event for compare
}

//counter input pin setting
static void gpiote_init(uint32_t pin) //Pin must be in port 0
{
	NRF_GPIOTE->CONFIG[0] 	= 	0x01 << 0; 								// MODE: Event
	NRF_GPIOTE->CONFIG[0] 	|= 	pin << 8;								// Pin number
	NRF_GPIOTE->CONFIG[0] 	|= 	GPIOTE_CONFIG_POLARITY_LoToHi	<< 16;		// Event rising edge 	
}

//hardware trigger: stop of counter on event of end timer1 gate
static void ppi_timer_stop_counter_init()
{
	NRF_PPI->CHEN |= 1 << 2; //channel
	*(&(NRF_PPI->CH2_EEP)) = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0]; //attach end gate event
	*(&(NRF_PPI->CH2_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_STOP; //to counter stop trigger
	NRF_PPI->CHENSET |= 1 << 2; //set channel
}

//hardware trigger: start of counter on event of begin timer1 (gate) event.gate
static void ppi_timer_start_counter_init()
{
	NRF_PPI->CHEN |= 1 << 4;// channel
	*(&(NRF_PPI->CH4_EEP)) = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[1]; //attach gate start event
	*(&(NRF_PPI->CH4_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_START; //to counter start trigger
	NRF_PPI->CHENSET |= 1 << 4;
}


static void ppi_gpiote_counter_init()
//hardware attachment for the gpiote that was selected above
{
	NRF_PPI->CHEN |= 1 << 1;
	*(&(NRF_PPI->CH1_EEP)) = (uint32_t)&NRF_GPIOTE->EVENTS_IN[0]; //attach pin change
	*(&(NRF_PPI->CH1_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_COUNT;//to one count
	NRF_PPI->CHENSET |= 1 << 1;
}

//gate end interrupt handler. Count is done at hardware and percice interrupt execution isnt critical
void TIMER1_IRQHandler(void) {
	if (NRF_TIMER1->EVENTS_COMPARE[0] != 0){ //end gate event 
		NRF_TIMER1->EVENTS_COMPARE[0] = 0; //reset end gate flag
		NRF_TIMER1->EVENTS_COMPARE[1] = 0; //reset start gate flag
		NRF_TIMER2->TASKS_CAPTURE[0] = 1; //trigger get counter value
		count = NRF_TIMER2->CC[0];
      	
		NRF_TIMER1->TASKS_CLEAR = 1; //reset timer
		NRF_TIMER2->TASKS_CLEAR = 1; //reset counter

        timer_status = STATE_FINISHED;
		NRF_TIMER1->TASKS_STOP = 1; //stop
		gpio_pin_set_dt(&hum_en, 0);
		//NRF_TIMER1->TASKS_START = 1; //start next count gate		
    }
}

void configure_measurement()
{

	int ret = 0;
	NVIC_ClearPendingIRQ(TIMER1_IRQn);
	NVIC_EnableIRQ(TIMER1_IRQn); //enable timer1 interrupt
	IRQ_CONNECT(TIMER1_IRQn, 5, TIMER1_IRQHandler, 0, 0); //link interrupt flag to handler

	if (!device_is_ready(hum_en.port)) {
        printk("hum_en device not ready\n");
        return;
    }
	    ret = gpio_pin_configure_dt(&hum_en, GPIO_OUTPUT_ACTIVE); if (ret < 0)
    {
        printk("Failed to configure hum_en\n");
        return;
    }

	configure_clock_pin(MEAS_PIN);

	counter_init();
	timer_init();
	gpiote_init(MEAS_PIN);
	ppi_gpiote_counter_init();
	ppi_timer_stop_counter_init();
	ppi_timer_start_counter_init();

}

void make_measurement()
{
	if( timer_status == STATE_RUNNING) {
		//manage error here
		return;
	}

    gpio_pin_set_dt(&hum_en, 1);
    k_sleep(K_MSEC(OSCILLATOR_INIT_DELAY_MS));

    timer_status = STATE_RUNNING;
	NRF_TIMER1->TASKS_START = 1;
}

uint32_t read_measurement(){
    if(timer_status != STATE_FINISHED) {
        return -timer_status;
    }
    else{
        return count;
    }
}
