#include <avr/io.h>

#include "lights.h"

#define BATTERY_ADC_SHIFT	2
#define RESISTOR_HI	1500	// kOhm
#define RESISTOR_LO	 100	// kOhm
/*
 * The internal 1.1V reference has tolerance from 1.0 to 1.2V
 * (datasheet, section 19.6). We have to measure the actual value
 * of our part.
 */
#define AREF_1100MV	1060	// mV

static volatile uint16_t battery_adcval;
static unsigned char initial_readings = 0;

void init_battery()
{
	battery_adcval = 0;
	initial_readings = 5;
}

unsigned char battery_100mv()
{
	/*
	 * This is tricky: we need to maintain precision, so we first
	 * multiply adcval by as big number as possible to fit uint16_t,
	 * then divide to get the final value,
	 * and finally type-cast it to unsigned char.
	 * We don't do running average, as the required precision
	 * is coarse (0.1 V).
	 */
	return (unsigned char)
		((uint16_t)(
		(battery_adcval >> BATTERY_ADC_SHIFT)
		* (11                                      // 1.1V
		* (RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO    // resistor ratio
		/ 4)) >> 8);                               // divide by 1024
}

void battery_adc(uint16_t adcval)
{
	if (initial_readings) {
		initial_readings--;
		battery_adcval = adcval << BATTERY_ADC_SHIFT;
	} else if (battery_adcval == 0) {
		battery_adcval = adcval << BATTERY_ADC_SHIFT;
	} else { // running average
		battery_adcval += (adcval
			- (battery_adcval >> BATTERY_ADC_SHIFT));
	}
#if 0
	log_byte(battery_100mv());
	log_flush();
#endif
}

unsigned char battery_gauge()
{
	unsigned char b8 = battery_100mv();
	unsigned char rv;

	if        (b8 < 70) {
		rv = 1;
	} else if (b8 < 75) {
		rv = 2;
	} else if (b8 < 80) {
		rv = 3;
	} else if (b8 < 85) {
		rv = 4;
	} else if (b8 < 90) {
		rv = 5;
	} else if (b8 < 95) {
		rv = 6;
	} else {
		rv = 7;
	}

	if (rv == 1 && !initial_readings)
		set_error(ERR_BATTERY);

#if 0
	log_byte(0xbb);
	log_byte(rv);
	log_flush();
#endif
	return rv;
}
