#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"

//uart1
static uint8_t app_rs485_buf[TX_BUFFER_SIZE];

static uint8_t bms_addr = SUB_BMS_ADDRESS_1;
SUB_BMS_COM sub_rs485_time_out_1;

SUB_BMS_INFO sub_bms_info_1;

DELAY_COMMON send_delay;

uint8_t RS485_busy_1 = 0;

uint8_t sub_bms_1_connect = 0;

uint8_t cang_wei = CW_CHE_SHANG_NO_CHARGER;

TEST_INFO test_info;

static int8_t Get_Check_Sum_1(uint16_t*value,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;
}

uint8_t SUB_BMS_1_DEC(void)
{
	return sub_bms_1_connect;
}

void RS485_Communication_Time_Out_1(void)
{
	if(sub_bms_info_1.rs485_connect)
	{
		sub_bms_info_1.conn_state = SUB_BMS_CONT_NO485;
	}
	else
	{
		sub_bms_info_1.conn_state = SUB_BMS_DISC_NO485;
	}
	
	if(sub_bms_info_1.rs485_time_out)
		return;
	memset(&sub_bms_info_1.packet_common,0x00,sizeof(sub_bms_info_1.packet_common));
	memset(&sub_bms_info_1.bat_dev_info,0x00,sizeof(sub_bms_info_1.bat_dev_info));
	memset(&sub_bms_info_1.bat_times,0x00,sizeof(sub_bms_info_1.bat_times));
	memset(&sub_bms_info_1.cell_vol,0x00,sizeof(sub_bms_info_1.cell_vol));
	memset(&sub_bms_info_1.temp_other,0x00,sizeof(sub_bms_info_1.temp_other));
	memset(&sub_bms_info_1.sub_bms_cmd,0x00,sizeof(sub_bms_info_1.sub_bms_cmd));
	sub_bms_info_1.rs485_time_out = 1;
	sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;
	//
	sub_bms_1_connect = 0;

}



static int8_t Handle_Sub_BMS_CMD_1(uint8_t *data)
{
	static uint8_t send_times = 0;
	COMMAND_BODY *bms = (COMMAND_BODY *)data;
	int8_t bStatus;
	uint16_t count;
	SUB_BMS_INFO *temp_bms;
	

	do
	{

		if(bms->type != bms_addr || bms->dir != BMS_DIR || bms->bStatus == 0)
			break;
		
		
		memset(&sub_rs485_time_out_1,0x00,sizeof(sub_rs485_time_out_1));
		g_event &= ~SUB_BMS_1_RS485_DISC_EVENT;
		temp_bms = &sub_bms_info_1;
		temp_bms->rs485_time_out = 0;
		//
		sub_bms_1_connect = 1;

		RS485_busy_1 = 0;

		if(sub_bms_info_1.rs485_connect)
		{
			sub_bms_info_1.conn_state = SUB_BMS_CONT_HV485;
		}
		else
		{
			sub_bms_info_1.conn_state = SUB_BMS_DISC_HV485;
		}
		
		//CRC 
		count = bms->checksum;
		bms->checksum = 0;
		bStatus = Get_Check_Sum_1((void*)&bms->checksum,data,bms->size);
		if(1!=bStatus || count != bms->checksum)
		{
			break;
		}

		//handle frame
		count = sizeof(COMMAND_BODY);
		
		memcpy(&temp_bms->packet_common,&data[count],sizeof(temp_bms->packet_common));
		count += sizeof(temp_bms->packet_common);

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

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

		switch((temp_bms->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(&temp_bms->bat_dev_info,&data[count],sizeof(temp_bms->bat_dev_info));
				count += sizeof(temp_bms->bat_dev_info);
				break;
			case OP_ALARM_TIMES:
				memcpy(&temp_bms->bat_times,&data[count],sizeof(temp_bms->bat_times));
				count += sizeof(temp_bms->bat_times);
				break;	
			case OP_CELL_VOL:
				memcpy(&temp_bms->cell_vol,&data[count],sizeof(temp_bms->cell_vol));
				count += sizeof(temp_bms->cell_vol);
				break;
			case OP_TEMP_OTHER:
				memcpy(&temp_bms->temp_other,&data[count],sizeof(temp_bms->temp_other));
				count += sizeof(temp_bms->temp_other);
				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(((temp_bms->packet_common.operate_result&0xF0)>>4) == temp_bms->sub_bms_cmd.operate)
		{
			memset(&temp_bms->sub_bms_cmd,0x00,sizeof(temp_bms->sub_bms_cmd));
			++send_times;
			if(send_times > 90)
			{
				temp_bms->sub_bms_cmd.operate = OP_ALARM_TIMES;
				send_times = 0;
			}
			else if(send_times > 60)
			{
				temp_bms->sub_bms_cmd.operate = OP_CELL_VOL;
				
			}
			else if(send_times > 30)
			{
				temp_bms->sub_bms_cmd.operate = OP_TEMP_OTHER;
				
			}
			else
				temp_bms->sub_bms_cmd.operate = OP_NONE;
		}
		return 1;
		
	}while(0);

	return 0;
	
}


static int8_t Send_Sub_BMS_CMD_1(void)
{
	int8_t bStatus;// 默认需要回复
	COMMAND_BODY*body = (COMMAND_BODY*)app_rs485_buf;
	uint8_t *buf = app_rs485_buf;
	SUB_BMS_INFO *temp_bms;
	
	
	temp_bms = &sub_bms_info_1;
	
	
// 填帧头
	body->size =  sizeof(COMMAND_BODY);
	body->type = bms_addr;
	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++] = temp_bms->sub_bms_cmd.operate;

	//对码
	buf[body->size++] = cang_wei;
	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(temp_bms->sub_bms_cmd.operate)
	{
		case OP_NONE:
			
			break;

		case OP_BOND:
			
			break;
			
		case OP_WRITE_SN:	
			switch(temp_bms->sub_bms_cmd.param)
			{
				case 3:
					buf[body->size++] = (uint8_t)(temp_bms->sub_bms_cmd.param);
					break;
				case 4:
					buf[body->size++] = (uint8_t)(temp_bms->sub_bms_cmd.param);
					
					buf[body->size++] = (uint8_t)(update_bat.ub_total>>0);
					buf[body->size++] = (uint8_t)(update_bat.ub_total>>8);
					buf[body->size++] = 0;
					buf[body->size++] = 0;
					buf[body->size++] = (uint8_t)(update_bat.ub_sq>>0);
					buf[body->size++] = (uint8_t)(update_bat.ub_sq>>8);
					buf[body->size++] = 0;
					buf[body->size++] = 0;
					memcpy(&buf[body->size],update_bat.ub_data,update_bat.ub_len);
					body->size += update_bat.ub_len;
					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)(temp_bms->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 0;
	}

	Send_Data_RS485(buf,body->size);
		
	sub_rs485_time_out_1.set = 1;
	sub_rs485_time_out_1.count = 0;

	
	RS485_busy_1 = 1;
	
	return 1;

}

void Send_Sub_BMS_1_CMD(void)
{
	
	if(RS485_busy_1)
		return;
	
	Send_Sub_BMS_CMD_1();
}




void Check_Sub_BMS_1(void)
{
	if(SUB_BMS_1_DEC())
	{
		if(sub_bms_info_1.rs485_connect == 0)
		{
			sub_bms_info_1.rs485_connect = 1;
			sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;
			
	
		}
	}
	else
	{
		if(sub_bms_info_1.rs485_connect)
		{
			// memset(&sub_bms_info_1,0x00,sizeof(sub_bms_info_1));
			memset(&sub_rs485_time_out_1,0x00,sizeof(sub_rs485_time_out_1));
			RS485_busy_1 = 0;

			//sub_bms_1_lt_state = SUB_BMS_DISC_NO485;
			sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;


			if(cb_operate_state == CB_BAT1)
			{
				//Power_On_Normal(0);
			}
		}
	}

		
}



int8_t Handle_RS485_1_Data(void)
{
	uint16_t len = Get_RS485_Data(app_rs485_buf,sizeof(app_rs485_buf));
	if(len != app_rs485_buf[0])
	{
		if(memcmp(app_rs485_buf,"zhengjiceshi",12) == 0 && ht_mode == 0)
		{
			Writer_HT_Flash(1);
			__set_FAULTMASK(1);
			NVIC_SystemReset();
		}
		//idra-test-start
		RS485_Print(0x22,app_rs485_buf,len);
		//idra-test-end
		return 0;
	}

	if((app_rs485_buf[0] > sizeof(COMMAND_BODY)))
	{

		if(!Handle_Sub_BMS_CMD_1(app_rs485_buf))
		{
			//idra-test-start
			RS485_Print(0x22,app_rs485_buf,len);
			//idra-test-end
			return 0;
		}
	}

	return 1;
	
}

void Sub_BMS_1_Initial(void)
{
	Usart1_Initial();

	memset(&sub_rs485_time_out_1,0x00,sizeof(sub_rs485_time_out_1));
	memset(&sub_bms_info_1,0x00,sizeof(sub_bms_info_1));
	send_delay.set = 1;
	send_delay.count = 0;

	sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;
}

void  Sub_BMS_1_lt_State(void)
{
	switch(sub_bms_info_1.conn_state)
	{
		case SUB_BMS_INVALID_STATUS:
			break;
		case SUB_BMS_DISC_NO485:
			break;
		case SUB_BMS_DISC_HV485:
			break;
		case SUB_BMS_CONT_HV485:
			break;
		case SUB_BMS_CONT_NO485:
			break;
	}
	
}

static shark_battery_exit_t shark_battery_is_normal_raw(SUB_BMS_INFO *info)
{
	uint16_t 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 (IS_CHARGER_ON()) {
		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) {
		return SHARK_BATT_EXIT_ERROR;
	}

	if (info->conn_state != SUB_BMS_CONT_HV485) {
		if (shark_bms_check_xl() == 0 || info->state == SHARK_BATT_STATE_IDLE) {
			return SHARK_BATT_EXIT_485;
		}
	}

	if (update_bat.ub_bat != UPDATE_BAT_NO) {
		if (update_bat.ub_bat == UPDATE_BAT_1 && info == &sub_bms_info_1) {
			return SHARK_BATT_EXIT_UPGRADE;
		}

		if (update_bat.ub_bat == UPDATE_BAT_2 && info == &sub_bms_info_2) {
			return SHARK_BATT_EXIT_UPGRADE;
		}
	}

	return SHARK_BATT_EXIT_SUCCESS;
}

shark_battery_exit_t shark_battery_is_normal(SUB_BMS_INFO *info)
{
	info->exit_code = shark_battery_is_normal_raw(info);
	return info->exit_code;
}

shark_bool shark_battery_is_power_on(SUB_BMS_INFO *info)
{
	if ((info->packet_common.bms_status & BMS_POWER_FULL) != BMS_POWER_FULL) {
		return shark_false;
	}

	return shark_true;
}

shark_bool shark_battery_is_normal_power_on(SUB_BMS_INFO *info)
{
	if (shark_battery_is_normal(info) == SHARK_BATT_EXIT_SUCCESS) {
		if (shark_battery_is_power_on(info)) {
			return shark_true;
		}

		info->exit_code = SHARK_BATT_EXIT_POWER;
	}

	return shark_false;
}

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

int8_t Operate_Sub_BMS_1_CD(uint8_t on)
{
	uint8_t cd_fet,rtn;
	uint16_t i,timeout = RS485_COM_TIMEOUT;
	
	sub_bms_info_1.sub_bms_cmd.operate = OP_OPEN_FET;
	switch(on)
	{
		case 1:
			cd_fet = 0x03;
			break;
		case 0:
			cd_fet = 0x00;
			break;
		case 2:
			cd_fet = 0x04;
			timeout = 2000;
			break;
		default:
			cd_fet = 0x00;
			break;
			
	}
	sub_bms_info_1.sub_bms_cmd.param = cd_fet;
	
	g_event &= ~RS485_RECEIVE_END_EVENT;
	Send_Sub_BMS_CMD_1();

	cd_fet <<= 1;
	rtn = 0;
	for(i = 0; i < timeout/10;i++)
	{
		delay_1ms(10);
		if(g_event & RS485_RECEIVE_END_EVENT)
		{
			g_event &= ~RS485_RECEIVE_END_EVENT;
			Handle_RS485_1_Data();
			if(on != 2)
			{
				if((sub_bms_info_1.packet_common.bms_status & cd_fet) == cd_fet)
				{
					rtn = 1;
				}
			}
			else
			{
				rtn = 1;
			}
			break;
		}
		
	}
	
	return rtn;
	
}

int8_t Operate_Sub_BMS_PING(uint32_t delay)
{
	uint64_t time = shark_get_time() + delay;
	uint8_t mask = 0;

	while (sub_bms_info_1.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_1) {
		if (time < shark_get_time_safe()) {
			println("bat1 busy");
			return 0;
		}
	}

	while (sub_bms_info_2.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_2) {
		if (time < shark_get_time_safe()) {
			println("bat2 busy");
			return 0;
		}
	}

	sub_bms_info_1.conn_state = SUB_BMS_DISC_HV485;
	sub_bms_info_1.sub_bms_cmd.operate = OP_READ_INFO;
	g_event &= ~RS485_RECEIVE_END_EVENT;

	sub_bms_info_2.conn_state = SUB_BMS_DISC_HV485;
	sub_bms_info_2.sub_bms_cmd.operate = OP_READ_INFO;
	g_event &= ~RS485_RECEIVE_END_EVENT;

	Send_Sub_BMS_CMD_1();
	Send_Sub_BMS_CMD_2();

	while (time > shark_get_time_safe() && mask != 3) {
		if(g_event & RS485_RECEIVE_END_EVENT) {
			g_event &= ~RS485_RECEIVE_END_EVENT;
			Handle_RS485_1_Data();
			mask |= 1;
			println("mask1: %d", mask);
		}

		if (g_event & RS485_2_RECEIVE_END_EVENT) {
			g_event &= ~RS485_2_RECEIVE_END_EVENT;
			Handle_RS485_2_Data();
			mask |= 2;
			println("mask2: %d", mask);
		}
	}

	println("mask: %d", mask);

	return 1;
}

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);
}

static shark_bool shark_battery_check_power(SUB_BMS_INFO *info, shark_battery_power_t power)
{
	if (info->conn_state != SUB_BMS_CONT_HV485) {
		return shark_false;
	}

	switch (power) {
	case SHARK_BATT_POWER_SMALL:
		if ((info->packet_common.bms_status & BMS_POWER_ALL) != BMS_POWER_SMALL) {
			return shark_false;
		} else {
			break;
		}

	case SHARK_BATT_POWER_FULL:
		if ((info->packet_common.bms_status & BMS_POWER_ALL) != BMS_POWER_FULL) {
			return shark_false;
		} else {
			break;
		}

	default:
		if ((info->packet_common.bms_status & BMS_POWER_ALL) != 0) {
			return shark_false;
		} else {
			break;
		}
	}

	return shark_true;
}

u8 shark_battery_set_power(shark_battery_power_t power1, shark_battery_power_t power2, u8 mask)
{
	u64 time = shark_get_time() + 200;
	u8 success = 0;
	u8 times;

	while (sub_bms_info_1.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_1) {
		if (time < shark_get_time_safe()) {
			break;
		}
	}

	while (sub_bms_info_2.conn_state == SUB_BMS_CONT_HV485 && RS485_busy_2) {
		if (time < shark_get_time_safe()) {
			break;
		}
	}

	sub_bms_info_1.conn_state = SUB_BMS_DISC_HV485;
	sub_bms_info_2.conn_state = SUB_BMS_DISC_HV485;

	for (times = 0; times < 3; times++) {
		shark_battery_set_power_param(&sub_bms_info_1, power1);
		g_event &= ~RS485_RECEIVE_END_EVENT;

		shark_battery_set_power_param(&sub_bms_info_2, power2);
		g_event &= ~RS485_2_RECEIVE_END_EVENT;

		Send_Sub_BMS_CMD_1();
		Send_Sub_BMS_CMD_2();

		time = shark_get_time() + 200;

		while (time > shark_get_time_safe()) {
			if(g_event & RS485_RECEIVE_END_EVENT) {
				g_event &= ~RS485_RECEIVE_END_EVENT;
				Handle_RS485_1_Data();

				if (shark_battery_check_power(&sub_bms_info_1, power1)) {
					success |= 1;
				}
			}

			if (g_event & RS485_2_RECEIVE_END_EVENT) {
				g_event &= ~RS485_2_RECEIVE_END_EVENT;
				Handle_RS485_2_Data();

				if (shark_battery_check_power(&sub_bms_info_2, power2)) {
					success |= 2;
				}
			}

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

	return success;
}

int8_t Update_Sub_BMS_1_Software(uint8_t step)
{
	uint8_t rtn;
	uint16_t i,timeout = RS485_COM_UPDATE_TIMEOUT;
	
	
	switch(step)
	{
		case UPDATE_STEP_NO:
			return 0;
		case UPDATE_STEP_REQ:
			sub_bms_info_1.sub_bms_cmd.operate = OP_WRITE_SN;
			sub_bms_info_1.sub_bms_cmd.param = 0x03;
			break;
		case UPDATE_STEP_DATA:
			sub_bms_info_1.sub_bms_cmd.operate = OP_WRITE_SN;
			sub_bms_info_1.sub_bms_cmd.param = 0x04;
			break;
		default:
			return 0;
			
	}
	
	g_event &= ~RS485_RECEIVE_END_EVENT;
	Send_Sub_BMS_CMD_1();

	rtn = 0;
	for(i = 0; i < timeout/10;i++)
	{
		delay_1ms(10);
		if(g_event & RS485_RECEIVE_END_EVENT)
		{
			g_event &= ~RS485_RECEIVE_END_EVENT;
			rtn = Handle_RS485_1_Data();
			
			break;
		}
		
	}
	
	return rtn;
	
}


uint8_t Sub_BMS_1_COM_Finish(void)
{
	return sub_bms_info_1.conn_state;
}





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;
}

uint8_t shark_bms_check_xl(void)
{
	return end_ctr_self_ss_new.xl_sta != 0 || XL_Dect() == RESET;
}

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

	println("fl: %d %d", mask, enable);

	if (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);
		}
	}
}

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);
	}
}

