#include "common.h"
#include "drv_usart.h"
#include "app_rs485_1.h"
#include "app.h"
#include "hardware_test.h"
#include "app_end_ctr.h"
#include "drv_io.h"
#include "measure_vol.h"
#include "shark_xl.h"
#include "shark_charge.h"

SUB_BMS_INFO sub_bms_info_1 = {
	.uart = USART0,
	.address = SUB_BMS_ADDRESS_1,
};

TEST_INFO test_info;

static int8_t Get_Check_Sum_1(uint16_t*value, const uint8_t*data,uint16_t size)
{
	uint32_t checksum;
	if((NULL==value)||(NULL==data)||(0==size))
	{
		return 0;
	}
//
	checksum = 0;
	while(size>1)
	{
		checksum += *(uint16_t*)data;
		data += 2;
		size -= 2;
	}
//
	if(size>0)
	{
		checksum += *data;
	}
//
	while(checksum>>16)
	{
		checksum = (checksum&0xFFFF)+(checksum>>16);
	}	
//
	*value = (uint16_t)~checksum;
	
	return 1;
}

void shark_battery_clear(SUB_BMS_INFO *info)
{
	shark_battery_full = shark_false;

	info->update_mask = 0xFF;
	info->sub_bms_cmd.operate = OP_READ_INFO;

	memset(&info->packet_common, 0x00, sizeof(info->packet_common));
	memset(&info->bat_dev_info, 0x00, sizeof(info->bat_dev_info));
	memset(&info->bat_times, 0x00, sizeof(info->bat_times));
	memset(&info->cell_vol, 0x00, sizeof(info->cell_vol));
	memset(&info->temp_other, 0x00, sizeof(info->temp_other));
	memset(&info->sub_bms_cmd, 0x00, sizeof(info->sub_bms_cmd));
}

static int8_t Handle_Sub_BMS_CMD_1(SUB_BMS_INFO *info, const u8 *buff, u8 length)
{
	COMMAND_BODY *bms = (COMMAND_BODY *) buff;
	int8_t bStatus;
	uint16_t count;

	do
	{

		if(bms->type != info->address || bms->dir != BMS_DIR || bms->bStatus == 0)
			break;
		
		//CRC 
		count = bms->checksum;
		bms->checksum = 0;
		bStatus = Get_Check_Sum_1((void*)&bms->checksum, buff, bms->size);
		if(1!=bStatus || count != bms->checksum)
		{
			break;
		}

		//handle frame
		count = sizeof(COMMAND_BODY);
		
		memcpy(&info->packet_common, buff + count,sizeof(info->packet_common));
		count += sizeof(info->packet_common);

		info->connected = CONFIG_UART_GOOD;
		info->send_state = SHARK_SEND_SUCCESS;

		//bang zi ce shi start
		//temp_bms ->packet_common.m_percent /= 2;
		//bang zi ce shi end

		
		if((info->packet_common.operate_result&0x01) != 0x01)
			break;

		switch((info->packet_common.operate_result&0xF0)>>4)
		{
			case OP_NONE:
				
				break;

			case OP_BOND:
				
				break;
				
			case OP_WRITE_SN:	
				
				break;
				
			case OP_PAIR:
				
				break;
			case OP_UPDATE_PAIR:
				
				break;
			case OP_READ_INFO:
				memcpy(&info->bat_dev_info, buff + count,sizeof(info->bat_dev_info));
				count += sizeof(info->bat_dev_info);
				info->update_mask &= ~SHARK_BATT_INFO_VERTION;
				break;
			case OP_ALARM_TIMES:
				memcpy(&info->bat_times, buff + count, sizeof(info->bat_times));
				count += sizeof(info->bat_times);
				info->update_mask &= ~SHARK_BATT_INFO_TIMES;
				break;	
			case OP_CELL_VOL:
				memcpy(&info->cell_vol, buff + count, sizeof(info->cell_vol));
				count += sizeof(info->cell_vol);
				info->update_mask &= ~SHARK_BATT_INFO_CELL_VOL;
				break;
			case OP_TEMP_OTHER:
				memcpy(&info->temp_other, buff + count, sizeof(info->temp_other));
				count += sizeof(info->temp_other);
				info->update_mask &= ~SHARK_BATT_INFO_TEMP;
				break;

				
			case OP_OPEN_FET:
				
				break;

			case OP_CLEAR_PAIR:
				break;

			case OP_UPDATE_SOFTWARE_REQ:
				break;
			case OP_UPDATE_SOFTWARE:
				break;
			default:break;

		}
		if(((info->packet_common.operate_result&0xF0)>>4) == info->sub_bms_cmd.operate)
		{
			memset(&info->sub_bms_cmd,0x00,sizeof(info->sub_bms_cmd));

			if (info->update_mask != 0) {
				if ((info->update_mask & SHARK_BATT_INFO_VERTION) != 0) {
					info->sub_bms_cmd.operate = OP_READ_INFO;
				} else if ((info->update_mask & SHARK_BATT_INFO_TIMES) != 0) {
					info->sub_bms_cmd.operate = OP_ALARM_TIMES;
				} else if ((info->update_mask & SHARK_BATT_INFO_CELL_VOL) != 0) {
					info->sub_bms_cmd.operate = OP_CELL_VOL;
				} else if ((info->update_mask & SHARK_BATT_INFO_TEMP) != 0) {
					info->sub_bms_cmd.operate = OP_TEMP_OTHER;
				} else {
					info->sub_bms_cmd.operate = OP_NONE;
					info->update_mask = 0;
				}

				info->tx_pending = shark_true;
			} else {
				info->sub_bms_cmd.operate = OP_NONE;
			}
		}

		return 1;
		
	}while(0);

	return 0;
	
}

shark_bool shark_battery_send_command(SUB_BMS_INFO *info)
{
	int8_t bStatus;// 默认需要回复
	COMMAND_BODY*body = (COMMAND_BODY *) info->tx_buff;
	uint8_t *buf = info->tx_buff;

	if (info->send_state == SHARK_SEND_PENDING) {
		return shark_false;
	}

// 填帧头
	body->size =  sizeof(COMMAND_BODY);
	body->type = info->address;
	body->protocol = 'B';
	body->cmd = SET_COMMAND;
	body->dir = BMS_DIR;
	body->checksum = 0;
	body->bStatus = 0;

	// 填帧数据
	//实时转速
	buf[body->size++] = 0;

	//本次电门打开已经行驶的里程
	buf[body->size++] = 0;
	buf[body->size++] = 0;
	buf[body->size++] = 0;
	buf[body->size++] = 0;

	//电门开关信号
	buf[body->size++] = 0;

	//操作
	buf[body->size++] = info->sub_bms_cmd.operate;

	//对码
	buf[body->size++] = shark_charger_enabled ? CW_CHE_SHANG_CHARGER : CW_CHE_SHANG_NO_CHARGER;
	buf[body->size++] = 0;
	buf[body->size++] = 0;
	buf[body->size++] = 0;
	//更换对码，新对码
	buf[body->size++] = 0;
	buf[body->size++] = 0;
	buf[body->size++] = 0;
	buf[body->size++] = 0;

	switch(info->sub_bms_cmd.operate)
	{
		case OP_NONE:
			
			break;

		case OP_BOND:
			
			break;
			
		case OP_WRITE_SN:	
			switch(info->sub_bms_cmd.param)
			{
				case 3:
					buf[body->size++] = (uint8_t)(info->sub_bms_cmd.param);
					break;
				case 4:
					buf[body->size++] = (uint8_t)(info->sub_bms_cmd.param);
					break;
			}
			break;
			
		case OP_PAIR:
			
			break;
		case OP_UPDATE_PAIR:
			
			break;
		case OP_READ_INFO:
			
			break;
		case OP_ALARM_TIMES:
			
			break;	
		case OP_CELL_VOL:
			
			break;

		case OP_OPEN_FET:
			buf[body->size++] = (uint8_t)(info->sub_bms_cmd.param);
			break;
		case OP_UPDATE_SOFTWARE_REQ:
			
			break;
		case OP_UPDATE_SOFTWARE:
			
			break;
		case OP_CLEAR_PAIR:
			break;
		default:break;
	}
	
	bStatus = Get_Check_Sum_1((void*)&body->checksum,(void*)body,body->size);
	if(1!=bStatus)
	{
		return shark_false;
	}

	info->send_state = SHARK_SEND_PENDING;
	shark_uart_write(info, body->size);

	return shark_true;
}

shark_bool shark_battery_send_command1(void)
{
	if (sub_bms_info_1.send_state != SHARK_SEND_PENDING) {
		return shark_false;
	}

	return shark_battery_send_command(&sub_bms_info_1);
}

shark_bool shark_battery_send_command2(void)
{
	if (sub_bms_info_2.send_state != SHARK_SEND_PENDING) {
		return shark_false;
	}

	return shark_battery_send_command(&sub_bms_info_2);
}

shark_bool shark_battery_process(SUB_BMS_INFO *info, const u8 *buff, u8 length)
{
	if (length != buff[0])
	{
		if(memcmp(buff, "zhengjiceshi",12) == 0 && ht_mode == 0)
		{
			Writer_HT_Flash(1);
			__set_FAULTMASK(1);
			NVIC_SystemReset();
		}
		return 0;
	}

	if (length > sizeof(COMMAND_BODY))
	{
		if(!Handle_Sub_BMS_CMD_1(info, buff, length))
		{
			return 0;
		}
	}

	return 1;
	
}

void Sub_BMS_1_Initial(void)
{
	shark_uart_init();
	sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;
	sub_bms_info_2.sub_bms_cmd.operate = OP_READ_INFO;
}

static shark_battery_exit_t shark_battery_is_normal_raw(SUB_BMS_INFO *info, shark_battery_power_t power)
{
	u16 work_status;

	if (info->define_error != D_BMS_ERROR_NO) {
		return SHARK_BATT_EXIT_ERROR;
	}

	if (info->test_error != D_BMS_ERROR_NO) {
		return SHARK_BATT_EXIT_ERROR;
	}

	work_status = info->packet_common.work_status;
	work_status &= ~(ST_CHRG_CUR | ST_DISCHRG_CUR | ST_OVRDISCHRG_CUR | ST_SMALL_CURRENT_OVER);

	if (shark_charger_enabled) {
		work_status &= ~(ST_OVRDISCHRG_VOL | ST_PDOWN | ST_UDR_TEMPE_DISCHRG | ST_OVR_TEMPE_DISCHRG);
	} else {
		work_status &= ~(ST_OVRCHRG_VOL | ST_OVR_TEMPE_CHRG | ST_UDR_TEMPE_CHRG);
	}

	if (work_status != 0) {
		return SHARK_BATT_EXIT_ERROR;
	}

	if (info->connected == 0) {
		if (info->used == shark_false) {
			return SHARK_BATT_EXIT_485;
		}

		if (shark_xl_check_with_qd() == shark_false) {
			return SHARK_BATT_EXIT_485;
		}

		if (cb_operate_state == CB_BAT1_BAT2_SERIES) {
			if (Measure_Vol() < SERIES_VOLTAGE_MIN) {
				return SHARK_BATT_EXIT_485;
			}
		} else if (Measure_Vol() < SINGLE_VOLTAGE_MIN) {
			return SHARK_BATT_EXIT_485;
		}
	}

	if (!shark_battery_check_power(info, power)) {
		return SHARK_BATT_EXIT_POWER;
	}

	return SHARK_BATT_EXIT_SUCCESS;
}

shark_battery_exit_t shark_battery_is_normal(SUB_BMS_INFO *info, shark_battery_power_t power)
{
	shark_battery_exit_t code = shark_battery_is_normal_raw(info, power);

	if (code != SHARK_BATT_EXIT_SUCCESS) {
		info->exit_code = code;
		info->exit_times++;
	}

	return code;
}

shark_battery_exit_t Is_Sub_BMS_1_Normal(void)
{
	return shark_battery_is_normal(&sub_bms_info_1, SHARK_BATT_POWER_ANY);
}

u32 shark_battery_get_voltage(SUB_BMS_INFO *info)
{
	return info->packet_common.m_total_vol - (info->packet_common.m_current / 30);
}

u32 shark_battery_get_voltage_delta(void)
{
	u32 voltage1 = shark_battery_get_voltage1();
	u32 voltage2 = shark_battery_get_voltage2();

	if (voltage1 > voltage2) {
		return voltage1 - voltage2;
	} else {
		return voltage2 - voltage1;
	}
}

u32 shark_battery_get_voltage_min(void)
{
	u32 voltage1 = shark_battery_get_voltage1();
	u32 voltage2 = shark_battery_get_voltage2();

	if (voltage1 < voltage2) {
		return voltage1;
	} else {
		return voltage2;
	}
}

u32 shark_battery_get_voltage_max(void)
{
	u32 voltage1 = shark_battery_get_voltage1();
	u32 voltage2 = shark_battery_get_voltage2();

	if (voltage1 > voltage2) {
		return voltage1;
	} else {
		return voltage2;
	}
}

static u8 shark_battery_get_power_param(shark_battery_power_t power)
{
	switch (power) {
	case SHARK_BATT_POWER_SMALL:
		return 0x04;

	case SHARK_BATT_POWER_FULL:
		return 0x03;

	default:
		return 0x00;
	}
}

static void shark_battery_set_power_param(SUB_BMS_INFO *info, shark_battery_power_t power)
{
	info->sub_bms_cmd.operate = OP_OPEN_FET;
	info->sub_bms_cmd.param = shark_battery_get_power_param(power);
}

shark_battery_power_t shark_battery_get_power(SUB_BMS_INFO *info)
{
	if (info->connected != CONFIG_UART_GOOD) {
		return SHARK_BATT_POWER_FAULT;
	}

	if ((info->packet_common.bms_status & BMS_POWER_ALL) == BMS_POWER_ALL) {
		return SHARK_BATT_POWER_ALL;
	}

	if ((info->packet_common.bms_status & BMS_POWER_FULL) == BMS_POWER_FULL) {
		return SHARK_BATT_POWER_FULL;
	}

	if ((info->packet_common.bms_status & BMS_POWER_SMALL) == BMS_POWER_SMALL) {
		return SHARK_BATT_POWER_SMALL;
	}

	return SHARK_BATT_POWER_OFF;
}

shark_bool shark_battery_check_power(SUB_BMS_INFO *info, shark_battery_power_t power)
{
	switch (power) {
	case SHARK_BATT_POWER_SMALL:
		return (info->packet_common.bms_status & BMS_POWER_SMALL) == BMS_POWER_SMALL;

	case SHARK_BATT_POWER_FULL:
		return(info->packet_common.bms_status & BMS_POWER_FULL) == BMS_POWER_FULL;

	case SHARK_BATT_POWER_ALL:
		return (info->packet_common.bms_status & BMS_POWER_ALL) == BMS_POWER_ALL;

	case SHARK_BATT_POWER_ANY:
		return shark_true;

	default:
		return (info->packet_common.bms_status & BMS_POWER_ALL) == 0;
	}
}

static void shark_battery_serial_wait_ready(void)
{
	u64 time = shark_get_mseconds() + 200;

	while (sub_bms_info_1.send_state == SHARK_SEND_PENDING && time > shark_get_time_safe());
	while (sub_bms_info_2.send_state == SHARK_SEND_PENDING && time > shark_get_time_safe());

	if (sub_bms_info_1.connected > CONFIG_UART_PING) {
		sub_bms_info_1.connected = CONFIG_UART_PING;
	}

	if (sub_bms_info_2.connected > CONFIG_UART_PING) {
		sub_bms_info_2.connected = CONFIG_UART_PING;
	}
}

static void shark_battery_send_commands(void)
{
	shark_battery_send_command(&sub_bms_info_1);
	shark_battery_send_command(&sub_bms_info_2);
}

static shark_battery_mask_t shark_battery_wait_response(void)
{
	shark_battery_mask_t success = SHARK_BATT_MASK_NONE;

	while (shark_battery_send_pending(&sub_bms_info_1)) {
		shark_uart_poll_safe();
	}

	while (shark_battery_send_pending(&sub_bms_info_2)) {
		shark_uart_poll_safe();
	}

	if (shark_battery_send_success(&sub_bms_info_1)) {
		success |= SHARK_BATT_MASK_BAT1;
	}

	if (shark_battery_send_success(&sub_bms_info_2)) {
		success |= SHARK_BATT_MASK_BAT2;
	}

	return success;
}

shark_battery_mask_t shark_battery_set_power(shark_battery_power_t power1, shark_battery_power_t power2, shark_battery_mask_t mask)
{
	shark_battery_mask_t success = SHARK_BATT_MASK_NONE;
	u8 times;

	shark_battery_serial_wait_ready();

	for (times = 0; times < 3; times++) {
		shark_battery_mask_t response;

		shark_battery_set_power_param(&sub_bms_info_1, power1);
		shark_battery_set_power_param(&sub_bms_info_2, power2);
		shark_battery_send_commands();

		response = shark_battery_wait_response();

		if ((response & SHARK_BATT_MASK_BAT1) != 0 && shark_battery_check_power(&sub_bms_info_1, power1)) {
			success |= SHARK_BATT_MASK_BAT1;
		}

		if ((response & SHARK_BATT_MASK_BAT2) != 0 && shark_battery_check_power(&sub_bms_info_2, power2)) {
			success |= SHARK_BATT_MASK_BAT2;
		}

		if ((success & mask) == mask) {
			return mask;
		}
	}

	return success;
}

shark_battery_mask_t shark_battery_detect(u8 times)
{
	shark_battery_mask_t success;

	shark_battery_serial_wait_ready();

	for (success = SHARK_BATT_MASK_NONE; times > 0; times--) {
		sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;
		sub_bms_info_2.sub_bms_cmd.operate = OP_READ_INFO;
		shark_battery_send_commands();

		success |= shark_battery_wait_response();
		if (success == SHARK_BATT_MASK_BOTH) {
			break;
		}
	}

	return success;
}

shark_bool shark_battery_ping(u8 times)
{
	while (shark_true) {
		if (shark_battery_detect(1) != SHARK_BATT_MASK_NONE) {
			return shark_true;
		}

		if (times > 0) {
			times--;
		} else {
			break;
		}
	}

	return shark_false;
}

void Save_Test_Info_To_Flash(uint8_t *data,uint16_t len)
{
	uint32_t capacity = (REG32(0x1FFFF7E0) & 0xFFFF) << 10;
	uint32_t address = 0x08000000 + (capacity - TEST_INFO_FLASH_ADDRESS);
	uint8_t i = 0;
	uint32_t df_value = 0x0325;
	
	
	fmc_unlock();
	Flash_flag_clear();
	fmc_page_erase(address);
	Flash_flag_clear();
	fmc_lock();



	fmc_unlock();
	
	i = 0;
	while(i<len)
	{
		memcpy(&df_value,&data[i],4);
		fmc_word_program(address + i,df_value);
		Flash_flag_clear();	
		i+= 4;
	}

	fmc_lock();
	
}


void Initial_Test_Info(void)
{
	uint32_t capacity = (REG32(0x1FFFF7E0) & 0xFFFF) << 10;
	uint32_t address = 0x08000000 + (capacity - TEST_INFO_FLASH_ADDRESS);
	
	
	TEST_INFO *temp_test_info = (TEST_INFO *)address;

	memset(&test_info,0x00,sizeof(test_info));
	 
	if(temp_test_info->ti_flag != TI_VALID_FLAG_KEY)
	{
		test_info.ti_flag = TI_VALID_FLAG_KEY;
		
		Save_Test_Info_To_Flash((uint8_t *)&test_info,sizeof(test_info));
	}
	else
	{
		test_info = *temp_test_info;

		test_info.ti_set = 0;
	}

	
}

void Save_Test_Info(void)
{		
	//if(test_info.ti_set == 0)
	//	return;
	
	Save_Test_Info_To_Flash((uint8_t*)&test_info, sizeof(test_info));
}
void Ca_Chu_Test_Info(void)
{
	memset(&test_info, 0x00,sizeof(test_info));

	test_info.ti_flag = TI_VALID_FLAG_KEY;
		
	Save_Test_Info_To_Flash((uint8_t *)&test_info,sizeof(test_info));
}

void Check_Enable_Test_Info(void)
{

	if(cb_operate_state == CB_BAT1_BAT2_SERIES)
		test_info.ti_set = 1;
	else
		test_info.ti_set = 0;
}

void shark_bms_set_vgs(shark_bms_vgs_t mask, uint8_t enable)
{
	static uint8_t shark_bms_vgs_mask;

	if (enable) {
		if (shark_bms_vgs_mask == 0) {
			println("FL Enable");
		}

		shark_bms_vgs_mask |= mask;
		gpio_bit_reset(GPIO_PORT_FL, GPIO_PIN_FL);
	} else {
		shark_bms_vgs_mask &= ~mask;

		if (shark_bms_vgs_mask == 0) {
			gpio_bit_set(GPIO_PORT_FL, GPIO_PIN_FL);
			println("FL Disable");
		}
	}
}

void shark_bms_set_mos(shark_bool ss, shark_bool s11, shark_bool s21)
{
	println("S11:%d, S21:%d, SS:%d", s11, s21, ss);

	shark_bms_set_vgs(SHARK_BMS_VGS_FV, s11);

	if (ss == 0) {
		gpio_bit_reset(GPIO_PORT_SS, GPIO_PIN_SS);
	}

	if (s11 == 0) {
		gpio_bit_reset(GPIO_PORT_S11, GPIO_PIN_S11);
	}

	if (s21 == 0) {
		gpio_bit_reset(GPIO_PORT_S21, GPIO_PIN_S21);
	}

	if (ss != 0) {
		gpio_bit_set(GPIO_PORT_SS, GPIO_PIN_SS);
	}

	if (s11 != 0) {
		gpio_bit_set(GPIO_PORT_S11, GPIO_PIN_S11);
	}

	if (s21 != 0) {
		gpio_bit_set(GPIO_PORT_S21, GPIO_PIN_S21);
	}
}

