/* 
* This document is used to 5.8G keypad firmware update.
*  main process: a, sdk send cmd  
*
*	 5.8G transfer speed faster then 2.4G！ 
* we can use other methods(protocol) to implement 5.8Gkeypad firmware upgrade;
*/


#include "base_core_user.h"
#include "platform_interface.h"
#include "function.h"
#include "string.h"

#ifdef A5130

#define 	UPDATE_KP_CNT		30


#define 	C_STEP_INIT				0
#define 	C_STEP_NOTICE_1		1	
#define 	C_STEP_NOTICE_0		2	
#define 	C_STEP_NOTICE_RE	22
#define 	C_STEP_NOTICE_EXCUTE 11
#define 	C_STEP_DATA			4




struct update_STR{
		//don't change next variable sequence!!!!
		unsigned char Hver;	//byte[8]
		unsigned char Sver[3];
		unsigned char crc[2];
		unsigned char file_len[4];
		//sequence limit over
		
		//data info
		unsigned char downID;		//section1
		unsigned char packH;			//section2
		unsigned char packL;			//section3
		unsigned char firmware[8][34]; //keypad firmware data 
	
		void (*send_function)(const unsigned char *,unsigned char id);
		volatile unsigned char control_step;
		unsigned char re_send_times;						//重发次数		
		unsigned char valid_cnt;
		unsigned char current_kp;					
		unsigned char start_end_flag;
	
		/* 为了便于内存复制，没有使用如下键盘结构体，而是用独立数组
		struct kp_STR{
			unsigned char sn[4];
			unsigned char result;	
		};
		struct kp_STR kp[UPDATE_KP_CNT];
		*/
		unsigned char sn_list[UPDATE_KP_CNT][4];
		unsigned char result[UPDATE_KP_CNT];
		
		unsigned char special_sn_list[UPDATE_KP_CNT][4];
		unsigned char special_mode_flag;
		unsigned char special_sn_count;

		unsigned short sdk_link_timeout;
		unsigned char  check_sdk_link_flag;
};
struct update_STR update;


/*
2019.12.04 实测 delay(500) =500us;
环境：主频168MHz,关闭中断,IO取反用示波器测试!!	
由于GPIO无法响应 delayus(1)，所以实际测试delay(500) =500us	*/
void upate_delay_us( unsigned short time )
{
    unsigned short i = 0;
    while( time-- ){
			i = 30; 
			while( i-- ) ;
    }
}

/* 2020.12.14 增加键盘升级过程中sdk断开而基站无法自动退出到正常模式的问题；
* 考虑到升级过程中不同阶段，sdk通信频率也不一样;简单的定时处理可能会误判断;
*/
void set_sdk_link_flag(unsigned char stat)
{
	update.check_sdk_link_flag = stat;
}

unsigned char get_sdk_link_flag(void)
{
	return update.check_sdk_link_flag;
}

//called by BASE send ack to sdk;
void set_sdk_link_timeout(unsigned short time)	//time* 2.5ms //
{
	update.sdk_link_timeout = time;
	set_sdk_link_flag(1);
}


/*
* called by 2.5ms loop
*/
unsigned char check_sdk_timeout(void)
{
	if( get_sdk_link_flag() ==0) return 0;

	if(update.sdk_link_timeout){
		update.sdk_link_timeout--;
	}
	else{
		if( base_core.get_send_beacon() ==0){ //turn on if the status is off;
			base_core.switch_send_beacon(1);							
			update.control_step =C_STEP_INIT;		
		}
	}

	return 0;
}






/*-------------------------- PC ---------------------
* base respond sdk command*/
static void update_ack_pc(const unsigned char *rx_pc)
{
		unsigned char tmp[64];
	set_sdk_link_timeout(200);			
		tmp[0] = (rx_pc[0]>64)?64:rx_pc[0];	
	
		memcpy(tmp+2,rx_pc+2,60);//	mem_cpy(rx_pc+2,tmp+2,60);	
		tmp[1] =0xE1;
		base_core.send_data_to_pc(tmp);
}

/* after acomplish communicate with keypad,
* base report status to SDK active;	*/
static void base_report_status(unsigned char status)
{
		unsigned char tmp[24];
		tmp[0] =24;
		tmp[1] =0xE1;
		tmp[2] =base_core.get_id();//get_base_id();	
		tmp[3] =22;
		tmp[4] =6;	
		tmp[5] =0;//packH
		tmp[6] =0;//packL
		tmp[7] =status;	//错误或者是通知/数据已经发送完了！ 		
		memset(tmp+8,0xff,6);//mem_set(tmp+8,6,0xff);					
	set_sdk_link_timeout(200);			
		base_core.send_data_to_pc(tmp);
}

/* after receive feedback from the keypad on the end signal,
* base call this function to report the keypad status actively to sdk;	*/
static void base_report_result(unsigned char status)
{
		unsigned char i,tmp[1024];
		tmp[0] =158;
		tmp[1] =0xE1;
		tmp[2] =base_core.get_id();//get_base_id();	
		tmp[3] =22;
		tmp[4] =6;	
		tmp[5] =0;//packH
		tmp[6] =0;//packL	
		tmp[7] =update.valid_cnt;
	
		for(i=0;i<update.valid_cnt;i++){
			memcpy(tmp+8+i*5,update.sn_list[i],4);//mem_cpy(update.sn_list[i],tmp+8+i*5,4);
			tmp[12+i*5] = update.result[i];
		}//for
	
		base_core.send_data_to_pc(tmp);//user__base_tx_to_pc_sub(tmp);
}


/*
* base process sdk cmd */
void update_kp_enter(const unsigned char *rx_pc)
{
	set_sdk_link_flag(0); //add by Gavin, turn off monitor SDK

	switch(rx_pc[4] ){
		
		case 1://-------enter or exit; 进入或退出下载
			update.special_mode_flag =rx_pc[5]; //广播模式还是指定SN模式
		
			if(rx_pc[7] ==1){//enter download 
				update.start_end_flag=1;
				if( (update.valid_cnt =base_core.get_5G8_keypad_sn_list(&update.sn_list[0][0])) >UPDATE_KP_CNT ){ //if( (update.valid_cnt =get_link_queue_sn(&update.sn_list[0][0])) >UPDATE_KP_CNT ){
					update.valid_cnt =UPDATE_KP_CNT;
				}																
				update.control_step =C_STEP_NOTICE_1;
			}
			else if(rx_pc[7] ==0){//exit download 				
				update.start_end_flag=0;
				update.control_step =C_STEP_NOTICE_0;
			}
			//update.special_mode_flag=0; //默认广播模式
			memset(update.result,0,UPDATE_KP_CNT);//mem_set(update.result,UPDATE_KP_CNT,0);//clear result record			
			memcpy(&update.Hver,rx_pc+8,10);	//mem_cpy(rx_pc+8,&update.Hver,10);		
			update_ack_pc(rx_pc);
			break;
	
		case 2://download id/sn list 下载id/sn表单 //add by 20191224
			if( (rx_pc[5]<=UPDATE_KP_CNT)&&(rx_pc[6]<3) ){
				unsigned char i;
				update.special_sn_count =rx_pc[5];
				for(i=0;i<10;i++){
					memcpy(update.special_sn_list[rx_pc[6]*10+i],rx_pc+7+i*4,4);//mem_cpy(rx_pc+7+i*4,update.special_sn_list[rx_pc[6]*10+i],4);
				}//for
			}				
			update_ack_pc(rx_pc);
			break;
		
		case 4://download keypad data 下载具体数据	
			update.downID =rx_pc[6];
			update.packH =rx_pc[7];
			update.packL =rx_pc[8];
			if(update.packL >=8) break;//error 防止数组溢出
			memcpy(update.firmware[update.packL],rx_pc+9,34);//mem_cpy(rx_pc+9,update.firmware[update.packL],34);			
			update_ack_pc(rx_pc);
						
			//test only
			if( update.packL>=7){
				//update.rx_256_count++; //test only
				update.control_step=C_STEP_DATA;
			}
			break;
	
		case 5://packet download finish,this time 本次数据下载完成		
			break;		
		case 6://PC confirm base report status 确认基站上报的状态			
			break;			
		default:
			break;
	}//switch		
}








/*---------------------------------- TX keypad -------------------------------------------------------------------
* broadcast SN three times; 	
*this format compatible with the normal voice communication
input : 要发送的键盘信息 */
static void broadcast_SN(const unsigned char *key_info)
{
	unsigned char tmp[64],i;	 
	unsigned short crc;
	memset(tmp,0,sizeof(tmp)/sizeof(unsigned char));//mem_set(tmp,sizeof(tmp)/sizeof(unsigned char),0);
	
	//3byte match code,1byte net id;
	tmp[0] =64;//32;
	base_core.get_match_code(tmp+1);		
	tmp[5] = 0x12;//0x11;//difference in normal voice
	
	for(i=0;i<10;i++){
		tmp[13+i*5] = key_info[0+i*4];
		tmp[14+i*5] = key_info[1+i*4];
		tmp[15+i*5] = key_info[2+i*4];
		tmp[16+i*5] = key_info[3+i*4];
		tmp[17+i*5] = 0x00;		
	}
		
	//第一次
	tmp[6] = 1;
	//crc =crc16(tmp+4,60);
//	tmp[62] = crc>>8;
//	tmp[63] = crc&0xff;	
	platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());//A5130_send_buf(tmp,64);
	upate_delay_us(50);
	//第二次
	tmp[6] = 2;
	//crc =crc16(tmp+4,60);
//	tmp[62] = crc>>8;
//	tmp[63] = crc&0xff;	
	platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());//A5130_send_buf(tmp,64);
	upate_delay_us(50);
	//第三次
	tmp[6] = 3;
	//crc =crc16(tmp+4,60);
//	tmp[62] = crc>>8;
//	tmp[63] = crc&0xff;	
	platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());//A5130_send_buf(tmp,64);		
}



/*
*broadcast the start/stop command to keypad, no SN id specified!
*input: 
//cmd -start or stop
*type -enter or exit ? 
*/
//static void broadcast_control_cmd(unsigned char start_exit,unsigned char *kp_sn)
static void broadcast_control_cmd(unsigned char start_exit)		
{
		unsigned char tmp[64+1];///20191226//tmp buffer+1 for the new keypad upgrade procotol,that longth is 64byte,but tmp[0] is used save length	
		unsigned char i;
	
		tmp[0] =64;
		base_core.get_match_code(tmp+1);//tmp1-4;			
		tmp[5] =0x40;	
		
//		tmp[6] =0x00;	 //broadcast 	
//		tmp[7] =0x00;		
//		mem_set(tmp+12,6,0x00); //6bytes
	
		tmp[8] =0x01;   //fix
		tmp[9] =0x1E;		//down type 30
		tmp[10] =0x00;			
		tmp[11] =start_exit;//DCMD  1-开始；0-退出		
		//见教育新版表决器协议0.91 -6.1	
		memcpy(tmp+18,&update.Hver,10);//mem_cpy(&update.Hver,tmp+18,10);

		tmp[31] =0x00;	 //CRC
		tmp[32] =0x00;
	
	
		switch(update.special_mode_flag){
			case 0:
				tmp[6] =0x00;	 //broadcast 	
				tmp[7] =0x00;		
				memset(tmp+12,0x00,6); //mem_set(tmp+12,6,0x00); //6bytes	
				platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());
				platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());
			
				break;
			
			case 1: //id?
				break;
			
			case 2://special sn
				tmp[6] =0xff;	 //spciel
				tmp[7] =0xff;	
			
				for(i=0;i<update.special_sn_count;){
						memcpy(tmp+33+(i%8)*4,update.special_sn_list[i],4);//mem_cpy(update.special_sn_list[i],tmp+33+(i%8)*4,4);
						i++;
						if( (i%8 ==0)||(i>=update.special_sn_count) ){
							platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());
							upate_delay_us(100);
						}
				}//for
						
				break;			
		}	//sw

		
//		platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());
//		platform.rf_5G8_load_send_data(tmp+1,64,base_core.get_mainRF_hard_id());	
}	


/* 
* broadcast 256bytes data to all keypad;
*/
static void broadcast_data256(unsigned short pkt_cnt)	
{
		unsigned char tmp[64];
		unsigned short i;
	
		tmp[0] =64;	
		base_core.get_match_code(tmp+1);//tmp1-4;
		tmp[5] =0x40;
		tmp[6] =0x00;//0xff;	 	//广播	
		tmp[7] =0x00;//0x01;			
		tmp[8] =0x02;		//广播下载数据
		tmp[9] =0x1E;		//down type
		tmp[10] =update.downID;			
		tmp[11] =update.packH;	//数据段
	
		for(i=0;i<8;i++){
			tmp[12] =i;			//数据片0-8			
			memcpy(tmp+13,update.firmware[i],34);//mem_cpy(update.firmware[i],tmp+13,34);
			base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id()); 
			upate_delay_us(200);//delay_us(200);//delay_us(500);
		}//for
}

/*
send 256byte: split 8times, 32bytes every send;
re-send 2times ;*/
static void broadcast_data256_2(unsigned short pkt_cnt)	
{
		unsigned char tmp[64];
		unsigned short i;
	
		tmp[0] =64;	
		base_core.get_match_code(tmp+1);//tmp1-4;
		tmp[5] =0x40;
		tmp[6] =0x00;//0xff;	 	//广播	
		tmp[7] =0x00;//0x01;			
		tmp[8] =0x02;		//广播下载数据
		tmp[9] =0x1E;		//down type
		tmp[10] =update.downID;			
		tmp[11] =update.packH;	//数据段
	
		for(i=0;i<8;i++){
			tmp[12] =i;			//数据片0-8			
			memcpy(tmp+13,update.firmware[i],34);//mem_cpy(update.firmware[i],tmp+13,34);
			base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id()); 
			upate_delay_us(200);//delay_us(200);
			base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id()); 
			upate_delay_us(200);//delay_us(200);
		}//for
}


/*
send start info and normal poll keypad
* add "unsigned char id" for compatibility the platform.rf_5G8_send_multi_frame() function intput parameter!
*/
static void broadcast_start_cmd(const unsigned char *sn,unsigned char id)
{
	broadcast_control_cmd(1); //enter download 
	broadcast_SN(sn);
}

/*
send stop info and normal poll keypad 
* add "unsigned char id" for compatibility the platform.rf_5G8_send_multi_frame() function intput parameter!
*/
static void broadcast_end_cmd(const unsigned char *sn,unsigned char id)
{
	broadcast_control_cmd(0); //exit download 
	broadcast_SN(sn);
}


//--------------- Rx ack of keypad -----------------------------
/*
rcv keypad ack data; data type is 0xC0	
called by 0xC0 */
unsigned char save_keypad_ack_data(const unsigned char *rx_kp)
{
	unsigned char i;	
	
////	update.test_flag =1;
//	//查找收到的键盘在sn list中的位置	
//	for(i=0;i<update.valid_cnt;i++){
//		if( mem_compare( update.sn_list[i],&rx_kp[10],4) )
//			break;
//	}//for
//	if( i>=update.valid_cnt) return 0;
//	
//	//b, record keypad result;
//	update.result[i] = rx_kp[14];
	
	
		//接收键盘的反馈
		//if( update.control_step !=C_STEP_NOTICE_EXCUTE ) return 0;
	
	
		if(update.start_end_flag==0){
				for(i=0;i<update.valid_cnt;i++){
					if( memcmp( update.sn_list[i],&rx_kp[10],4) ==0){//if( mem_compare( update.sn_list[i],&rx_kp[10],4) ){
						update.result[i] = rx_kp[14];
						break;
					}
				}//for
		}
		else{//发送完数据后，键盘对基站询问升级状态的反馈;
			
			
		}
	
	
	
	return 1;
}



/*
minimum send unitl;
load and send data,then update.current_kp pointer next ten keypad if exist!
return:1--表单中还有sn
0--没有sn了;
*/
static unsigned char update_process_sub(void )	
{
	if(update.current_kp>=UPDATE_KP_CNT) return 0;
	
	platform.rf_5G8_send_multi_frame(update.send_function, &update.sn_list[update.current_kp][0], base_core.get_mainRF_hard_id());	
	
	if( update.current_kp+10 <update.valid_cnt ){
		update.current_kp+=10;
		return 1;
	}
	else 
		return 0;
}



/*------------------------------------
upgrade keypad  firmware;Process:
a, notice keypad start/stop cmd,the actual execution in update_process_sub();
b, send 256bytes 
called by base send normal beacon( 2.5ms*13 =32.5ms) 
base stop send beacon while upgrade keypad firmware;
*/
unsigned char update_kp_progress(void)
{		
	
		switch(update.control_step){
			case C_STEP_INIT:
				break;
			
			

			
			case C_STEP_NOTICE_1:
			case C_STEP_NOTICE_0://通知退出 				
				if(update.start_end_flag==1){
					base_core.switch_send_beacon(0);
					update.send_function =broadcast_start_cmd;
				}
				else{					
					update.send_function =broadcast_end_cmd;
				}				
				update.re_send_times=30;//重传次数
				//特别注意，此处没有 break;
				
			case C_STEP_NOTICE_RE:	
				update.current_kp=0;
				if(update.re_send_times>0){//重复次数还没到
					update.re_send_times--;
					update.control_step =C_STEP_NOTICE_EXCUTE;
				}
				else{
					//---------------重复次数到了
					if(update.start_end_flag){
						//此处可以计算 有多少键盘对开始升级信号做了回应
						
						platform.delay_ms(500);
						base_report_status(1);
						update.control_step =C_STEP_INIT;												
					}
					else{
						//此处可以看到键盘反馈其升级结果！
						
						base_report_result(1);
						base_core.switch_send_beacon(1);	//turn on send beacon						
						update.control_step =C_STEP_INIT;
					}
					//--------------				
					break;
				}
				//特别注意，此处没有 break;
			
			case C_STEP_NOTICE_EXCUTE://polling min send modual ,interval is 32.5ms
				update.control_step =(update_process_sub())?C_STEP_NOTICE_EXCUTE:C_STEP_NOTICE_RE;
				break;
													
				// type 2:
			case C_STEP_DATA://发送256字节数据
				broadcast_data256(1);
				broadcast_data256(1);	
				broadcast_data256(1);	
				broadcast_data256_2(1);
				platform.delay_ms(8);//一页发完了，延时留给键盘写flash的时间！！
			
				base_report_status(1);
				update.control_step =C_STEP_INIT; 
				break;
					
			default:break;
		}//switch

		//2020.12.14 add by Gavin
		check_sdk_timeout();

		return 1;	
}


/*
* 为了兼容接口而增加，5.8G键盘固件升级没有用!!!
*/
unsigned char update_get_status(void)
{
	
	return 0;
}



/*
* 检测基站和sdk的连接状态;
*解决关闭sdk后，基站和键盘无法退出升级状态的问题;
*called by 20ms 
*/
unsigned short update_sdk_connect_cnt;

void update_monitor_sdk_connect(void)
{
	if( !update_get_status() ) return;
	if( base_core.get_sdk_connect_status() )
		update_sdk_connect_cnt=0;
	else{		
//		if( (++update_sdk_connect_cnt>= 50*4)&&
//			(update.step!=_STEP_NOTICE_ABORT )&& (update.step!=_STEP_NOTICE_STOP_PROCESS )
//		){
//			update.type_start_stop_data=0;// stop cmd
//			update.step =	_STEP_NOTICE_ABORT;	
//		}			
	}
}







#endif 




