
#include "base_core_user.h"
#include "function.h"
#include "string.h"
#include "platform_interface.h"
/*
* see base protocol V0.9.5 section5.4 base download multi-packets
* 常规2.4 慢速的键盘固件升级方式; 还有5.8G快速键盘固件升级模式。
*
*/


#ifndef A5130

#if (!UPDATE_KP_2)
#define 	UPDATE_KP_CNT		100//80 //基站支持一次最多升级的键盘数

struct update_STR{

		//don't change next variable sequence!!!!
		unsigned char Hver;
		unsigned char Sver[3];
		unsigned char crc[2];
		unsigned char file_len[4];
		//sequence limit over
	
		//from pc	
		volatile unsigned char start_end_flag;
	
		unsigned char downID;		//section1
		unsigned char packH;			//section2
		unsigned char packL;			//section3
		unsigned char pack_cur;	//当前数据包0-15
		unsigned char data[16][18];
	
		volatile unsigned char step;
//		volatile unsigned short OKBITS;
		unsigned short okbits;
		volatile unsigned char wait_timer;			//等待键盘回复的计时器
		unsigned char re_send_times;						//重发次数
		unsigned char re_send_data_times;
		
		volatile unsigned char pc_confirm_flag; 				//sdk确认出错键盘标志	
		unsigned char pc_confirm_type;
		
		volatile unsigned char type_start_stop_data;		//0,1 -开始/结束下载;2-数据下载
		
		unsigned char idsn_mode; 	//id or sn			
		unsigned char idsn[UPDATE_KP_CNT][6]; 	//store id/sn of kp
		unsigned char valid[UPDATE_KP_CNT];		//0-valid; 1-invalid
		unsigned char valid_cnt;
		
		unsigned char kp_counter;						//升级键盘的个数
		volatile unsigned char kp_cur;			//当前键盘序号		
		
		//rx keypad ack
		volatile unsigned char keypad_ack_flag;	//键盘回应基站标志
		unsigned char keypad_ack_buf[64];
		
		void (*send_inquire_to_keypad)(unsigned char);
		unsigned char (*process_keypad_ack)(void);
		
		unsigned char send_data_slice_interval;
		unsigned char broadcast_data_re_send_flag;
		
		//debug only
		unsigned int rx_det_err;
		unsigned int rx_det_err2;
};

struct update_STR update;
static void update_report_info_to_pc(unsigned char kp_seq,unsigned char status);





//------------ debug start ----------------------------------------------
//	#define 	MAX_PKT		10//0
//	#define 	DBG_UPDATE

#ifdef DBG_UPDATE
struct debug_update_STR{

	//start
	unsigned short start__ask_kp_cnt[UPDATE_KP_CNT];
	unsigned short start__kp_ack_cnt[UPDATE_KP_CNT];
	
	//stop
	unsigned short stop__ask_kp_cnt[UPDATE_KP_CNT];
//	unsigned short start__kp_ack_cnt;	
	
	//data 
	unsigned short data__re_send_times[MAX_PKT];
	unsigned short data__ask_kp_cnt[UPDATE_KP_CNT][MAX_PKT];
	unsigned short data__kp_ack_cnt[UPDATE_KP_CNT][MAX_PKT];	
};

struct debug_update_STR debug_update;
#endif 

/*
每次开始升级清理所有debug参数
*/
static void _debug__updata_init(void)
{
	#ifdef DBG_UPDATE
	unsigned short i,j;
	for(i=0;i<UPDATE_KP_CNT;i++){
		debug_update.start__ask_kp_cnt[i]=0;
		debug_update.start__kp_ack_cnt[i]=0;
		debug_update.stop__ask_kp_cnt[i]=0;
	}//for

	for(i=0;i<MAX_PKT;i++){
		debug_update.data__re_send_times[i]=0;
	}//for	

	for(i=0;i<UPDATE_KP_CNT;i++){
		for(j=0;j<MAX_PKT;j++){
			debug_update.data__ask_kp_cnt[i][j]=0;
			debug_update.data__kp_ack_cnt[i][j]=0;
		}//for
	}//for
	#endif
}
	






//------------------------------------------------
//对某个键盘发送启动信号的次数
static void _debug__start__ask_kp_cnt(unsigned char sn)
{
	#ifdef DBG_UPDATE
	if(sn>=UPDATE_KP_CNT) return;
	debug_update.start__ask_kp_cnt[sn]++;
	#endif
}

//对某个键盘,收到对启动信号的回应的次数
static void _debug__start__kp_ack_cnt(unsigned char sn)
{
#ifdef DBG_UPDATE	
	if(sn>=UPDATE_KP_CNT) return;
	debug_update.start__kp_ack_cnt[sn]++;
	#endif
}

//----------------------------------------------------
//对某个键盘发送 停止信号的次数
static void _debug__stop__ask_kp_cnt(unsigned char sn)
{
	#ifdef DBG_UPDATE
	if(sn>=UPDATE_KP_CNT) return;
	debug_update.stop__ask_kp_cnt[sn]++;
	#endif
}

//------------------ data ---------------------------------
//某个数据包 重发的次数
static void _debug__data__re_send_times(void)
{
	#ifdef DBG_UPDATE
	debug_update.data__re_send_times[update.packH]++;
	#endif
}

//某个键盘的某个数据包 询问次数 
static void _debug__data__ask_kp_cnt(unsigned char sn)
{
	#ifdef DBG_UPDATE
	if(update.packH>=MAX_PKT) return;
	if(sn>=UPDATE_KP_CNT) return;
	debug_update.data__ask_kp_cnt[sn][update.packH]++;
	#endif
}


//某个键盘的某个数据包 询问次数 
static void _debug__data__kp_ack_cnt(unsigned char sn)
{
	#ifdef DBG_UPDATE
	if(update.packH>=MAX_PKT) return;
	if(sn>=UPDATE_KP_CNT) return;
	debug_update.data__kp_ack_cnt[sn][update.packH]++;
	#endif 
}


//--------------------- debug end -----------------------------


//init
#define 	_STEP_INIT0											0x00

//start stop
#define 	_STEP_NOTICE_START							0x10
#define 	_STEP_NOTICE_ABORT							0x11
#define 	_STEP_NOTICE_FINISH							0x12
#define 	_STEP_NOTICE_STOP_PROCESS				0x13

//data 
#define 	_STEP_BROADCAST_DATA_INIT				0x20
#define 	_STEP_BROADCAST_DATA						0x21
#define 	_STEP_BROADCAST_DATA_RE 				0x22
//#define 	_STEP_BROADCAST_DATA_RE_SENDING	0x23

//report pc
#define 	_STEP_KEYPAD_NO_ACK_ERROR				0x0a
#define 	_STEP_WAIT_PC_CONFIRM_ERROR			0x0b
#define 	_STEP_THIS_PKT_FINISH						0x0c
#define 	_STEP_WAIT_PC_CONFIRM_FINISH		0x0d

//common
#define 	_STEP_ASK_KEYPAD_CONTINUE				0xc0
#define 	_STEP_ASK_KEYPAD_INIT						0xc1
#define 	_STEP_ASK_KEYPAD 								0xc2
#define 	_STEP_WAIT_KEYPAD_ACK 					0xc3


/*
* 
*/
#if  BASE_TYPE == EVS200	
	#define 	WAITFOR_KEYPAD_ACK_CYCLE		30//12	//等待每个键盘回复的周期数2.5ms/cycle
	#define 	ASK_KP_TIMES								50//30  //每个键盘每次通信最大询问键盘的次数
	#define		UPDATE_DATA_RE_SEND_TIMES		50//30	//每包键盘升级数据最多重发次数
	#define 	SEND_UPDATE_DATA_INTERVEL		4//6//5		//发送每片数据包的时间间隔 2.5ms 
#else 
	//沿用EA3100 
	#define 	WAITFOR_KEYPAD_ACK_CYCLE		14//10	//等待每个键盘回复的周期数2.5ms/cycle
	#define 	ASK_KP_TIMES					50//40  //每个键盘每次通信最大询问键盘的次数
	#define		UPDATE_DATA_RE_SEND_TIMES		50//40	//每包键盘升级数据最多重发次数
	#define 	SEND_UPDATE_DATA_INTERVEL		6//4		//发送每片数据包的时间间隔 2.5ms 
#endif

/*
通知键盘进入/退出 固件升级模式
输入：进入还是退出，b，要发送的键盘id/sn的数组下标
input: enter/exit, array of offset;
*/
static void notice_kp_enter_exit_update(unsigned char kp_seq)	
{
		unsigned char tmp[33];	
	
		tmp[0] =0x20;
		base_core.get_match_code(tmp+1);//tmp1-4;			
		tmp[5] =0x40;
		if(update.idsn_mode == 1 ){ //see base protocol 5.4		
			tmp[6] =update.idsn[kp_seq][0];	 	//id H	
			tmp[7] =update.idsn[kp_seq][1];		//id L	
			memset(tmp+12,0,6);//mem_set(tmp+12,6,0x00);
		}
		else{
			tmp[6] =0xff;	 	//id H	
			tmp[7] =0xff;		//id L
			memcpy(tmp+12,update.idsn[kp_seq],6);//mem_cpy(update.idsn[kp_seq],tmp+12,6);			
		}	
		tmp[8] =0x01;   //进入下载
		tmp[9] =0x1E;		//down type 30
		tmp[10] =0x00;			
		tmp[11] =update.type_start_stop_data;//  enter_exit;//DCMD  1-开始；0-退出		
		//见教育新版表决器协议0.91 -6.1	
		memcpy(tmp+18,&update.Hver,10);//mem_cpy(&update.Hver,tmp+18,10);		
//operation_debug_io(3);
		base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id());	

		//test only
		if( update.type_start_stop_data)
			_debug__start__ask_kp_cnt(update.idsn[kp_seq][5]);
		else
			_debug__stop__ask_kp_cnt(update.idsn[kp_seq][5]);
}	


/*
基站广播数据给所有键盘
input: 数据数组下标 0-15
*/
static void broadcast_update_data(unsigned char data_seq)	
{
		unsigned char tmp[33];	

		tmp[0] =0x1E;	
		base_core.get_match_code(tmp+1);//tmp1-4;
		tmp[5] =0x40;
		tmp[6] =0xff;	 	//广播	
		tmp[7] =0x01;			
		tmp[8] =0x02;		//广播下载数据
		tmp[9] =0x1E;		//down type
		tmp[10] =update.downID;			
		tmp[11] =update.packH;	//数据段	
		tmp[12] =data_seq;			//数据片0-15
		memcpy(tmp+13,update.data[data_seq],18);//mem_cpy(update.data[data_seq],tmp+13,18);
//operation_debug_io(6);	//	
		base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id());	
}	


/*
基站询问键盘是否收到升级数据
输入：键盘id/sn的数组下标
*/
static void ask_keypad(unsigned char kp_seq)	
{
		unsigned char tmp[33];	

		tmp[0] =0x1E;
	  base_core.get_match_code(tmp+1);//tmp1-4;
		tmp[5] =0x40;	
		tmp[8] =0x03;		//询问状态
		tmp[9] =0x1E;		//down type
		tmp[10] =update.downID;			
		tmp[11] =update.packH;		//数据段	
			
		if(update.idsn_mode == 1 ){ //see base protocol 5.4		
			tmp[6] =update.idsn[kp_seq][0];	 	//id H	
			tmp[7] =update.idsn[kp_seq][1];		//id L	
memset(tmp+12,0,6);//			mem_set(tmp+12,6,0x00);		
		}
		else{
			tmp[6] =0xff;	 	//id H	
			tmp[7] =0xff;		//id L
			memcpy(tmp+12,update.idsn[kp_seq],6);//mem_cpy(update.idsn[kp_seq],tmp+12,6);				
		}
	
		base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id());

		//test only
		_debug__data__ask_kp_cnt( update.idsn[kp_seq][5]);	
		
}

/*
保存键盘的回应数据 
called by 基站处理键盘转发给pc的数据处理函数
return 1-有键盘回
*/
unsigned char save_keypad_ack_data(const unsigned char *rxkp)
{
		//只有在升级键盘固件模式下才有效；区别常规的转发数据，
		if( update.start_end_flag &&(rxkp[1]==0xC0)&& ((rxkp[4]==0x01)||(rxkp[4]==0x03)) ){
						
//			if( (rxkp[4]==0x03)&&(rxkp[7] != update.packH) ){
//				update.rx_det_err++; //debug only
//				return 0;
//			}
			
			memcpy(update.keypad_ack_buf,rxkp,rxkp[0]);	//copy keypad ack data
			update.keypad_ack_flag=1;

			//-------------------------						
				//test only			
				if(update.type_start_stop_data==2){//data 
					_debug__data__kp_ack_cnt(update.keypad_ack_buf[15]);
				}
				else if(update.type_start_stop_data==1){

					_debug__start__kp_ack_cnt(update.keypad_ack_buf[13]);
				}
				else{		
				}
			//-----------------
			
			return 1;
		}	
		else{
			update.rx_det_err2++; //debug only
			return 0;
		}
}




/*
检测是否收到指定键盘的ack
收到的键盘的回应，并且id/sn正确 return 1 */
static unsigned char check_keypad_ack_idsn(unsigned char type)
{	
	unsigned char i;
	
	if(!update.keypad_ack_flag) return 0;
	update.keypad_ack_flag =0;

		//广播开始进入下载时和后面下载数据时，键盘返回数据中 SN的位置是不一样的； id的位置固定在byte2
		if(type==1)	i=8;
		else 
			i=10;
		
		switch(update.idsn_mode){
			case 1: //id mode
				if( memcmp(update.idsn[update.kp_cur],update.keypad_ack_buf+2,2)==0 )	
					return 1;	
				break;
			case 2: //4byte SN
				if( memcmp(update.idsn[update.kp_cur]+2,update.keypad_ack_buf+2+i,4)==0 )	
					return 1;	//后4byte SN
				else
				break;		
			case 3:	//6byte SN
				if( memcmp(update.idsn[update.kp_cur],update.keypad_ack_buf+i,6)==0 )	
					return 1;	
				break;
			
			default:break;
		}//sw
	
	return 0;		
}


/*
获取更新状态
 0- 没有进入更新模式
*/
unsigned char update_get_status(void)
{
	return update.start_end_flag;
}


//-------------------------------- 与pc 之间的通信 -----------------------------------------------
/*
基站发送升级过程中的状态给PC
*/
static void update_report_info_to_pc(unsigned char kp_seq,unsigned char status)
{
		unsigned char tmp[32];
		if(kp_seq>= UPDATE_KP_CNT) return;//error 防止数组溢出
		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;	//错误或者是通知/数据已经发送完了！ 		
		if(tmp[7]==1)//报告完成状态时，不关注id/SN，便于调试理解
memset(tmp+8,0xff,6);//			mem_set(tmp+8,6,0xff);					
		else
			memcpy(tmp+8,update.idsn[kp_seq],6);//mem_cpy(update.idsn[kp_seq],tmp+8,6);	//报告错误时必须包含id/SN
				
		base_core.send_data_to_pc(tmp);//user__base_tx_to_pc_sub(tmp);
}



/*
基站升级键盘固件之 基站与pc之间的通信入口，也是升级功能的总入口！
call by rx_pc_0x61
流程： pc下载名单
	pc告知基站可以开始通知键盘进入下载
	pc开始发送升级数据
	然后基站进入广播升级数据
*/
void update_kp_enter(const unsigned char *rx_pc)
{	
		switch(rx_pc[4] ){
			case 1:
				update.idsn_mode =rx_pc[5];
				memcpy(&update.Hver,rx_pc+8,10);//mem_cpy(rx_pc+8,&update.Hver,10);				
			
				if(rx_pc[7]==1){			//a start update
					update.type_start_stop_data=1;//update.type_cmd_data =1;			
					update.start_end_flag=1;					
					//memset(update.valid,0,UPDATE_KP_CNT); //clear valid flag
					if(update.valid_cnt < UPDATE_KP_CNT)
						memset(update.valid+update.valid_cnt,0,UPDATE_KP_CNT-update.valid_cnt); 
					update.step =_STEP_NOTICE_START;
					_debug__updata_init();					
					update.start_end_flag=1;	//升级功能总开关!!				
				}
				else if(rx_pc[7]==0){	//b,finish update 
					update.type_start_stop_data=0;//update.type_cmd_data =0;
					update.step =_STEP_NOTICE_FINISH;	
				}
				else{									//c, stop update
					update.type_start_stop_data=0;//update.type_cmd_data =0;
					update.step =_STEP_NOTICE_ABORT;//停止命令
				}	
							
				user__pc_cmd_ack(0x61,22,rx_pc+4,26);//update_ack_pc_0x61(rx_pc);		//responce sdk		
				break;
			
			case 2:{	//download id/sn list of keypad
					unsigned char i,current;
					update.kp_counter =rx_pc[5];
					update.valid_cnt =rx_pc[5];//初始化有效个数	
					if(update.kp_counter >UPDATE_KP_CNT ) break; //超出最大键盘个数 error ??如何报告此错误?	
					//每次发送8个6字节表单	
					current = (rx_pc[6]<<3);
					//if( current >= UPDATE_KP_CNT-8) break;//error 防止数组溢出
					for(i=0;i<8;i++){
						if(current+i >= UPDATE_KP_CNT) break; //解决100只键盘最后4只无法进入升级的问题
						memcpy(update.idsn[current+i],&rx_pc[7+i*6],6);
						update.valid[current+i] =1;
					}
				}	
			
				user__pc_cmd_ack(0x61,22,rx_pc+4,26);//update_ack_pc_0x61(rx_pc);
				break;
			
			case 4://down update data
				update.downID =rx_pc[6];
				update.packH =rx_pc[7];
				update.packL =rx_pc[8];
				if(update.packL >=16) break;//error 防止数组溢出
				memcpy(update.data[update.packL],rx_pc+9,18);//mem_cpy(rx_pc+9,update.data[update.packL],18);//16bytes data +2bytes crc			
				break;
			
			case 5://一包数据传输完了，可以开始向键盘广播数据了！

				update.type_start_stop_data=2;
				update.step =_STEP_BROADCAST_DATA_INIT;
				break;
			
			case 6:	//confirm report data from pc
				update.pc_confirm_flag=1;
				update.pc_confirm_type =rx_pc[7];
				break;
					
			default:break;
		}//sw			
}



//-----------------------------------------------------------------------------
/*
* 查找下一个键盘：
* return 1-没有键盘了
* return 0-切换到下一个键盘
*/
static unsigned char next_keypad(void)
{	
	do{
			if( update.kp_cur+1	>=update.kp_counter){ 
				return 1; 
			}
			
			update.kp_cur++;
			if( update.valid[update.kp_cur]==1){ //if( update.valid[update.kp_cur]==0){
				return 0;
			}				
	}while(1);		
}


/*
* 处理询问广播启停命令后对应的键盘ack
* 与process_data_ack函数保持统一意义的return值；
*/
static unsigned char process_notice_ack(void)
{		
	return check_keypad_ack_idsn(1);
}


/*
* 处理询问广播升级数据后对应的键盘ack
*与process_notice_ack函数保持统一意义的return值；
*/
static unsigned char process_data_ack(void)
{
	unsigned char i;
	unsigned short okbit,dist_okbit=0xffff;	
	
		if(!check_keypad_ack_idsn(2)) return 0;	
	
		update.okbits = (update.keypad_ack_buf[9]<<8) + update.keypad_ack_buf[8];//record un-recevice data;all 16packets
	
//	for(i=0;i<=update.packL;i++) //Notice:packL=0-15
//			dist_okbit &= ~(1<<i);
		dist_okbit &= ~((1<<(update.packL+1))-1); //modify by Gavin 2021.05.18 解决99%时卡死问题.	
		if( (update.okbits&~dist_okbit) ==0){	 //if(update.okbits == dist_okbit){//此键盘收到了此数据块的所有数据包			
			return 1;
		}
		else{
			//没有收完所有数据片！！
			if(++update.re_send_data_times >= UPDATE_DATA_RE_SEND_TIMES){//针对某个键盘，1个数据包最多发送20次
				update.re_send_data_times=0;
				return 4;		//error;
			}
			else				
				return 3;		//not all data slot;	
		}			
}



/*
* 与键盘的交互处理
*/
unsigned char update_kp_progress(void)	
{	
		switch(update.step){
										
			/*----------------------- common start-------------------------------- 
			* part0:: common：基站发送询问数据，键盘收到后就回复;
			* 有正确回应:
			* 没有收到正确回应:
			*/	
			case _STEP_ASK_KEYPAD_INIT:				
				update.kp_cur=0;
			
			case _STEP_ASK_KEYPAD_CONTINUE:				
				if( (update.valid[update.kp_cur]==0) && next_keypad() ){//if( (update.valid[update.kp_cur]==1) && next_keypad() ){//无效键盘不再询问!!
					update.step =_STEP_THIS_PKT_FINISH;//所有键盘都询问完毕了
					break;
				}				
				update.re_send_times=0;	
				update.wait_timer=0;
				update.step =_STEP_ASK_KEYPAD;	
				//notice:此处没有break!!!!
			
			case _STEP_ASK_KEYPAD://发送询问通知
				//init rx keypad parameter！！！
				update.keypad_ack_flag=0;
				memset(update.keypad_ack_buf,0,20);			
				update.keypad_ack_buf[8]=0xff;
				update.keypad_ack_buf[9]=0xff;			
				//load send interface
				update.send_inquire_to_keypad(update.kp_cur);			
				update.step =_STEP_WAIT_KEYPAD_ACK;				
				break;

			case _STEP_WAIT_KEYPAD_ACK://等待键盘回应	
					switch(update.process_keypad_ack()){
						case 0: //键盘没有回应
							if(++update.wait_timer <WAITFOR_KEYPAD_ACK_CYCLE)	break;//等待4x2.5ms=10ms,
							update.wait_timer=0;				
							if(++update.re_send_times>=ASK_KP_TIMES){//没有等到就重发询问，最多重发 次
								update.re_send_times=0;							
								update.step =_STEP_KEYPAD_NO_ACK_ERROR;//重发次数到，error
							}
							else
								update.step =_STEP_ASK_KEYPAD;	//继续询问当前键盘						
							break;
						
						case 1://收到键盘的正确回应
							if(next_keypad()){	//is last keypad
								update.step =_STEP_THIS_PKT_FINISH;//所有键盘都询问完毕了	
							}
							else{
//								//开始询问下一个键盘时初始化；
//								update.re_send_times=0;	
//								update.wait_timer=0;	
//								update.re_send_data_times=0;	
								update.step =_STEP_ASK_KEYPAD_CONTINUE;//开始询问下一个键盘												
							}																		
							break;
						
						//case 3,case 4,used to data only
						case 3: 
							update.broadcast_data_re_send_flag =1;
							update.step =_STEP_BROADCAST_DATA_RE;//键盘没有收完所有的数据片就重发所有数据片
							break;	
						case 4:
							update.step =_STEP_KEYPAD_NO_ACK_ERROR;
							break;																								
								
						default:break;
					}//sw
				break;
				//-------------------- common end -----------------------------------------
			
			
			/* part1-0: stop and abort ;;
			*	特殊处理 终止和停止命令，广播之后不再询问键盘，基站直接退出键盘固件升级模式。
			*/
			case _STEP_NOTICE_ABORT:				
			case _STEP_NOTICE_FINISH:
				update.kp_cur=0;
				update.re_send_times=0;
				update.step =_STEP_NOTICE_STOP_PROCESS;
			
			case _STEP_NOTICE_STOP_PROCESS:				
				if(++update.re_send_times<50){	//对每个键盘发送50次停止命令
					notice_kp_enter_exit_update(update.kp_cur);
				}
				else{					
					update.re_send_times=0;					
					if(++update.kp_cur >=update.kp_counter){
						update_report_info_to_pc(update.kp_cur,1); //report finish 
						update.start_end_flag =0;//基站退出键盘固件升级模式。						
						update.step =_STEP_INIT0;						
					}
				}
				break;
			
				
			/* part1-1:start 广播启动命令
			*/			
			case _STEP_NOTICE_START:	
				update.send_inquire_to_keypad =notice_kp_enter_exit_update;
				update.process_keypad_ack =process_notice_ack;
				update.step= _STEP_ASK_KEYPAD_INIT;	
				break;					
						
			/* part 2: send upgrade data 
			*/			
			case _STEP_BROADCAST_DATA_INIT:		//每包数据发送从这里开始			
				update.re_send_data_times=0;			
				update.send_inquire_to_keypad =ask_keypad;
				update.process_keypad_ack =process_data_ack;			
				update.broadcast_data_re_send_flag =0;
			
				update.pack_cur =0;
				update.step= _STEP_BROADCAST_DATA;
				//此处没有break!!!
			
			case _STEP_BROADCAST_DATA:	//每包数据有N片，每片发送从这里开始 SEND_UPDATE_DATA_INTERVEL
				if(++update.send_data_slice_interval <=SEND_UPDATE_DATA_INTERVEL) break;
			
				if( update.pack_cur<=update.packL){//broadcast this packet,then pointer next packet;
					broadcast_update_data(update.pack_cur);					
					update.pack_cur++;//指向下一条数据
					update.send_data_slice_interval=0;
				}
				else{//本次数据块发送完成;
					_debug__data__re_send_times();
//					if(update.broadcast_data_re_send_flag)
//						update.step= _STEP_ASK_KEYPAD_CONTINUE;
//					else	
						update.step= _STEP_ASK_KEYPAD_INIT;					
				}
				break;
				
			/*part2-2 16片数据没有收齐, 重复发送当前所有数据包,
			发送完毕后要从当前键盘开始询问,而不是从kp_cur=0开始 */
			case _STEP_BROADCAST_DATA_RE:	//重发数据包从此开始
				//update.pack_cur =0;
				//update.step= _STEP_BROADCAST_DATA;
				if( update.okbits ==0){//add by Gavin20210518,处理异常;
					update.okbits =0xffff;
				}
				
				if(++update.send_data_slice_interval <=SEND_UPDATE_DATA_INTERVEL) break;					
				for(unsigned char i=0;i<16;i++){
					if( ((update.okbits>>i)&0x01)==0)continue;//find re-send
					update.okbits &= ~(1<<i); //clear this bit					
					broadcast_update_data(i);
					if( update.okbits ==0)
						update.step= _STEP_ASK_KEYPAD_CONTINUE;
					break;	//break for loop when send a slice data, for keep data send interval;
				}//for				
				break;
				
																		
			/* part3: 基站报告键盘错误信息to PC
			*/							
			case _STEP_KEYPAD_NO_ACK_ERROR:
				update.pc_confirm_flag=0;
				update_report_info_to_pc(update.kp_cur,2);	//report error to pc
			  //record invalid keypad flag,and dec vaild count keypad
			  update.valid[update.kp_cur]= 0;//1;							
				if(update.valid_cnt) update.valid_cnt--;
				update.step= _STEP_WAIT_PC_CONFIRM_ERROR;
				break;
			
			case _STEP_WAIT_PC_CONFIRM_ERROR:
				if(!update.pc_confirm_flag){//no rx pc ack 
					//update_report_info_to_pc(update.kp_cur,2);	//report error to pc
				}
				//rx pc ack ok
				update.pc_confirm_flag =0;
				if(next_keypad() ){
					update.step =_STEP_THIS_PKT_FINISH;
					//update.step =_STEP_INIT0;
				}
				else{
					//ask_next_keypad_init();	
					update.re_send_times=0;	
					update.wait_timer=0;	
					update.re_send_data_times=0;	
					update.step =_STEP_ASK_KEYPAD;//开始询问下一个键盘					
				}					
				break;
			
				
			/* part4:基站上报完成一包数据 给pc 
			*/	
			case _STEP_THIS_PKT_FINISH:
				update.pc_confirm_flag=0; 
				//rpt to pc
				update_report_info_to_pc(update.kp_cur,1); //report finish 
				update.step = _STEP_WAIT_PC_CONFIRM_FINISH;			
				break;
				
			case _STEP_WAIT_PC_CONFIRM_FINISH:
				if(!update.pc_confirm_flag){//no rx pc ack 
					//update_report_info_to_pc(update.kp_cur,1); //report finish 
				}				
				update.pc_confirm_flag =0;	

				//list中没有有效键盘了 add by Gavin 20200316
				if(update.valid_cnt==0 ){
					update.start_end_flag =0;//基站退出键盘固件升级模式。						
					update.step =_STEP_INIT0;		
				}
				break;				
				
			default:break;
		}//sw
		
				
		//返回升级状态，用于入口知道是否还有数据
		return update_get_status();		
}



/*
* 检测基站和sdk的连接状态;
*解决关闭sdk后，基站和键盘无法退出升级状态的问题;
*/
void update_monitor_sdk_connect(void)
{
//	static unsigned short update_sdk_connect_cnt;
//	
//	if( !update_get_status() ) return;
//	
//	if( base_core.get_sdk_connect_status() )
//		update_sdk_connect_cnt=0;
//	else{		
//		if( (++update_sdk_connect_cnt>= 50* 20)&&
//			(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 

#endif
