/******************************************************************************
 * @file      bsp_adbms1818.c
 * @brief     LT6820-ADBMS1818�ջ���оƬ�ɼ�
 * @version   V1.0
 * @author    Gary 2024-11-13
 * @copyright
 ******************************************************************************/
#include "bsp_adbms1818.h"
#include "kit_debug.h"

#define ENABLED 1
#define DISABLED 0
#define DATALOG_ENABLED 1
#define DATALOG_DISABLED 0

/*******************************************************************
  Setup Variables
  The following variables can be modified to configure the software.
********************************************************************/
const uint8_t TOTAL_IC = 10; //!< Number of ICs in the daisy chain

/********************************************************************
  ADC Command Configurations. See ADBMS181x.h for options
*********************************************************************/
const uint8_t ADC_OPT = ADC_OPT_ENABLED;		  //!< ADC Mode option bit
const uint8_t ADC_CONVERSION_MODE = MD_7KHZ_3KHZ; //!< ADC

const uint8_t ADC_DCP = DCP_DISABLED;			//!< Discharge Permitted
const uint8_t CELL_CH_TO_CONVERT = CELL_CH_ALL; //!< Channel Selection for ADC conversion
const uint8_t AUX_CH_TO_CONVERT = AUX_CH_ALL;	//!< Channel Selection for ADC conversion
const uint8_t STAT_CH_TO_CONVERT = STAT_CH_ALL; //!< Channel Selection for ADC conversion
const uint8_t SEL_ALL_REG = REG_ALL;			//!< Register Selection
const uint8_t SEL_REG_A = REG_1;				//!< Register Selection
const uint8_t SEL_REG_B = REG_2;				//!< Register Selection

const uint16_t MEASUREMENT_LOOP_TIME = 100; //!< Loop Time in milliseconds(ms)

// Under Voltage and Over Voltage Thresholds
const uint16_t OV_THRESHOLD = 41000; //!< Over voltage threshold ADC Code. LSB = 0.0001 ---(4.1V)
const uint16_t UV_THRESHOLD = 30000; //!< Under voltage threshold ADC Code. LSB = 0.0001 ---(3V)

// Loop Measurement Setup. These Variables are ENABLED or DISABLED. Remember ALL CAPS
const uint8_t WRITE_CONFIG = ENABLED;  //!< This is to ENABLED or DISABLED writing into to configuration registers in a continuous loop
const uint8_t READ_CONFIG = ENABLED;   //!< This is to ENABLED or DISABLED reading the configuration registers in a continuous loop
const uint8_t MEASURE_CELL = ENABLED;  //!< This is to ENABLED or DISABLED measuring the cell voltages in a continuous loop
const uint8_t MEASURE_AUX = DISABLED;  //!< This is to ENABLED or DISABLED reading the auxiliary registers in a continuous loop
const uint8_t MEASURE_STAT = DISABLED; //!< This is to ENABLED or DISABLED reading the status registers in a continuous loop
const uint8_t PRINT_PEC = DISABLED;	   //!< This is to ENABLED or DISABLED printing the PEC Error Count in a continuous loop
/************************************
  END SETUP
*************************************/

/*******************************************************
  Global Battery Variables received from 181x commands
  These variables store the results from the ADBMS1818
  register reads and the array lengths must be based
  on the number of ICs on the stack
 ******************************************************/
cell_asic BMS_IC[TOTAL_IC]  __attribute__((section (".ccmram"))); //!< Global Battery Variable

/*************************************************************************
  Set configuration register. Refer to the data sheet
**************************************************************************/
bool REFON = false;																						   //!< Reference Powered Up Bit
bool ADCOPT = false;																					   //!< ADC Mode option bit
bool GPIOBITS_A[5] = {false, false, true, true, true};													   //!< GPIO Pin Control // Gpio 1,2,3,4,5
bool GPIOBITS_B[4] = {false, false, false, false};														   //!< GPIO Pin Control // Gpio 6,7,8,9
uint16_t UV = UV_THRESHOLD;																				   //!< Under voltage Comparison Voltage
uint16_t OV = OV_THRESHOLD;																				   //!< Over voltage Comparison Voltage
bool DCCBITS_A[12] = {false, false, false, false, false, false, false, false, false, false, false, false}; //!< Discharge cell switch //Dcc 1,2,3,4,5,6,7,8,9,10,11,12
bool DCCBITS_B[7] = {false, false, false, false, false, false, false};									   //!< Discharge cell switch //Dcc 0,13,14,15
bool DCTOBITS[4] = {true, false, true, false};															   //!< Discharge time value //Dcto 0,1,2,3  // Programed for 4 min
/*Ensure that Dcto bits are set according to the required discharge time. Refer to the data sheet */
bool FDRF = false;				 //!< Force Digital Redundancy Failure Bit
bool DTMEN = true;				 //!< Enable Discharge Timer Monitor
bool PSBITS[2] = {false, false}; //!< Digital Redundancy Path Selection//ps-0,1


cell_asic* bsp_adbms1818_global(void)
{
	return (cell_asic*)BMS_IC; //!< Global Battery Variable
}

/* Helper function to initialize CFG variables */
void ADBMS1818_init_cfg(uint8_t total_ic, // Number of ICs in the system
						cell_asic *ic	  // A two dimensional array that stores the data
)
{
	for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
	{
		for (int j = 0; j < 6; j++)
		{
			ic[current_ic].config.tx_data[j] = 0;
		}
	}
}

void ADBMS1818_init_cfgb(uint8_t total_ic, cell_asic *ic)
{
	for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
	{
		for (int j = 0; j < 6; j++)
		{
			ic[current_ic].configb.tx_data[j] = 0;
		}
	}
}

void check_error(int error)
{
	if (error == -1)
	{
		KIT_DEBUG_PRINTF("A PEC error was detected in the received data");
	}
}

/*!************************************************************
  \brief Prints cell voltage codes to the seeger
  @return void
 *************************************************************/
void print_cells(uint8_t datalog_en)
{
	for (int current_ic = 0; current_ic < TOTAL_IC; current_ic++)
	{
		if (datalog_en == 0)
		{
			KIT_DEBUG_PRINTF(" IC ");
//			KIT_DEBUG_PRINTF(current_ic + 1, DEC);
			KIT_DEBUG_PRINTF(", ");
			for (int i = 0; i < BMS_IC[0].ic_reg.cell_channels; i++)
			{
				KIT_DEBUG_PRINTF(" C");
//				KIT_DEBUG_PRINTF(i + 1, DEC);
//				KIT_DEBUG_PRINTF(":");
//				KIT_DEBUG_PRINTF(BMS_IC[current_ic].cells.c_codes[i] * 0.0001, 4);
				KIT_DEBUG_PRINTF(",");
			}
			KIT_DEBUG_PRINTF("\n");
		}
		else
		{
			KIT_DEBUG_PRINTF(" Cells, ");
			for (int i = 0; i < BMS_IC[0].ic_reg.cell_channels; i++)
			{
//				KIT_DEBUG_PRINTF(BMS_IC[current_ic].cells.c_codes[i] * 0.0001, 4);
				KIT_DEBUG_PRINTF(",");
			}
		}
	}
	KIT_DEBUG_PRINTF("\n");
}

void ADBMS1818_reset_crc_count(uint8_t total_ic, cell_asic *ic)
{
	for (int current_ic = 0; current_ic < total_ic; current_ic++)
	{
		ic[current_ic].crc_count.pec_count = 0;
		ic[current_ic].crc_count.cfgr_pec = 0;
		for (int i = 0; i < 6; i++)
		{
			ic[current_ic].crc_count.cell_pec[i] = 0;
		}
		for (int i = 0; i < 4; i++)
		{
			ic[current_ic].crc_count.aux_pec[i] = 0;
		}
		for (int i = 0; i < 2; i++)
		{
			ic[current_ic].crc_count.stat_pec[i] = 0;
		}
	}
}

void ADBMS1818_init_reg_limits(uint8_t total_ic, cell_asic *ic)
{
    for(uint8_t cic=0; cic<total_ic; cic++)
    {
        ic[cic].ic_reg.cell_channels=18; 
        ic[cic].ic_reg.stat_channels=4;
        ic[cic].ic_reg.aux_channels=9;
        ic[cic].ic_reg.num_cv_reg=6; 
        ic[cic].ic_reg.num_gpio_reg=4;    
        ic[cic].ic_reg.num_stat_reg=2;     
    } 
}


//init adbms1818
void ADBMS1818_init(uint8_t total_ic, cell_asic *ic)
{
	ADBMS1818_init_cfg(total_ic, ic);
	ADBMS1818_init_cfgb(total_ic, ic);
	
	ADBMS1818_reset_crc_count(total_ic, ic);
	ADBMS1818_init_reg_limits(total_ic, ic);
}

void run_command(uint32_t cmd,uint16_t total_ic)
{
	//uint8_t streg = 0;
	int8_t error = 0;
	uint32_t conv_time = 0;
	//int8_t s_pin_read = 0;
	switch (cmd)
	{
	case 1: // Write and read Configuration Register
		wakeup_sleep(total_ic);
		ADBMS1818_wrcfg(total_ic, BMS_IC);	// Write into Configuration Register
		ADBMS1818_wrcfgb(total_ic, BMS_IC); // Write into Configuration Register B

		wakeup_idle(total_ic);
		error = ADBMS1818_rdcfg(total_ic, BMS_IC);	// Read Configuration Register
		error = ADBMS1818_rdcfgb(total_ic, BMS_IC); // Read Configuration Register B
		check_error(error);
		break;

	case 2: // Read Configuration Register
		wakeup_sleep(total_ic);
		error = ADBMS1818_rdcfg(total_ic, BMS_IC);
		check_error(error);
		error = ADBMS1818_rdcfgb(total_ic, BMS_IC);
		check_error(error);
		break;

	case 3: // Start Cell ADC Measurement
		wakeup_sleep(total_ic);
		ADBMS1818_adcv(ADC_CONVERSION_MODE, ADC_DCP, CELL_CH_TO_CONVERT);
		conv_time = ADBMS1818_pollAdc();
		// print_conv_time(conv_time);
		break;

	case 4: // Read Cell Voltage Registers
		wakeup_sleep(total_ic);
		error = ADBMS1818_rdcv(SEL_ALL_REG, total_ic, BMS_IC); // Set to read back all cell voltage registers
		check_error(error);
		print_cells(DATALOG_DISABLED);
		break;

	case 5: // Start GPIO ADC Measurement
		wakeup_sleep(total_ic);
		ADBMS1818_adax(ADC_CONVERSION_MODE, AUX_CH_TO_CONVERT);
		conv_time = ADBMS1818_pollAdc();
		// print_conv_time(conv_time);
		break;

	case 6: // Read AUX Voltage Registers
		wakeup_sleep(total_ic);
		error = ADBMS1818_rdaux(SEL_ALL_REG, total_ic, BMS_IC); // Set to read back all aux registers
		check_error(error);
		// print_aux(DATALOG_DISABLED);
		break;
	default:
		conv_time = 0;
		break;
	}
}
