#include "common.h"
#include "drv_usart.h"
#include "app_rs485_1.h"
#include "app.h"
#include "hardware_test.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_lt_state = SUB_BMS_INVALID_STATUS;

uint8_t sub_bms_1_connect = 0;

uint8_t cang_wei = CW_CHE_SHANG_NO_CHARGER;

uint16_t bms_1_work_status = 0;

uint8_t bms_1_test_define_error = 0;

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_1_lt_state = SUB_BMS_CONT_NO485;
	}
	else
	{
		sub_bms_1_lt_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_1_lt_state = SUB_BMS_CONT_HV485;
		}
		else
		{
			sub_bms_1_lt_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_1_lt_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;
	}
	
}

uint8_t Is_Sub_BMS_1_Normal(void)
{
	uint16_t work_sta = sub_bms_info_1.packet_common.work_status;

	work_sta &= ~ST_CHRG_CUR;
	work_sta &= ~ST_DISCHRG_CUR;
	work_sta &= ~ST_OVRDISCHRG_CUR;
	work_sta &= ~ST_SMALL_CURRENT_OVER;
	if(IS_CHARGER_ON())
	//if(IS_CHARGE_IN())
	{
		work_sta &= ~ST_OVRDISCHRG_VOL;
		work_sta &= ~ST_PDOWN;
		work_sta &= ~ST_UDR_TEMPE_DISCHRG;
		work_sta &= ~ST_OVR_TEMPE_DISCHRG;
	}
	else
	{
		work_sta &= ~ST_OVRCHRG_VOL;
		work_sta &= ~ST_OVR_TEMPE_CHRG;
		work_sta &= ~ST_UDR_TEMPE_CHRG;
	}

	
	do
	{
		/*if(cb_operate_state != CB_BAT1_BAT2_PARRALLEL && cb_operate_state != CB_BAT_NO  )
		{
			if((BAT1_IS_OPEN() == 0))
				break;
		}*/

		if(update_bat.ub_bat == UPDATE_BAT_1)
			break;
		
		if(define_bms_1_error != D_BMS_ERROR_NO)
			break;
		
		if((cb_operate_state == CB_BAT1_BAT2_SERIES)&&(BAT1_IS_OPEN() == 0))
				break;
		if(Is_Soak())
			break;
		
		if(SUB_BMS_1_DEC() == 0)
			break;
		
		if(work_sta)
		{
			bms_1_work_status = sub_bms_info_1.packet_common.work_status;
			break;
		}

		if(sub_bms_1_lt_state != SUB_BMS_CONT_HV485)
			break;

		if(bms_1_test_define_error != 0)
			break;
		
		return 1;
	}while(0);

	return 0;
	
}

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

