/*
 * adc.cpp
 *
 * $Id$
*/

#include "adc.h"


int16_t  adc_raw[GPIO_NUM_MAX];

uint32_t adc_brightness;	// processed value
uint8_t  adc_bright_c;		// last re-read count, high bit = in progress
uint8_t  adc_bright_i;		// averaging index
uint32_t adc_bright_w[8];	// average values


// initialization and setup
void adc_init()
{
	uint8_t i;

	analogSetAttenuation(ADC_0db);
	analogSetClockDiv(20);
	pinMode(ADC_PIN_VBAT, INPUT);

	adc_brightness = 0xffff;
	adc_bright_i = 0;
	for (i = 0; i < 8; i++) {
		adc_bright_w[i] = 0xffff;	
	}
}

// use
bool adc_start(int pin)
{
	adcAttachPin(pin);
	adcStart(pin);
	return true;
}

uint16_t adc_end(int pin)
{
	adc_raw[pin] = adcEnd(pin);
	return adc_raw[pin];
}

bool adc_get_blocking(int pin)
{
	if (adc_start(pin)) {
		adc_raw[pin] = adc_end(pin);
		return true;
	}

	return false;
}

// get
uint16_t adc_val_raw(uint8_t pin)
{
	return adc_raw[pin];
}

// device-specific tasks
uint16_t adc_scale_vbat(uint16_t val)
{
	return ((uint32_t)(val * 1284) >> 10);
}

uint16_t IRAM_ATTR adc_get_vbat()
{
	pinMode(ADC_PIN_VBAT, ANALOG);
	if (!adc_get_blocking(ADC_PIN_VBAT)) {
		return 0xffff;
	}

	return (adc_scale_vbat(adc_raw[ADC_PIN_VBAT]));
}

int16_t adc_get_hall()
{
	adc_raw[ADC_PIN_HALL] = hallRead();

	return adc_raw[ADC_PIN_HALL];
}

uint16_t adc_val_brightness()
{
	return adc_brightness;
}
uint8_t IRAM_ATTR adc_get_brightness_c()
{
	return adc_bright_c;
}
uint8_t IRAM_ATTR adc_get_brightness(uint8_t reset)
{
	uint8_t i;

	switch (reset) {
		case ADC_GET_RESTART: {				// reset reading
			adc_bright_c = 0x80;

			// reverse bias LED
			pinMode(ADC_PIN_LED_K, OUTPUT);
			digitalWrite(ADC_PIN_LED_K, HIGH);

			adc_bright_w[adc_bright_i] = 0;

			break;
		}

		case ADC_GET_STOP_DARK: {			// conversion too long, force exit full dark
			adc_bright_c &= 0x80;

			adc_bright_w[adc_bright_i++] = 4095;

			goto adc_bright_done;
		}
	}

	if (!(adc_bright_c & 0x80)) {
		return 0;
	}

	// read the charge off the LED
	pinMode(ADC_PIN_LED_K, ANALOG);

	if (!adc_get_blocking(ADC_PIN_LED_K)) {
		adc_bright_c &= 0x80;
		return 0;
	}

	adc_bright_c++;

	adc_bright_w[adc_bright_i] = adc_raw[ADC_PIN_LED_K];
	if (adc_raw[ADC_PIN_LED_K] < ADC_BRIGHT_THRESH_MIN) {
		// clear working bit
		adc_bright_c &= ~0x80;
		
		// brightness value calculation
		adc_bright_w[adc_bright_i++] += (adc_bright_c * ADC_BRIGHT_COUNT_ADD);
adc_bright_done:
		adc_bright_i %= 8;

		// final value smoothing
		for (i = 0; i < 8; i++) {
			adc_brightness += adc_bright_w[i];
		}
		adc_brightness >>= 3;

		return 0;
	}

	return adc_bright_c;
}
void adc_task_brightness(void *p)
{

	vTaskDelete(NULL);
}
