#include <msp430.h>
#include <msp430xgeneric.h>
#include <stdint.h>

#include "mw_main.h"

#define HARDWARE_CFG_INPUT_CHANNEL  ( ADC12INCH_13 )
#define BATTERY_SENSE_INPUT_CHANNEL ( ADC12INCH_15 )
#define LIGHT_SENSE_INPUT_CHANNEL   ( ADC12INCH_1 )

#define ENABLE_ADC()		{ ADC12CTL0 |= ADC12ON; ADC12CTL0 |= ADC12ENC + ADC12SC; }
#define DISABLE_ADC()		{ ADC12CTL0 &= ~ADC12ENC; ADC12CTL0 &= ~ADC12ON; }
#define CLEAR_START_ADDR()	{ ADC12CTL1 &= 0x0FFF; }

const double CONVERSION_FACTOR_BATTERY = ((24300.0+38300.0)*2.5*1000.0)/(4095.0*24300.0);
#define BATTERY_FULL_LEVEL		(4140)
#define BATTERY_CRITICAL_LEVEL		(3300)
#define BATTERY_LEVEL_RANGE		(BATTERY_FULL_LEVEL - BATTERY_CRITICAL_LEVEL)

/*! conversion factor */
const double CONVERSION_FACTOR =  2.5*10000.0/4096.0;


void mw_init_adc(void)
{
	REFCTL0 = REFMSTR | REFTCOFF; 

	LIGHT_SENSE_INIT();
	BATTERY_SENSE_INIT();
	HARDWARE_CFG_SENSE_INIT();
 
	/* allow conditional request for modosc */
	UCSCTL8 |= MODOSCREQEN;

	/* select ADC12SC bit as sample and hold source (00) 
	 * and use pulse mode
	 * use modosc / 8 because frequency must be 0.45 MHz to 2.7 MHz (0.625 MHz)
	 */
	ADC12CTL1 = ADC12CSTARTADD_0 + ADC12SHP + ADC12SSEL_0 + ADC12DIV_7; 

	/* 12 bit resolution, only use reference when doing a conversion */
	ADC12CTL2 = ADC12TCOFF + ADC12RES_2 + ADC12REFBURST;

	/* setup input channels */
	ADC12MCTL0 = HARDWARE_CFG_INPUT_CHANNEL + ADC12EOS;
	ADC12MCTL1 = BATTERY_SENSE_INPUT_CHANNEL + ADC12EOS;
	ADC12MCTL2 = LIGHT_SENSE_INPUT_CHANNEL + ADC12EOS;
}

unsigned int mw_get_battery_adc_val(void)
{ 
	BATTERY_SENSE_ENABLE();

	/* low_bat_en assertion to bat_sense valid is ~100 ns */
	/* Start battery sense conversion */
	CLEAR_START_ADDR();
	ADC12CTL1 |= ADC12CSTARTADD_1;
	ENABLE_ADC();

	/* WaitForAdcBusy(); */
	while (ADC12CTL1 & ADC12BUSY)
		nop();

	/* Convert the ADC count for the battery input into a voltage
	 * ADC12MEM1: Counts Battery Voltage in ADC counts
	 * Result: Battery voltage in millivolts */
	BATTERY_SENSE_DISABLE();

	return (unsigned int)(CONVERSION_FACTOR_BATTERY * (double)ADC12MEM1);
}

uint8_t mw_get_battery_percentage_from_val(unsigned int BattVal)
{
	if (BattVal > BATTERY_FULL_LEVEL)
		BattVal = BATTERY_FULL_LEVEL;
	if (BattVal < BATTERY_CRITICAL_LEVEL)
		BattVal = 0;
	else
		BattVal -= BATTERY_CRITICAL_LEVEL;
	BattVal = (BattVal > 0) ? (BattVal * 10 / (BATTERY_LEVEL_RANGE / 10)) : 0;

	return (unsigned char)BattVal;
}

uint16_t mw_get_amblight_adc_val(void)
{ 
	LIGHT_SENSE_ENABLE();

	CLEAR_START_ADDR();
	ADC12CTL1 |= ADC12CSTARTADD_2;
	ENABLE_ADC();

	/* WaitForAdcBusy(); */
	while (ADC12CTL1 & ADC12BUSY)
		nop();

	LIGHT_SENSE_DISABLE();

	return ADC12MEM2;
}