#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "adc.h"
#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"

#include "nrf_log.h"
#include "ble_imp.h"

void saadc_init(void);
void saadc_sampling_event_init(void);
void saadc_sampling_event_enable(void);

float voltages_adc[SAMPLED_CHANNELS] = {0};

struct adc_voltages voltages_device = {
	.mcu = 0,
	.input = 0,
	.cell = {0}
};

#define GAIN	(1/6)
volatile uint8_t state = 1;

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(1);
nrf_saadc_value_t     m_buffer_pool[2][SAMPLED_CHANNELS];
static nrf_ppi_channel_t     m_ppi_channel;

void init_ADC(void)
{
	saadc_init();
	saadc_sampling_event_init();
	saadc_sampling_event_enable();
};

/* Voltage divider - calculate input voltage */
float Uin_divider(uint32_t R1, uint32_t R2, float output_voltage)
{
	return ((float)((R1+R2)/(float)R2)*output_voltage);
}

float ADC_voltage_comp(int16_t * input)
{
	/* Compute ADC channel voltages */
	return((3.6f * *input)/4096);
}

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
	if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
	{
		ret_code_t err_code;

		err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLED_CHANNELS);
		APP_ERROR_CHECK(err_code);


		voltages_adc[0] = ADC_voltage_comp(&p_event->data.done.p_buffer[0]);
		voltages_adc[1] = ADC_voltage_comp(&p_event->data.done.p_buffer[1]);
		voltages_adc[2] = ADC_voltage_comp(&p_event->data.done.p_buffer[2]);
		voltages_adc[3] = ADC_voltage_comp(&p_event->data.done.p_buffer[3]);

		voltages_device.mcu = voltages_adc[3];
		voltages_device.input = Uin_divider(10000,3300,voltages_adc[2]);
		voltages_device.cell[0] = Uin_divider(10000,3300,voltages_adc[0]);
		voltages_device.cell[1] = Uin_divider(10000,3300,voltages_adc[1]) - voltages_device.cell[0];
		voltages_device.cell[2] = voltages_device.input - Uin_divider(10000,3300,voltages_adc[1]);
		
		/* Low voltage check */
		if(voltages_device.input < 9)
		{
			/* Disable power output */
			nrf_gpio_pin_write(26, false);
		}else
		{
			/* Enable power output */
			nrf_gpio_pin_write(26, true);
		}
		/* Send battery cells voltages to BLE */
		update_battery();
	}
}
void saadc_sampling_event_init(void)
{
	ret_code_t err_code;
	nrf_drv_ppi_init();

	nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
	timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
	err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
	APP_ERROR_CHECK(err_code);

	/* setup m_timer for compare event every 400ms */
	uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
	nrf_drv_timer_extended_compare(&m_timer,
								   NRF_TIMER_CC_CHANNEL0,
								   ticks,
								   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
								   false);
	nrf_drv_timer_enable(&m_timer);

	uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
																				NRF_TIMER_CC_CHANNEL0);
	uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

	/* setup ppi channel so that timer compare event is triggering sample task in SAADC */
	err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
										  timer_compare_event_addr,
										  saadc_sample_task_addr);
	APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
	ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

	APP_ERROR_CHECK(err_code);
}


void saadc_init(void)
{
	ret_code_t err_code;

	nrf_saadc_channel_config_t channel_config	= {
									.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
									.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
									.gain       = NRF_SAADC_GAIN1_6,
									.reference  = NRF_SAADC_REFERENCE_INTERNAL,
									.acq_time   = NRF_SAADC_ACQTIME_40US,
									.mode       = NRF_SAADC_MODE_SINGLE_ENDED,
									.burst      = NRF_SAADC_BURST_DISABLED,
									.pin_p      = NRF_SAADC_INPUT_AIN7,
									.pin_n      = NRF_SAADC_INPUT_DISABLED
								};

	nrf_drv_saadc_config_t adc_config	= {
					.resolution         = NRF_SAADC_RESOLUTION_12BIT,
					.oversample         = NRF_SAADC_OVERSAMPLE_DISABLED,
					.interrupt_priority = 7,
					.low_power_mode     = false
					};

	err_code = nrf_drv_saadc_init(&adc_config, saadc_callback);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_channel_init(0, &channel_config);
	APP_ERROR_CHECK(err_code);

	channel_config.pin_p = NRF_SAADC_INPUT_AIN6;
	err_code = nrf_drv_saadc_channel_init(1, &channel_config);
	APP_ERROR_CHECK(err_code);

	channel_config.pin_p = NRF_SAADC_INPUT_AIN5;
	err_code = nrf_drv_saadc_channel_init(2, &channel_config);
	APP_ERROR_CHECK(err_code);

	channel_config.pin_p = NRF_SAADC_INPUT_VDD;
	err_code = nrf_drv_saadc_channel_init(3, &channel_config);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLED_CHANNELS);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLED_CHANNELS);
	APP_ERROR_CHECK(err_code);

}
