
#include "base_pc_protocol.h"
#include "platform.h"
#include "function_interface.h"
#include "base_core.h"
#include "base_core_user.h"
#include "func_down_beacon_intf.h"
#include "ext_beacon_intf.h"
#include "func_multipkt_up_intf.h"
#include "fast_beacon_intf.h"
#include "stop_beacon_intf.h"

struct keypad_idsn_STR keypad_idsn;


/*----------------------- CRC --------------------------------------------------------
基站和键盘之间的crc校验开关，sdk可以直接设置;
区别于function.crc16_keypad__SW --固件是否支持crc功能;
*/

/*
*/
void set_keypad_crc_config(unsigned char flag)
{
	if( function.crc16_keypad__SW){
		//a,特殊的 AES开启的模式下,keypad CRC强制打开的!!!!!!
		if(function.aes__get_status() !=0)
			kernel.keypad_crc_flag =1;
		else{
			kernel.keypad_crc_flag =flag;
		}
	}
	else{
		//如果base core不支持CRC功能，直接反馈0
		kernel.keypad_crc_flag =0;		
	}
	
	//store keypad crc config 
	base_write_e2prom(STORE_KP_CRC_CONFIG,&kernel.keypad_crc_flag,1);
}

///*
//特殊的..
//*/
//unsigned char get_keypad_crc_config(void)
//{
//	//AES开启的模式下,keypad CRC强制打开的!!!!!!
//	if(function.aes__get_status() !=0)
//		set_keypad_crc_config(1);
//	
//	return kernel.keypad_crc_flag;
//}
	
/*
判断基站和键盘是否进行CRC校验
如果已经开启了AES功能，由于AES自带了CRC，所以外部不能再做CRC了
如果没有开启AES功能，就按 keypad_crc_flag的实际值来运行
*/
unsigned char keypad_crc_check(void)
{
	if(function.aes__get_status() !=0)
		return 0;	
	else if (function.crc16_keypad__SW==0)
		return 0;
	else
		return kernel.keypad_crc_flag;
	
}



/*-----------------------------------------------------------
基站发给键盘的数据：
基础信标，投票信标和投票数据的确认
input[0] = data length
rf_id 表示的是核心内部记录的硬件编号的数组下标!!!!
*/
void base_tx_to_keypad_sub(unsigned char *ibuf,unsigned char rf_id)
{		
		unsigned char buf[64+1];		//add by Gavin,函数重入问题;
		mem_cpy(ibuf,buf,ibuf[0]+1);
	
		if(function.no_matchcode__SW){ //NO math code 
			buf[0] -=4;
			mem_cpy(buf+5,buf+1,buf[0]);
		}		

//		if( keypad_crc_check()){//if(function.crc16_keypad__SW){
//			unsigned short crc_tmp;
//			crc_tmp = crc16(buf+5,26);
//			buf[31]=crc_tmp>>8;
//			buf[32]=crc_tmp&0xff;
//			buf[0]=32;	
//		}

		//monitor rf modual
		rf_modual__tx_counter(multi.modual_id[rf_id]);

		function.aes__rf_Encrypt(buf); //AES		
		platform.rf_send_data(buf+1,buf[0],multi.modual_id[rf_id]);		
}


/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
和上述函数相比，此函数专门给外部使用 function中都可能会用到。
rf_id表示的是 无线模块的硬件标号*/
void send_to_keypad_user_hardID(unsigned char *ibuf,unsigned char rf_hard_id)
{	
		unsigned char buf[64+1];		//add by Gavin,函数重入问题;
		mem_cpy(ibuf,buf,ibuf[0]+1);
	
		if(function.no_matchcode__SW){ //NO math code 
			buf[0] -=4;
			mem_cpy(buf+5,buf+1,buf[0]);
		}	

		//
//		if( keypad_crc_check()){//if(function.crc16_keypad__SW){
//			unsigned short crc_tmp;
//			crc_tmp = crc16(buf+5,26);
//			buf[31]=crc_tmp>>8;
//			buf[32]=crc_tmp&0xff;
//			buf[0]=32;	
//		}
		
		function.aes__rf_Encrypt(buf); //AES			
		platform.rf_send_data(buf+1,buf[0],rf_hard_id);		
}



/*
判断/限制基站频点*/
unsigned char assert_base_channel(void)
{
	if(function.lock_channel!=0)
		base_config.chan = function.lock_channel;
	
	if( function.mask_spec_channel){
		if( base_config.chan ==2) base_config.chan=1;
		if( base_config.chan ==26) base_config.chan=25;
		if( base_config.chan ==80) base_config.chan=79;		
	}

			
	if( (base_config.chan <=0)||(base_config.chan>function.rf_channel_max) ){
		base_config.chan =1;
		return 0;
	}
	return 1;	
}





//--------------------------------------- record id/sn  process--------------------------
/*
保存键盘的id/sn 
intput:
	idsn--buffer
	byteN- id/sn字符个数
return:
	0- fail
	1- OK			*/
unsigned char keypad_idsn_save(const unsigned char *idsn,unsigned char byteN,unsigned char rf_id)
{	
		unsigned char idsn_count; 
		if( byteN>6) return 0;		
		if(rf_id >=4)  return 0;
	
//kernel.multi_title_flag=0;//debug only	
//		if(kernel.multi_title_flag){	//多题型特殊处理
//			if( (idsn[8]==0) ||(idsn[8] >200) ) return 0;		//判断题型
//		}

		PLATFORM_DISABLE_IRQ();//platform.disable_interrupt();	
			
		if( (idsn_count= multi.multi_idsn[rf_id].number) <10){	
			mem_cpy(idsn,multi.multi_idsn[rf_id].idsn[idsn_count],byteN);

//			if(kernel.multi_title_flag){	//多题型特殊处理
//				multi.multi_idsn[rf_id].idsn[idsn_count][4] = idsn[8]; //记录题型，用于ack, debug only!!!
//			}
//			else
			{
				//crs2模式下需要特殊处理【4】
				if(function.crs2__SW)	//键盘用此字节判断基站的ack是否有效
//					multi.multi_idsn[rf_id].idsn[idsn_count][4] =1;	
                    multi.multi_idsn[rf_id].idsn[idsn_count][4] = idsn[8];//20221008 用于解决测验题丢题，键盘发了， 基站未收到的bug,可能是键盘ACK逻辑问题
                
                if(idsn[14] == 1 && *(idsn-1)== 11)//入网申请,20220621
                {
                    if((idsn[12]*256 + idsn[13])== function.network__get_pwd() || function.network__get_pwd()==0)//密码正确或无密码
                    {
                        multi.multi_idsn[rf_id].idsn[idsn_count][4] =11;
                    }
                    else
                    {
                        multi.multi_idsn[rf_id].idsn[idsn_count][4] =10;
                    }
                }
			}			
			multi.multi_idsn[rf_id].number++;
		}
		
		PLATFORM_ENABLE_IRQ();//platform.enable_interrupt();		
		return 1;
}


/*
清除记录键盘idsn,及有效个数
*/
void keypad_idsn_clear(void)
{
		unsigned char i,j;
		//涉及到副模块发信标和频点轮转
		for(i=0;i<multi.hard_rf_modual_cnt;i++){
			multi.multi_idsn[i].number=0;
			for(j=0;j<10;j++)
				mem_set(multi.multi_idsn[i].idsn[j],SN_LEN,0);
		}//for		
}


/*
* sdk设置的扩展基础信标之后，就开启和标准基础信标交替发送;	*/
static unsigned char ext_basic_beacon_startup_flag=0;

void set_ext_basicbeacon_startup_flag(unsigned char sw)
{
	ext_basic_beacon_startup_flag=sw;
}

/*
判断是否在容量均衡模式*/
unsigned char get_ext_basicbeacon_startup_flag(void)
{
	return ext_basic_beacon_startup_flag;
}





#ifndef RF_5G8
//-----------------------------------------------
//id模式下，回复键盘
static void base_confirm_keypad_id_mode(void)
{
		unsigned char tmp[32];
		unsigned char i,j;
	
		tmp[0] =28;
		get_base_match_code(tmp+1);
		tmp[5] =0x15;	
 			
		for(j=0;j<multi.count;j++){ 
			if(multi.whitelist_index ==j) continue;//白名单模块不需要回复ack
			for(i=0;i<10;i++)
				mem_cpy(multi.multi_idsn[j].idsn[i],tmp+6+2*i,2);//id =2
			//add by Gavin 20210423
			if( (function.base_type ==TYPE_EVS100)&&(function.crc16_keypad__SW==1)&&keypad_crc_check()){ //E100			
				unsigned short crc_tmp;
				tmp[26] = 0;
				crc_tmp =crc16(tmp+5,22);
				tmp[27] = crc_tmp>>8;
				tmp[28] = crc_tmp&0xff;
			}					
			base_tx_to_keypad_sub(tmp,j);
		}//for				
}

static void base_confirm_keypad_sn_mode(unsigned char seq)
{
		unsigned char tmp[64];//tmp[32]; //20200511
		unsigned char i,seq2,j;
	
		tmp[0] =35;
		get_base_match_code(tmp+1);
		tmp[5] =0x16;	
		seq2 = (seq==1)?0:5;
 			
		for(j=0;j<multi.count;j++){ 
			if(multi.whitelist_index ==j) continue;//白名单模块不需要回复ack
			for(i=0;i<5;i++)
				mem_cpy(multi.multi_idsn[j].idsn[seq2+i],tmp+6+SN_LEN*i,SN_LEN);
			//add by Gavin 20210423
			if( (function.base_type ==TYPE_EVS100)&&(function.crc16_keypad__SW==1)&&keypad_crc_check()){ //E100
				unsigned short crc_tmp;
				i=4;
				tmp[6+i*6] = 0x00;
				tmp[7+i*6] = 0x00;
				tmp[8+i*6] = 0x00;
				tmp[9+i*6] = 0x00;				
				crc_tmp =crc16(tmp+5,29);
				tmp[10+i*6] = crc_tmp>>8;
				tmp[11+i*6] = crc_tmp&0xff;				
			}

			base_tx_to_keypad_sub(tmp,j);
		}//for

}


static void base_confirm_keypad_crs2_mode(unsigned char seq)
{
		unsigned char tmp[64];//tmp[32];
		unsigned char i,seq2,j;
#if 0	
		tmp[0] =32;
		get_base_match_code(tmp+1);
		tmp[6] =0;
		tmp[7] =0;
		if(seq==1){
			seq2 =0;
			tmp[5] =0x18;
			if(function.aux_att__SW)
				tmp[6] =(aux_att.keypad_attn_sw>0)+ ((aux_att.keypad_report_sw>0)<<1) + ((aux_att.base_beacon_sw>0)<<2);		
		}else{
			seq2=5;
			tmp[5] =0x19;	
			if(function.aux_att__SW)
				tmp[6] =(aux_att.keypad_attn_sw>0)+ ((aux_att.keypad_report_sw>0)<<1);
		}
							
		for(j=0;j<multi.count;j++){ 
			if(multi.whitelist_index ==j) continue;//白名单模块不需要回复ack
			for(i=0;i<5;i++){
				#ifdef _DBG_2G4_KP_
				core_debug__record_ack_keypad(multi.multi_idsn[j].idsn[seq2+i] );
				#endif
				mem_cpy(multi.multi_idsn[j].idsn[seq2+i],tmp+8+5*i,5);
			}				
			base_tx_to_keypad_sub(tmp,j);
		}//for
#else
		tmp[0] =32;
		get_base_match_code(tmp+1);
		tmp[6] =0;
		tmp[7] =0;
		if(seq==1){
			seq2 =0;
			tmp[5] =0x18;
			if(function.aux_att__SW)
				tmp[6] =(aux_att.keypad_attn_sw>0)+ ((aux_att.keypad_report_sw>0)<<1) + ((aux_att.base_beacon_sw>0)<<2);		
		}else{
			seq2=5;
			tmp[5] =0x19;	
			if(function.aux_att__SW)
				tmp[6] =(aux_att.keypad_attn_sw>0)+ ((aux_att.keypad_report_sw>0)<<1);
		}
							
		for(j=0;j<multi.count;j++){ 
			if(multi.whitelist_index ==j) continue;//白名单模块不需要回复ack
			
			if(kernel.multi_title_flag == 0){
				for(i=0;i<5;i++){
					#ifdef _DBG_2G4_KP_
					_debug_core__record_ackkp_info(tmp[5],multi.multi_idsn[j].idsn[seq2+i] );
					#endif
					mem_cpy(multi.multi_idsn[j].idsn[seq2+i],tmp+8+5*i,5);
				}//for
				//add by Gavin 20210423
				if( (function.base_type ==TYPE_EVS100)&&(function.crc16_keypad__SW==1)&&keypad_crc_check()){ //E100
					unsigned short crc_tmp;
					i=4;
					tmp[6+i*6] = 0x00;
					tmp[7+i*6] = 0x00;
					tmp[8+i*6] = 0x00;
					tmp[9+i*6] = 0x00;				
					crc_tmp =crc16(tmp+5,29);
					tmp[10+i*6] = crc_tmp>>8;
					tmp[11+i*6] = crc_tmp&0xff;				
				}
			}
			else{ //200200826;特殊处理多题型:
				unsigned short crc;					
				for(i=0;i<4;i++){	//ACK 4 keypad Max, remain 5bytes for CRC load tmp31,32;
					#ifdef _DBG_2G4_KP_
					_debug_core__record_ackkp_info(tmp[5], multi.multi_idsn[j].idsn[seq2+i] );
					#endif
					mem_cpy(multi.multi_idsn[j].idsn[seq2+i],tmp+8+5*i,5);
				}//for									
				tmp[28] = 0xff;
				tmp[29] = 0xff;
				tmp[30] = 0xff;			
				crc=crc16(tmp+5,26);
				tmp[31] = crc>>8;
				tmp[32] = crc;			
			}
			
			base_tx_to_keypad_sub(tmp,j);
		}//for
		
#endif
}



//============================================ base tx to keypad beacon =========================================
#define 	STEP_SEND_BASIC_BEACON			1
#define 	STEP_SEND_VOTE_BEACON				2
#define 	STEP_RX_VOTE				  			3
#define 	STEP_SEND_CONFIRM1				  4
#define 	STEP_SEND_CONFIRM2				  5
#define 	STEP_SEND_CONFIRM_END				6
#define 	STEP_TRANS2KEYPAD				  	7
#define 	STEP_KEYPAD_UPDATE				  8
		

struct send_beacon_STR{
	unsigned char step;
	unsigned char vote_beacon_cnt;
	#define 	WAITFOR_VOTE_2MS5  10	
	unsigned char waitfor_vote;
	//转发相关
	unsigned char (*transfer_function_pointer)(void);
	unsigned char transfer_idle_times,transfer_busy_times;	
};
struct send_beacon_STR send_beacon;









/*
*发送扩展基础信标
*用于多基站容量均衡;
* see keypad protocol V5.40 secton2.3
*/ 
static void base_tx_ext_basic_beacon(void)
{
		unsigned char tmp[32],j;
		
		tmp[0] =31;//28; //len
		base_core.get_match_code(tmp+1);
		tmp[5] =0x10; //ext basic beacon
		tmp[6] =get_base_id(); //base id
		mem_cpy(&basic_ext_beacon.head_addr+1,tmp+7,BASIC_EXT_BEACON_LEN);
	
		for(j=0;j<multi.count;j++)
			base_tx_to_keypad_sub(tmp,j);
			
		send_beacon.step = STEP_RX_VOTE;
		send_beacon.vote_beacon_cnt =0;
		send_beacon.waitfor_vote=0;
}




/*
*扩展基础投票信标的启停控制：
* 扩展基础信标和正常基础信标交替发送;
*/
static unsigned char check_send_ext_basic_beacon(void)
{
	static unsigned char alternate=0;
	
	if( get_ext_basicbeacon_startup_flag() ==0) return 0;
	
	alternate ^=1;	
	if( alternate){
		base_tx_ext_basic_beacon();
		return 1;		
	}
	return 0;		
}


static unsigned char beacon_type=0;
/*
发送基础信标函数  get_base_match_code
*/
static void base_tx_basic_beacon(void)
{	
		
		unsigned char tmp[40],j;

		if( check_send_ext_basic_beacon()) return;
	
		keypad_idsn_clear();
	
		tmp[0] =32;	
		get_base_match_code(tmp+1);//tmp1-4
		tmp[5] =0x10; //basic beacon		
		tmp[6] =get_base_id(); //base id		
		tmp[7] =0xA5; //表决器协议2.1 :第一个字节是0xA5时，第二字节(KEYMAX值)是频点	
		tmp[8] =get_base_main_rfchannel();
		tmp[9] =base_config.keymax[0];
		tmp[10] =base_config.keymax[1];
		mem_cpy(basic_beacon.auth_code,tmp+11,8);	// auth_code - nowT tmp[14];
			
		//自由登录模式标志
		tmp[13]=basic_beacon.login &0x0f;
		if( (get_base_log_mode()==2) ||(get_base_log_mode()==5) )
			tmp[13] |=0x80;
		
		switch(beacon_type){
			case 0:
				tmp[19] =1;// base name 
				mem_cpy(base_name_log_mode.base_name,tmp+20,12);
				//tmp[0] = 31;
				//VOXM键盘才发送议案信息		
				beacon_type =(function.base_type == TYPE_CRS200_433)?1:2;////beacon_type =(function.match_keypad_type ==KP_VOXM)?1:2;
				break;	
			
			case 1:
				tmp[19] =3;//议案信息
				mem_cpy(kernel.bill_info,tmp+20,9);
				beacon_type++;//beacon_type=0;//
				break;
			
			case 2:
				tmp[19] =2;//特殊模式，多频点信息!!!!
				tmp[20] = multi_freq_setup.attrib2;// 128;
				tmp[21] = multi.count;//
				mem_cpy(multi.modual_chan,tmp+22,4);			
				beacon_type=0;
				break;		

			default:
				beacon_type=0;
				break;
		}//sw
		
		for(j=0;j<multi.count;j++){	
			if(multi.whitelist_index ==j) continue;//白名单模块不发信标;
			if( get_ext_basicbeacon_startup_flag() )
				tmp[8] =multi.modual_chan[j];
			if( (function.base_type ==TYPE_CRS200_433) ||//433M 增加crc
						( (function.base_type ==TYPE_EVS100)&&(function.crc16_keypad__SW==1)&&keypad_crc_check()) //E100
					){				
				unsigned short crc=crc16(tmp+5,26);
				tmp[31] = crc>>8;
				tmp[32] = crc;
				tmp[0] = 32;					
			}
			base_tx_to_keypad_sub(tmp,j);
		}//for
				
		send_beacon.step = STEP_RX_VOTE;
		send_beacon.vote_beacon_cnt =0;
		send_beacon.waitfor_vote=0;
}


/*
*双天线切换
*/
static void doule_ant_application(void)
{
		static unsigned char multi_ant_counter;
		if( ++multi_ant_counter>10){
			if(multi_ant_counter>12)	multi_ant_counter=0;
			platform.doule_ANT_sw(1);//副天线
		}
		else{			
			platform.doule_ANT_sw(0);//主天线
		}		
}




/*------------------------------ extend vote beacon start -------------------------------------
20200914 
1,将 CRS100上 自定义标题（新东方泡泡定制）移植到大基站;see keypad protocol V0.99-10 secton2.2.17
2,增加section 2.2.17-2指定答题器;

*发送扩展投票信标
教育新版-表决器V0.99-14 section2.2.17-2;
沿用教育新版-基站协议V0.95 section2.4 设置扩展信标。
可以参考之前已经在CRS100上完成的 -表决器V0.99-10 section2.2.17（泡泡自定义题型）
*/
#ifdef 	EXTEND_VBEACON2
static void base_tx_ext_vbeacon(unsigned char type)
{
	unsigned char tmp[32];
	
	tmp[0] =31;//28; //len
	base_core.get_match_code(tmp+1);//get_base_match_code(tmp+1);//tmp1-4
	tmp[5] =0x33; //ext vote beacon		
	if(type==0)
		mem_cpy(&ext_vbeacon.head_addr+1,tmp+6,EXT_VBEACON_LEN);
	else 
		mem_cpy(&ext_vbeacon_2.head_addr+1,tmp+6,EXT_VBEACON_LEN);
	tmp[31] =get_base_main_rfchannel();// add by Gavin 20201222 配合T1lite
	base_tx_to_keypad_sub(tmp,get_mainRF_usr_id());	
	
	send_beacon.step = STEP_RX_VOTE;
	send_beacon.vote_beacon_cnt++;   
	send_beacon.waitfor_vote= 0;	
}
#else
static void base_tx_ext_vbeacon(void)
{
	unsigned char tmp[32];
	
	tmp[0] =31;//28; //len
	base_core.get_match_code(tmp+1);//get_base_match_code(tmp+1);//tmp1-4
	tmp[5] =0x33; //ext vote beacon		
	mem_cpy(&ext_vbeacon.head_addr+1,tmp+6,EXT_VBEACON_LEN);
	
	base_tx_to_keypad_sub(tmp,get_mainRF_usr_id());	
	
	send_beacon.step = STEP_RX_VOTE;
	send_beacon.vote_beacon_cnt++;   
	send_beacon.waitfor_vote= 0;	
}
#endif


/*
*扩展投票信标的启停控制 
* turn on : sdk写入参数后就启动发送 kernel.ext_vbeacon_onoff_flag
* turn off: sdk停止业务。
*/
static unsigned char check_send_ext_vbeacon(void)
{
	static unsigned char alternate_flag=0;
	
	if( kernel.ext_vbeacon_onoff_flag && (alternate_flag ^=1) ){
		
		#ifdef 	EXTEND_VBEACON2	
		if(kernel.ext_vbeacon_type1_flag && kernel.ext_vbeacon_type2_flag){
			static unsigned char cur_type=0;
			if(cur_type==0)
				base_tx_ext_vbeacon(0);
			else
				base_tx_ext_vbeacon(1);					
			cur_type^=1;			
		}
		else if(kernel.ext_vbeacon_type1_flag){
			base_tx_ext_vbeacon(0);
		}
		else if(kernel.ext_vbeacon_type2_flag){
			base_tx_ext_vbeacon(1);
		}		
		#else
		base_tx_ext_vbeacon();
		#endif
		return 1;				
	}
	
	if( kernel.ext_vbeacon_sysmode_change_flag &&  (vote_beacon.sys_mode ==0) ){
		kernel.ext_vbeacon_sysmode_change_flag=0;
		kernel.ext_vbeacon_onoff_flag=0;
		
		kernel.ext_vbeacon_type1_flag=0;
		kernel.ext_vbeacon_type2_flag=0;		
	}
	
	return 0;
}
//------------------------------ extend vote beacon end -------------------------------------


/*
发送投票信标函数*/
static void base_tx_vote_beacon(void)
{	
		unsigned char tmp[40],j;
		
		//check send exr vote beacon
		if(check_send_ext_vbeacon()) return;
	
		//clear record id/sn buffer,	
		keypad_idsn_clear();
		
		if( function.broadcast__keypad_request(0)==1) return; //接收键盘的重复广播的申请并且已经确认后就开启广播，关闭信标发送
		//双天线切换
	//	doule_ant_application();
    
        basic_beacon_crs2.pack_cnt++;
        if(basic_beacon_crs2.pack_cnt>7) basic_beacon_crs2.pack_cnt=0;//0~7 信标序号，20220518
        
        #if MD_EXT_BEACON	
        volatile static unsigned char special_ext_beacon_flag =1;
		if(basic_beacon_crs2.pack_cnt ==0){
			special_ext_beacon_flag ^=1;
			if(special_ext_beacon_flag==0){
				if(core__ext_beacon_intf.execute())
                {
                    basic_beacon_crs2.pack_cnt =7;
//    				platform._2ms5_count_down(100); //platform__timer_intf._2ms5_count_down(1000);
                    return;	
                }
			}
		}
        #endif
        
        #if (MD_DOWN_BEACON)
        if( func__down_beacon_intf.get_status() )
        {
            basic_beacon_crs2.pack_cnt =7;	
        }			
        #endif
        
        #if MD_FAST_BEACON
		if( core__fast_beacon_intf.get_status() )
			basic_beacon_crs2.pack_cnt =7;	
		#endif
	
		//如果开启了att功能， 模拟测试打开后才发投票信标
		if( (function.aux_att__SW==0)|| (function.aux_att__SW && aux_att.base_beacon_sw) )
		{

			tmp[0] =32;			
			get_base_match_code(tmp+1);//tmp1-4
			tmp[5] =(log_mode_is_ID)?0x13:0x14; //vote beacon	
			if(log_mode_is_CRS2 )	tmp[5] =0x17;//见教育新版表决器协议	
			tmp[6] =basic_beacon.nowT[0]; //nowT
			tmp[7] =basic_beacon.nowT[1];			
			mem_cpy(&vote_beacon.head_addr+1,tmp+8,VOTE_BEACON_LEN);
#if MD_SPECIAL_STOP_PRO
			if(vote_beacon.sys_mode == 0){//tmp+14
				core__stop_beacon_intf.cover(tmp+16);
			}
#endif
			
			if( log_mode_is_WHITELIST)
				tmp[9] =vote_beacon.sys_mode |(1<<6) ; //控制白名单开关
			else
				tmp[9] =vote_beacon.sys_mode &~(1<<6) ;
			
			/*		
			//由于增加了快速配对时发送AES秘钥;所以在AES加密模式下快速配对时，不能加载如下信息，否则AES秘钥被会被修改!!!		*/
			//if( function.fastmatch__load_info_to_vote_beacon(tmp)==0){//modify by gavin 20200422
			if( (function.fastmatch__load_info_to_vote_beacon(tmp)==0) || (function.aes__get_status()==0) ){	
				if(log_mode_is_CRS2 ){ //crs2 mode
					tmp[5] =0x17;//见教育新版表决器协议	
					//tmp[0] =32;
					mem_cpy(&basic_beacon_crs2.head_addr+1,tmp+29,BASIC_BEACON_CRS2_LEN);
//                    basic_beacon_crs2.pack_cnt++;
//                    if(basic_beacon_crs2.pack_cnt>7) basic_beacon_crs2.pack_cnt=0;//0~7 信标序号，20220518
                    tmp[28] =basic_beacon_crs2.pack_cnt;//序号用于键盘休眠同步醒来,20220518
					tmp[29] =basic_beacon_crs2.crs2_attrib[0]| (get_base_log_mode()==5);
					tmp[30] =basic_beacon_crs2.crs2_attrib[1];
					tmp[31] =get_base_main_rfchannel();//不能用组网序号，需要主频点，否则会有副频点干扰 		
//                    tmp[31] = function.network__get_netseq();//改为组网序号，20220621
					if( (function.base_type == TYPE_CRS200)||(function.base_type == TYPE_C100) )
						tmp[32] = crc16(tmp+5,27)&0xff;	//Notice:配合T1lite 必须启用
					else{
						tmp[32] =basic_beacon_crs2.crs2_attrib[3];
					}
				}
				else{//20200401 配G1时无法锁频而增加主频点信息;
						tmp[29] =0xA5;				
						tmp[30] =get_base_main_rfchannel();					
				}
			}
		
			for(j=0;j<multi.count;j++){
				if(multi.whitelist_index ==j) continue;//白名单模块不发信标;
				if( get_ext_basicbeacon_startup_flag() )//容量均衡模式下发送各自模块的信标
					tmp[30] =multi.modual_chan[j];
				if( (function.base_type ==TYPE_CRS200_433)|| //433M 增加crc
						( (function.base_type ==TYPE_EVS100)&&(function.crc16_keypad__SW==1)&&keypad_crc_check()) //E100
					){
					unsigned short crc=crc16(tmp+5,26);
					tmp[31] = crc>>8;
					tmp[32] = crc;
					tmp[0] = 32;					
				}				
				if(tmp[9])
                {
                    if((tmp[9]&0x80)==0)
                      tmp[0] = 32;
                    else
                        tmp[0] = 32;
                }
                
				base_tx_to_keypad_sub(tmp,j);
			}//for
		
		}
		//here,add special setting 
	
		send_beacon.step = STEP_RX_VOTE;
		send_beacon.vote_beacon_cnt++;   
		send_beacon.waitfor_vote= 0;
}

extern unsigned char msg_issendtime(void);
extern void msg_recover_beacon_countdown(void);
/* ---------------------------------------------------------
基站发送信标/时序 给键盘 
此函数2.5ms被调用一次	
called by 2.5ms timer*/
void base_tx_keypad_beacon(void)
{
    #if TEXT_MESSAGE 
        msg_recover_beacon_countdown();
    #endif
		if(send_beacon.step==0) return;
					
		switch(send_beacon.step){
			//----1 基础信标
			case STEP_SEND_BASIC_BEACON:
				if(log_mode_is_CRS2)
					base_tx_vote_beacon();//crs2协议下 不发送基础信标了
				else 
					base_tx_basic_beacon();					
				break;
			
			//----2 投票信标
			case STEP_SEND_VOTE_BEACON:				
				base_tx_vote_beacon();			
				break;			
			
			//-----3 接收键盘投票
			case STEP_RX_VOTE: //?? 
				if( ++send_beacon.waitfor_vote <WAITFOR_VOTE_2MS5){
                    function.network__polling(1);
					if( log_mode_is_WHITELIST) 
						function.whitelist__base_confirm_keypad_request(); //回复白名单申请;
					break;	//时间未到，继续等待	
				}
				else 
                {
                    function.network__polling(0);
					send_beacon.step = STEP_SEND_CONFIRM1;
                }
				break;
			
			//-----4 开始发送确认信息  
			case STEP_SEND_CONFIRM1: 
				if( log_mode_is_ID){ //is id -only one confirm
					base_confirm_keypad_id_mode();	
					send_beacon.step = STEP_SEND_CONFIRM_END;
				}
				else{// SN/CRS2 --two confirm, this is first confirm;
					if(log_mode_is_CRS2)//is CRS2
						base_confirm_keypad_crs2_mode(1);
					else								//is SN
						base_confirm_keypad_sn_mode(1);										
					send_beacon.step = STEP_SEND_CONFIRM2;
				}						
				break;
			
			//-----5 开始发送确认信息 2  
			case STEP_SEND_CONFIRM2: 	//SN/CRS2，this is second confirm;
					if(log_mode_is_CRS2)	//is CRS2
						base_confirm_keypad_crs2_mode(2);
					else								//is SN
						base_confirm_keypad_sn_mode(2);	
					send_beacon.step = STEP_SEND_CONFIRM_END;
				break;				
			
			//------------------------------------------------
			//-----6 发完确认信息后，分情况执行
			case STEP_SEND_CONFIRM_END:
				multi_chan_polling();
				//a,快速配对模式下，连续发送投票信标
//                msg_polling();
				//base_tx_vote_beacon();
				//b,判断是否有转发
                #if MD_MULTIPKT_UP
					if( func__multipkt_up_intf.tx_call()) return;
                #endif
            
				if(pc_transfer2keypad_data_fetch()){
					send_beacon.transfer_busy_times=0;
					send_beacon.transfer_idle_times=0;
					send_beacon.transfer_function_pointer = pc_transfer2keypad_data_fetch;//function.update__kp_progress;
					send_beacon.step = STEP_TRANS2KEYPAD;					
				}
				else	//c,升级键盘固件 (轮询)		
				if(function.updatekp__SW && function.update__get_status() ){
					send_beacon.transfer_busy_times=0;
					send_beacon.transfer_idle_times=0;
					send_beacon.transfer_function_pointer = function.update__kp_progress;
					send_beacon.step = STEP_TRANS2KEYPAD;
				}			
				//d,常规状态下，1个基础信标2个投票信标的 节奏 
				else
				{
					if( (!log_mode_is_CRS2)&&( send_beacon.vote_beacon_cnt >=2)){
						send_beacon.vote_beacon_cnt=0;
						base_tx_basic_beacon();
					}
					else//crs2模式 或者非crs2模式下投票信标少于2	
                    {    
                        #if TEXT_MESSAGE 
                            if(!msg_issendtime())  
                                base_tx_vote_beacon();
                            else
                            {
                                base_send_beacon_switch(0);
                            }
                        #else
                            base_tx_vote_beacon();
                        #endif
                    }                        
				}
				break;	
						
			case STEP_TRANS2KEYPAD:
				if(send_beacon.transfer_function_pointer() ){//有数据
					//send_beacon.transfer_idle_times=0;
					send_beacon.transfer_busy_times++;
					if(send_beacon.transfer_busy_times>= 80){
						beacon_type=1;	//433M
						send_beacon.step =STEP_SEND_BASIC_BEACON;
					}						
				}
				else{
					unsigned char transfer_idle_timer_tmp;
					send_beacon.transfer_idle_times++;
					//send_beacon.transfer_busy_times=0;
					/* 2020.07.23 433M基站配合Voxm平板时"显示结果的状态下离线再在线无法恢复到离线前的状态" 解决办法：20timers
					2020.09.15 EVS200 下发名单经常失败; 解决办法：80timers;
					*/
					if(function.base_type ==TYPE_CRS200_433)
						transfer_idle_timer_tmp =20;
					else
						transfer_idle_timer_tmp =80;						
					if(send_beacon.transfer_idle_times>= transfer_idle_timer_tmp){//if(send_beacon.transfer_idle_times>=80){
						beacon_type=1;	//433M
						send_beacon.step =STEP_SEND_BASIC_BEACON;
					}
				}				
				break;
								
			default:break;
		}//sw
}


//---------------------------------------------------------------------
/*
基站发送信标的开关,
某些功能需要关闭 基站发送信标
基站读取基础参数后再开启发送信标
*/
void base_send_beacon_switch(unsigned char sw)
{
		send_beacon.step =sw;	
}

unsigned char get_base_send_beacon_status(void)
{
	return send_beacon.step;
}


#endif //RF_5G8


