/*
	Copyright 2017 - 2018 Danny Bokma	danny@diebie.nl
	Copyright 2019 - 2020 Kevin Dionne	kevin.dionne@ennoid.me

	This file is part of the DieBieMS/ENNOID-BMS firmware.

	The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#include "modStateOfCharge.h"
#include "main.h"

modStateOfChargeStructTypeDef modStateOfChargeGeneralStateOfCharge;
modPowerElectronicsPackStateTypedef *modStateOfChargePackStatehandle;
modConfigGeneralConfigStructTypedef *modStateOfChargeGeneralConfigHandle;
uint32_t modStateOfChargeLargeCoulombTick;
uint32_t modStateOfChargeStoreSoCTick;

bool modStateOfChargePowerDownSavedFlag = false;

modStateOfChargeStructTypeDef* modStateOfChargeInit(modPowerElectronicsPackStateTypedef *packState, modConfigGeneralConfigStructTypedef *generalConfigPointer){
	modStateOfChargePackStatehandle = packState;
	modStateOfChargeGeneralConfigHandle = generalConfigPointer;
	driverSWStorageManagerStateOfChargeStructSize = (sizeof(modStateOfChargeStructTypeDef)/sizeof(uint16_t)); // Calculate the space needed for the config struct in EEPROM
	
	modStateOfChargeLargeCoulombTick = HAL_GetTick();
	modStateOfChargeStoreSoCTick = HAL_GetTick();
	
	return &modStateOfChargeGeneralStateOfCharge;
};

float real_capacity = 0;
float previous_capacity = 0;
float previous_SoC = 0;
//static float current_SoC = 0;
float soc_diff = 0;
float capacity_diff = 0;
uint8_t SoC_Save_Flag = 0;

void modStateOfChargeProcess(void){
	// Calculate accumulated energy
	uint32_t dt = HAL_GetTick() - modStateOfChargeLargeCoulombTick;

	static float lastsaved_remainingCapacityAh = 0;
	modStateOfChargeStructTypeDef lastGeneralStateOfCharge;





	/*
	 * ������� ��������
	 * ������� ��������
	 * ���� �������� ������� �������
	 *
	 * �������� = ��������, �����
	 * �������� ������� ��� �� ���������� �� ������� ������
	 *
	 * soc = ������ ������� / �������� ������� * 100
	 *
	 * � - ������� ������� �� ������ ���� ������ �� 1% (��)
	 * b - ������� ������� ������� ������ �� 5% (��) ( x amp - 5%
	 * 													y amp - 100%; y = 100x/5
	 *
	 * �������� ������� = ( 100 * �������� ��� ) / ������ � ���������
	 *
	 * 100 * 2 /1 = 200
	 *
	 *  	 *
	 * �������� ������ � ��������� 1%, �������� 1,4���
	 * �� = (100 * 1.4) / 1 = 140 ���
	 *
	 * �������� ������ � ��������� 1%, �������� 2,8���
	 * (100 * 2,8) /1 = 280 ���
	 *
	 * ������ 2%, �������� 1,4
	 * (100 * 1.4) /2 70 ���
	 *
	 *
	 *
	 * soh
	 *
	 * �������� ������� 150, ������ 1,5, ��� ���������� 99%
	 *
	 *
	 * ������� ������� ��� ������ � ������� ���������� ������ � (������ ���) ������� ��������� ��� ���������
	 *
	 * soh = ��������� �������� ������� � ��������
	 *
	 * soc =
	 *
	 *
	 */
	
	lastGeneralStateOfCharge = modStateOfChargeGeneralStateOfCharge;
	
	modStateOfChargeLargeCoulombTick = HAL_GetTick();
	// calc in Ahmps how much we put or take
	modStateOfChargeGeneralStateOfCharge.remainingCapacityAh += dt*modStateOfChargePackStatehandle->packCurrent/(3600*1000);// (miliseconds * amps)/(3600*1000) accumulatedCharge in AmpHour.
	
	// Cap the max stored energy to the configured battery capacity.
	// if we put more than battery is, set maximum
	if(modStateOfChargeGeneralStateOfCharge.remainingCapacityAh > modStateOfChargeGeneralConfigHandle->batteryCapacity)
		modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
	
	// if we take more than battery, set zero
	if(modStateOfChargeGeneralStateOfCharge.remainingCapacityAh < 0.0f)
		modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = 0.0f;
	
	// Calculate state of charge
	// calc percent of we put/take to battery capacity
	modStateOfChargeGeneralStateOfCharge.generalStateOfCharge =
            modStateOfChargeGeneralStateOfCharge.remainingCapacityAh / modStateOfChargeGeneralConfigHandle->batteryCapacity * 100.0f;
	
	if(SoC_Save_Flag == 0) {
		previous_SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
		previous_capacity = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;

		SoC_Save_Flag = 1;
	}

	if(previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge > 1) {
		soc_diff = previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
		//
		if(soc_diff == 0) soc_diff = 1;
		capacity_diff = previous_capacity - modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
		real_capacity = (100 * capacity_diff) / soc_diff;

		export_real_capacity = real_capacity;

		previous_SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
		previous_capacity = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;

		//SoC_Save_Flag = 0;

	} //else if (previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge < -1) {
	//	SoC_Save_Flag = 0;
	//}



	// if we have more than 100% it is 100%
	if(modStateOfChargeGeneralStateOfCharge.generalStateOfCharge >= 100.0f)
		modStateOfChargeGeneralStateOfCharge.generalStateOfCharge = 100.0f;
	
	// save soc and amps
	modStateOfChargePackStatehandle->SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
	modStateOfChargePackStatehandle->SoCCapacityAh = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
	
	// Store SoC every 'stateOfChargeStoreInterval'

	 modStateOfChargeGeneralConfigHandle->stateOfChargeStoreInterval = 10000;



	if(modDelayTick1ms(&modStateOfChargeStoreSoCTick,modStateOfChargeGeneralConfigHandle->stateOfChargeStoreInterval) &&
				(lastsaved_remainingCapacityAh != modStateOfChargeGeneralStateOfCharge.remainingCapacityAh)) {
		lastsaved_remainingCapacityAh = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
		modStateOfChargeStoreStateOfCharge();
	}


};

bool modStateOfChargeStoreAndLoadDefaultStateOfCharge(void){
	bool returnVal = false;
	if(driverSWStorageManagerStateOfChargeEmpty){
		// TODO: SoC manager is empy -> Determin SoC from voltage when voltages are available.
		modStateOfChargeStructTypeDef defaultStateOfCharge;
		defaultStateOfCharge.generalStateOfCharge = 100.0f;
		defaultStateOfCharge.generalStateOfHealth = 100.0f;
		defaultStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
		defaultStateOfCharge.remainingCapacityWh = 0.0f;
		
		driverSWStorageManagerStateOfChargeEmpty = false;
		driverSWStorageManagerStoreStruct(&defaultStateOfCharge,STORAGE_STATEOFCHARGE);
		// TODO_EEPROM
	}
	
	modStateOfChargeStructTypeDef tempStateOfCharge;
	driverSWStorageManagerGetStruct(&tempStateOfCharge,STORAGE_STATEOFCHARGE);
	
	modStateOfChargeLoadStateOfCharge();
	return returnVal;
};

bool modStateOfChargeStoreStateOfCharge(void){
	HAL_GPIO_TogglePin(HL2_GPIO_Port, HL2_Pin);
	return driverSWStorageManagerStoreStruct(&modStateOfChargeGeneralStateOfCharge,STORAGE_STATEOFCHARGE);
};

bool modStateOfChargeLoadStateOfCharge(void){
	return driverSWStorageManagerGetStruct(&modStateOfChargeGeneralStateOfCharge,STORAGE_STATEOFCHARGE);
};

bool modStateOfChargePowerDownSave(void) {
//	if(!modStateOfChargePowerDownSavedFlag) {
//		modStateOfChargePowerDownSavedFlag = true;
//		modStateOfChargeStoreStateOfCharge();
//		// TODO_EEPROM
//		return true;
//	}else
//		return false;
};

void modStateOfChargeVoltageEvent(modStateOfChargeVoltageEventTypeDef eventType) {
	switch(eventType) {
		case EVENT_EMPTY:
			break;
		case EVENT_FULL:
			modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
			break;
		default:
			break;
	}
};
