/*
 * ADBMS_Abstraction.c
 *
 *  Created on: 14.07.2022
 *      Author: max
 */

#include "ADBMS_Abstraction.h"



uint8 numberofcells;
uint8 numberofauxchannels;

uint8 initAMS(SPI_HandleTypeDef* hspi, uint8 numofcells, uint8 numofaux)
{
	adbmsDriverInit(hspi);
	numberofcells = numofcells;
	numberofauxchannels = numofaux;


	amsWakeUp();
	amsStopBalancing();
	amsConfigOverVoltage(DEFAULT_OV);
	amsConfigUnderVoltage(DEFAULT_UV);
	amsConfigAuxMeasurement(0xFFFF);

	return 0;
}

uint8 amsWakeUp()
{
	uint8 buf[6];
	readCMD(RDCFGA, buf, 6);
	return 0;
}

uint8 amsCellMeasurement(Cell_Module *module)
{
	uint8_t rxbuffer[CV_GROUP_A_SIZE];
	writeCMD((ADCV | CH000 | MD10), rxbuffer, 0);
	mcuDelay(5);
	amsReadCellVoltages(module);
	return 0;
}

uint8 amsConfigCellMeasurement(uint8 numberofChannels)
{
	numberofcells = numberofChannels;
	return 0;
}

uint8 amsAuxMeasurement(Cell_Module *module)
{
	uint8 args;
	uint8 rxbuf[AUX_GROUP_A_SIZE];
	writeCMD(ADAX | MD01 | CHG000, &args, 0);

	mcuDelay(5);

	readCMD(RDAUXA, rxbuf, AUX_GROUP_A_SIZE);

	module->auxVoltages[0] = rxbuf[0] | (rxbuf[1]<<8);
	module->auxVoltages[1] = rxbuf[2] | (rxbuf[3]<<8);
	module->auxVoltages[2] = rxbuf[4] | (rxbuf[5]<<8);

	readCMD(RDAUXB, rxbuf, AUX_GROUP_A_SIZE);

	module->auxVoltages[3] = rxbuf[0] | (rxbuf[1]<<8);
	module->auxVoltages[4] = rxbuf[2] | (rxbuf[3]<<8);
	module->refVoltage = rxbuf[4] | (rxbuf[5]<<8);

	readCMD(RDAUXC, rxbuf, AUX_GROUP_A_SIZE);

	module->auxVoltages[5] = rxbuf[0] | (rxbuf[1]<<8);
	module->auxVoltages[6] = rxbuf[2] | (rxbuf[3]<<8);
	module->auxVoltages[7] = rxbuf[4] | (rxbuf[5]<<8);

	readCMD(RDAUXD, rxbuf, AUX_GROUP_A_SIZE);

	module->auxVoltages[8] = rxbuf[0] | (rxbuf[1]<<8);

	return 0;
}

uint8 amsInternalStatusMeasurement(Cell_Module *module)
{
	uint8 rxbuffer[STATUS_GROUP_A_SIZE];
	writeCMD(ADSTAT | MD01 | CHST000, rxbuffer, STATUS_GROUP_A_SIZE);
	mcuDelay(5);

	readCMD(RDSTATA, rxbuffer, STATUS_GROUP_A_SIZE);

	module->sumOfCellMeasurements = rxbuffer[0] | (rxbuffer[1]<<8);
	module->internalDieTemp		  = rxbuffer[2] | (rxbuffer[3]<<8);
	module->analogSupplyVoltage   = rxbuffer[4] | (rxbuffer[5]<<8);

	readCMD(RDSTATB, rxbuffer, STATUS_GROUP_B_SIZE);
	module->digitalSupplyVoltage = rxbuffer[0] | (rxbuffer[1]<<8);


	return 0;
}

uint8 amsConfigAuxMeasurement(uint16 Channels)
{
	uint8 buf[CFG_GROUP_A_SIZE];

	readCMD(RDCFGA, buf, CFG_GROUP_A_SIZE);
	buf[0] |= 0xF8;
	writeCMD(WRCFGA, buf, CFG_GROUP_A_SIZE);

	readCMD(RDCFGB, buf, CFG_GROUP_B_SIZE);
	buf[0] |= 0x0F;
	writeCMD(WRCFGB, buf, CFG_GROUP_B_SIZE);
	return 0;
}

uint8 amsConfigGPIO(uint16 gpios)
{
	return 0;
}

uint8 amsSetGPIO(uint16 gpios)
{
	return 0;
}

uint8 readGPIO(Cell_Module* module)
{
	return 0;
}

uint8 amsConfigBalancing(uint32 Channels)
{

	uint8 regbuffer[CFG_GROUP_A_SIZE];
	readCMD(RDCFGA, regbuffer, CFG_GROUP_A_SIZE);

	regbuffer[4] = Channels & 0xFF;
	regbuffer[5] &= 0xF0;
	regbuffer[5] |= (Channels>>8) & 0x0F;
	writeCMD(WRCFGA, regbuffer, CFG_GROUP_A_SIZE);

	readCMD(RDCFGB, regbuffer, CFG_GROUP_B_SIZE);
	regbuffer[0] &= 0x0F;
	regbuffer[0] |= (Channels>>8) & 0xF0;
	regbuffer[1] &= 0xFC;
	regbuffer[1] |= 0x03 & (Channels>>16);
	writeCMD(WRCFGB, regbuffer, CFG_GROUP_B_SIZE);

	return 0;
}

uint8 amsStartBalancing(uint8 dutyCycle)
{
	writeCMD(UNMUTE, NULL, 0);
	return 0;
}

uint8 amsStopBalancing()
{
	writeCMD(MUTE, NULL, 0);
	return 0;
}

uint8 amsSelfTest()
{
	return 0;
}



uint8 amsConfigUnderVoltage(uint16 underVoltage)
{
	uint8 buffer[CFG_GROUP_A_SIZE];
	readCMD(RDCFGA, buffer, CFG_GROUP_A_SIZE);

	buffer[1] = (uint8) underVoltage & 0xFF;
	uint8 ovuv = buffer[2] & 0xF0;
	ovuv |= (uint8) (underVoltage >> 8) & 0x0F;
	buffer[2] = ovuv;

	writeCMD(WRCFGA, buffer, CFG_GROUP_A_SIZE);

	return 0;
}

uint8 amsCheckUnderOverVoltage(Cell_Module *module)
{
	uint8 regbuffer[STATUS_GROUP_B_SIZE];
	uint32 overundervoltages = 0;
	readCMD(RDSTATB, regbuffer, STATUS_GROUP_B_SIZE);
	overundervoltages = regbuffer[2] | (regbuffer[3]<<8) | (regbuffer[4]<<16);
	module->overVoltage = 0;
	module->underVoltage = 0;
	for(uint8 n = 0; n < 12; n++)
	{
		uint8 overvolt = (overundervoltages>>(2*n+1)) & 0x01;
		uint8 undervolt = (overundervoltages>>(2*n))&0x01;

		module->overVoltage |= overvolt<<n;
		module->underVoltage |= undervolt<<n;
	}

	readCMD(RDAUXD,regbuffer,AUX_GROUP_D_SIZE);
	overundervoltages = 0;
	overundervoltages = regbuffer[4] | (regbuffer[5]<<8);

	for(uint8 n = 0; n < 6; n++)
	{
		uint8 overvolt = (overundervoltages>>(2*n+1)) & 0x01;
		uint8 undervolt = (overundervoltages>>(2*n))&0x01;

		module->overVoltage |= (uint32) overvolt<<(n+12);
		module->underVoltage |= (uint32) undervolt<<(n+12);
	}


	return 0;
}

uint8 amsConfigOverVoltage(uint16 overVoltage)
{
	uint8 buffer[CFG_GROUP_B_SIZE];

	readCMD(RDCFGA, buffer, CFG_GROUP_A_SIZE);
	buffer[2] &= 0x0F;
	buffer[2] |= (uint8) overVoltage << 4;
	buffer[3] = (uint8)(overVoltage>>4);

	writeCMD(WRCFGA, buffer, CFG_GROUP_A_SIZE);

	return 0;
}

/*
void dumpRegister(UART_HandleTypeDef *huart, uint8 RegID, uint8* buffer)
{
	switch(RegID)
	{
		case CFG_GROUP_A_ID:
			readCMD(RDCFGA, buffer, CFG_GROUP_A_SIZE);
		break;
		case CFG_GROUP_B_ID:
					readCMD(RDCFGB, buffer, CFG_GROUP_A_SIZE);
				break;
		case CV_GROUP_A_ID:
					readCMD(RDCVA, buffer, CFG_GROUP_A_SIZE);
				break;
		case CV_GROUP_B_ID:
					readCMD(RDCVB, buffer, CFG_GROUP_A_SIZE);
				break;
		case CV_GROUP_C_ID:
					readCMD(RDCVC, buffer, CFG_GROUP_A_SIZE);
				break;
		case CV_GROUP_D_ID:
					readCMD(RDCVD, buffer, CFG_GROUP_A_SIZE);
				break;
		case CV_GROUP_E_ID:
					readCMD(RDCVE, buffer, CFG_GROUP_A_SIZE);
				break;
		case CV_GROUP_F_ID:
					readCMD(RDCVF, buffer, CFG_GROUP_A_SIZE);
				break;
		case AUX_GROUP_A_ID:
					readCMD(RDAUXA, buffer, CFG_GROUP_A_SIZE);
				break;
		case AUX_GROUP_B_ID:
					readCMD(RDAUXB, buffer, CFG_GROUP_A_SIZE);
				break;
		case AUX_GROUP_C_ID:
					readCMD(RDAUXC, buffer, CFG_GROUP_A_SIZE);
				break;
		case AUX_GROUP_D_ID:
					readCMD(RDAUXD, buffer, CFG_GROUP_A_SIZE);
				break;
		case STATUS_GROUP_A_ID:
					readCMD(RDSTATA, buffer, CFG_GROUP_A_SIZE);
				break;
		case STATUS_GROUP_B_ID:
					readCMD(RDSTATB, buffer, CFG_GROUP_A_SIZE);
				break;
		case COMM_GROUP_ID:
					readCMD(RDCOMM, buffer, CFG_GROUP_A_SIZE);
				break;
		case S_CONTROL_GROUP_ID:
					readCMD(RDSCTRL, buffer, CFG_GROUP_A_SIZE);
				break;
		case PWM_GROUP_ID:
					readCMD(RDPWM, buffer, CFG_GROUP_A_SIZE);
				break;
		case PWM_S_CONTROL_GROUP_B_ID:
					readCMD(RDPSB, buffer, CFG_GROUP_A_SIZE);
				break;
	}
}
*/

uint8 amsClearStatus()
{
	uint8 buffer[6];
	writeCMD(CLRSTAT, buffer, 0);
	return 0;
}
uint8 amsClearAux()
{
	uint8 buffer[6];
	writeCMD(CLRAUX, buffer, 0);
	return 0;
}
uint8 amsClearCells()
{
	uint8 buffer[6];
	writeCMD(CLRCELL, buffer, 0);
	return 0;
}

uint8 amsSendWarning()
{
	//HAL_GPIO_WritePin(AMS_Warning_GPIO_Port, AMS_Warning_Pin, GPIO_PIN_SET);
	return 0;
}

uint8 amsSendError()
{
	//HAL_GPIO_WritePin(AMS_Error_GPIO_Port, AMS_Error_Pin, GPIO_PIN_SET);
	return 0;
}

uint8 amsClearWarning()
{
	//HAL_GPIO_WritePin(AMS_Warning_GPIO_Port, AMS_Warning_Pin, GPIO_PIN_RESET);
	return 0;
}

uint8 amsClearError()
{
	//HAL_GPIO_WritePin(AMS_Error_GPIO_Port, AMS_Error_Pin, GPIO_PIN_RESET);
	return 0;
}

uint8 amscheckOpenCellWire(Cell_Module *module)
{
	uint8 args;
	uint16 cellspu[18];

	writeCMD(ADOW |MD01|CH000|PUP , &args, 0); //run Pull Up at least Twice
	HAL_Delay(5);
	writeCMD(ADOW |MD01|CH000|PUP , &args, 0); //run Pull Up at least Twice
	HAL_Delay(5);

	amsReadCellVoltages(module);

	for(uint8_t n = 0; n <numberofcells; n++)
	{
		cellspu[n] = module->cellVoltages[n];
	}


	writeCMD(ADOW |MD01|CH000, &args, 0); //run Pull Up at least Twice
	HAL_Delay(5);
	writeCMD(ADOW |MD01|CH000, &args, 0); //run Pull Up at least Twice
	HAL_Delay(5);

	amsReadCellVoltages(module);

	for(uint8 n = 1; n < numberofcells; n++)
	{
		int dv = cellspu[n]-module->cellVoltages[n];
		if(dv < -4000)
		{
			return (1+n);
		}
	}
	if((cellspu[0] == 0) || (cellspu[0] == 0xFFFF))
	{
		return 1;
	}
	if(module->cellVoltages[numberofcells-1] == 0)
	{
		return 19;
	}

	return 0;
}

uint8 amsReadCellVoltages(Cell_Module *module)
{
	uint8 rxbuffer[CV_GROUP_A_SIZE];
	readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE);
	module->cellVoltages[0] = rxbuffer[0] | (rxbuffer[1]<<8);
	module->cellVoltages[1] = rxbuffer[2] | (rxbuffer[3]<<8);
	module->cellVoltages[2] = rxbuffer[4] | (rxbuffer[5]<<8);

	readCMD(RDCVB, rxbuffer, CV_GROUP_A_SIZE);
	module->cellVoltages[3] = rxbuffer[0] | (rxbuffer[1]<<8);
	module->cellVoltages[4] = rxbuffer[2] | (rxbuffer[3]<<8);
	module->cellVoltages[5] = rxbuffer[4] | (rxbuffer[5]<<8);

	readCMD(RDCVC, rxbuffer, CV_GROUP_A_SIZE);
	module->cellVoltages[6] = rxbuffer[0] | (rxbuffer[1]<<8);
	module->cellVoltages[7] = rxbuffer[2] | (rxbuffer[3]<<8);
	module->cellVoltages[8] = rxbuffer[4] | (rxbuffer[5]<<8);

	readCMD(RDCVD, rxbuffer, CV_GROUP_A_SIZE);
	module->cellVoltages[9] = rxbuffer[0] | (rxbuffer[1]<<8);
	module->cellVoltages[10] = rxbuffer[2] | (rxbuffer[3]<<8);
	module->cellVoltages[11] = rxbuffer[4] | (rxbuffer[5]<<8);

	readCMD(RDCVE, rxbuffer, CV_GROUP_A_SIZE);
	module->cellVoltages[12] = rxbuffer[0] | (rxbuffer[1]<<8);
	module->cellVoltages[13] = rxbuffer[2] | (rxbuffer[3]<<8);
	module->cellVoltages[14] = rxbuffer[4] | (rxbuffer[5]<<8);

	readCMD(RDCVF, rxbuffer, CV_GROUP_A_SIZE);
	module->cellVoltages[15] = rxbuffer[0] | (rxbuffer[1]<<8);
	module->cellVoltages[16] = rxbuffer[2] | (rxbuffer[3]<<8);
	module->cellVoltages[17] = rxbuffer[4] | (rxbuffer[5]<<8);

	return 0;
}
