#include "battery.h"
#include "ADI/ltc3335/adi_ltc3335.h"
#include <drivers/xint/adi_xint.h>

//=========================== defines =========================================

//==== static configuration
#define BATTERY_PRESCALER       8
#define BATTERY_ALARM_THRESHOLD 210 // Alarm is raised when 2300mAh is drained from the battery

//==== interrupt info
#define BATTERY_IRQ_PIN        ADI_XINT_EVENT_INT1
#define BATTERY_IRQ_POLARITY   ADI_XINT_IRQ_FALLING_EDGE

//=========================== typedef =========================================

typedef struct
{   
    bool                critical;
    bool                valid;
} battery_vars_t;

//=========================== variables =======================================

static IRQn_Type    SYSWAKE1_IRQ = XINT_EVT1_IRQn;
battery_vars_t      battery_vars;
adi_ltc3335_alarm_t battery_alarms;

//=========================== prototypes ======================================

bool battery_configureCoulombCnt(uint16_t bat_capacity); // in mAh

void battery_alarm(void *pCBParam, uint32_t Event, void *pArg);

//=========================== public ==========================================

bool battery_init(void)
{
    bool success = true;
	  uint16_t temp;
	
    adi_ltc3335_Init();
    adi_xint_RegisterCallback(BATTERY_IRQ_PIN, battery_alarm, &SYSWAKE1_IRQ);
    adi_xint_EnableIRQ(BATTERY_IRQ_PIN, BATTERY_IRQ_POLARITY);
	
	  
	  //DEBUG only
		success &= battery_getLife(&temp); 
		
		DEBUG_MSG("Bat life: %d\n", temp);
		
	//success  &= adi_ltc3335_Clear_Int();
    success &= battery_configureCoulombCnt(BATTERY_CAPACITY);
	  //success &= battery_processAlarms();

    return success;
}

// This function does not initialize communication with LTC3335 to save power
bool battery_isCritical(bool* isCritical)
{
    *isCritical = battery_vars.critical;
    return battery_vars.valid;
}

// This function gets detailed info via I2C
bool battery_getLife(uint16_t *days)
{
	  bool    success;
	  uint8_t accumulator;

	  // determine charge left
    success   = adi_ltc3335_Get_Accumulator(&accumulator);	
	DEBUG_MSG("accumulator: %d\n", accumulator);
	  *days     = 255 - accumulator; // TODO this should be recalculated to days
	  
	  return success;
}

//=========================== private =========================================

//==== Load and process LTC3335 alarms
bool battery_processAlarms(void)
{
    bool success;

    success  =  adi_ltc3335_Get_Alarms(&battery_alarms);

    if ((battery_alarms.ac_on_time_overflow == 1) || (battery_alarms.coulomb_counter_overflow == 1))
        battery_vars.valid = false;
    else
			  battery_vars.valid = true;
	
		if (battery_alarms.alarm_trip == 1)
        battery_vars.critical = true;
		else
			  battery_vars.critical = false;

    //success &= adi_ltc3335_Clear_Int();
		
		DEBUG_MSG("Alarms: %d %d %d\n", battery_alarms.ac_on_time_overflow, battery_alarms.coulomb_counter_overflow,battery_alarms.alarm_trip);

    return success;
}

//==== Configure Coulomb Counter for proper measurement
bool battery_configureCoulombCnt(uint16_t bat_capacity)
{
    uint8_t temp;
    bool    success;

    // check if the battery is LS14500 (2600mAh)
    // this config is only static, it does not work with different batteries
    if (bat_capacity != BATTERY_CAPACITY)
        return false;
		
    success  = adi_ltc3335_Set_Prescaler(BATTERY_PRESCALER);
    success &= adi_ltc3335_Set_Alarm_Threshold(BATTERY_ALARM_THRESHOLD);

    return success;
}

//==== IRQ handler
void battery_alarm(void *pCBParam, uint32_t Event, void *pArg)
{
    DEBUG_MSG("LTC3335 INT\n");
    battery_processAlarms();
}
