
#include "base_core_user.h"
#include "base_core.h"
#include "platform_interface.h"
#include "base_pc_protocol.h"
#include "function_interface.h"

#ifdef 	RF_5G8

unsigned char Send_beacon_kyepad_nub=0;   //add by Daiyu 标志大周期计数 让键盘知道
/*
2019.12.04 实测 delay(500) =500us;
环境：主频168MHz,关闭中断,IO取反用示波器测试!!	
由于GPIO无法响应 delayus(1)，所以实际测试delay(500) =500us	*/
static void _5G8_delay_us( unsigned short time )
{
    unsigned short i = 0;
    while( time-- ){
			i = 30; 
			while( i-- ) ;
    }
}


/*
*基站发送投票信标
*Warning !!! 特别注意：此处id是模块硬件id,不是内核重新编的号码!!!
*/
static void base_load_vote_beacon(unsigned char timers,unsigned char id)
{
	unsigned char i;
	unsigned char tmp[64+1];
	
	keypad_idsn_clear();	

	tmp[0] =64;//28; //len
	base_core.get_match_code(tmp+1);//tmp1-4
	tmp[5] =0x17;//(log_mode_is_ID)?0x13:0x14; //vote beacon		
	tmp[6] =basic_beacon.nowT[0]; //nowT
	tmp[7] =basic_beacon.nowT[1];
	// #ifdef VOTE_BEACON_64BYTE
	// mem_cpy(&vote_beacon.head_addr+1,tmp+8,55);	//special!!!!!!!Gavin20200204
	// #else
	mem_cpy(&vote_beacon.head_addr+1,tmp+8,VOTE_BEACON_LEN);	
	// #endif
	
	
	mem_cpy(&basic_beacon_crs2.head_addr+1,tmp+29,BASIC_BEACON_CRS2_LEN);
//	tmp[29] =basic_beacon_crs2.crs2_attrib[0]| (get_base_log_mode()==5);
	tmp[29] =basic_beacon_crs2.crs2_attrib[0]| (base_core.get_log_mode()==5);
	tmp[30] =basic_beacon_crs2.crs2_attrib[1];
	tmp[31] =base_core.get_main_rf_chan();//get_base_main_rfchannel();// 
	tmp[32] =basic_beacon_crs2.crs2_attrib[3];
	
	
	
	for(i=0;i<timers;i++){
		platform.rf_5G8_load_send_data(tmp+1,64,id);
		_5G8_delay_us(50);//delay_us1(50);
	}
}


/*
基站发送确认信标
*Warning !!! 特别注意：此处id是模块硬件id,不是内核重新编的号码!!!
*/
static void base_load_confirm_beacon(unsigned char timers,unsigned char id)
{
	unsigned char tmp[64+1];
	unsigned char i,rfid=0;
	mem_set(tmp,sizeof(tmp)/sizeof(unsigned char),0);
	
	tmp[0] =64;
	base_core.get_match_code(tmp+1);	
	tmp[5] =0x19;
	tmp[6] =0;
	tmp[7] =0;

	//reverse transfer to core rfid
	for(i=0;i<multi.count;i++){
		if( id == multi.modual_id[i]){
			rfid =i; //get core rf_id
			break;
		}
	}
	for(i=0;i<10;i++){//tmp[8]...
		#if (MULTI_5G8==1)
		mem_cpy(multi.multi_idsn[rfid].idsn[i],tmp+8+5*i,5); 	//2021.02.21 修改成非固定的，适配多模块
		#else
		mem_cpy(multi.multi_idsn[0].idsn[i],tmp+8+5*i,5); //此处id 固件为0--T2只有一个模块
		#endif
		#ifdef _DBG_VOICE_KP
		_debug_voice_kp__ack_keypad(multi.multi_idsn[0].idsn[i]);
		#endif 
	}
	
	for(i=0;i<timers;i++){	
		platform.rf_5G8_load_send_data(tmp+1,64,id);
		_5G8_delay_us(50);//
	}
//2019.12.26 调试CRS200发现多个模块时波形异常	
//	for(j=0;j<multi.count;j++){	
//		for(i=0;i<10;i++)//tmp[8]...
//			mem_cpy(multi.multi_idsn[j].idsn[i],tmp+8+5*i,5);
//		
//		for(i=0;i<timers;i++){
//			platform.rf_5G8_load_send_data(tmp+1,64,multi.modual_id[j]);
//		_5G8_delay_us(50);//			delay_us1(50);
//		}
//	}//for
}



/*
基站发送语音信标,包括重发
input : 要发送的键盘信息 
* Warning !!! 特别注意：此处id是模块硬件id,不是内核重新编的号码!!!
*/
static void base_load_voice_beacon(const unsigned char *key_info,unsigned char id)
{
	unsigned char tmp[64+1];
	unsigned short crc;
	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] = 0x11;
	mem_cpy(key_info,tmp+13,50);	
	
	//特殊处理转发，强制插入到第一个位置；
	spec_trans__load_sn(tmp+13);
//	//第一次
//	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,multi.modual_id[get_mainRF_usr_id()]);
//	_5G8_delay_us(50);//	delay_us1(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,multi.modual_id[get_mainRF_usr_id()]);//A5130_send_buf(tmp,64);
//	_5G8_delay_us(50);//	delay_us1(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,multi.modual_id[get_mainRF_usr_id()]);//A5130_send_buf(tmp,64);

	tmp[7]=  Send_beacon_kyepad_nub;          // 标志大周期的次数 
	//第一次
	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,id);
	_5G8_delay_us(150);//_5G8_delay_us(200);//	delay_us1(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,id);
	//_5G8_delay_us(50);//	delay_us1(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,id);
}


/*
7帧数据集中发送，节省切换时间
Warning !!! 特别注意：此处id是模块硬件id,不是内核重新编的号码!!!
*/
static void base_send_beacon_all(const unsigned char *info,unsigned char id)
{
	#ifdef KEYPAD60 //60路语音时不发ack 
	if(vote_beacon.sys_mode !=16)
	#endif	
	base_load_confirm_beacon(2,id);					//confirm beacon 2
	
	if( pc_transfer2keypad_data_fetch()){//pc transfer to keypad 

	}
	else{
		#ifdef KEYPAD60 //60路语音时不发ack 
		if(vote_beacon.sys_mode ==16)
			base_load_vote_beacon(1,id);
		else
		#endif		
		base_load_vote_beacon(2,id);								//vote beacon 2
	}
	
	base_load_voice_beacon(info,id);	//voice beacon 3	
}

/*
重发时，调用此函数，区别于正常数据帧，只是为了调试好看波形;
5帧数据集中发送，节省切换时间
Warning !!! 特别注意：此处id是模块硬件id,不是内核重新编的号码!!!
*/
static void base_send_beacon_all_2(const unsigned char *info,unsigned char id)
{
	#ifdef KEYPAD60 //60路语音时不发ack 
	if(vote_beacon.sys_mode !=16)
	#endif
	base_load_confirm_beacon(1,id);					//confirm beacon 2
	
	if( pc_transfer2keypad_data_fetch()){

	}
	else	
		base_load_vote_beacon(1,id);								//vote beacon 2
	
	base_load_voice_beacon(info,id);	//voice beacon 3	 
}



/*
*此函数仅仅是为了封装成base_send_beacon_all 一致，便于调用  platform.rf_5G8_send_multi_frame
用于副模块发送多个ack 
如果是发送一个ack可以用 base_send_confirm_beacon_direct函数
*/
static void base_send_ack_only(const unsigned char *info,unsigned char id)
{
	base_load_confirm_beacon(2,id);					//confirm beacon 2

}


/*
基站直接直接....发送确认信标 ,与上述函数的区别是调用一个完整的发送函数 ！！！
*Warning !!! 特别注意：此处id是模块硬件id,不是内核重新编的号码!!!
//2020.02.27 add by Gavin
*/
//static void base_send_confirm_beacon_direct(unsigned char timers,unsigned char id)
//{
//	unsigned char tmp[64+1];
//	unsigned char i;
//	mem_set(tmp,sizeof(tmp)/sizeof(unsigned char),0);
//	
//	tmp[0] =64;
//	base_core.get_match_code(tmp+1);	
//	tmp[5] =0x19;
//	tmp[6] =0;
//	tmp[7] =0;

//	
//	for(i=0;i<10;i++){//tmp[8]...
//		mem_cpy(multi.multi_idsn[0].idsn[i],tmp+8+5*i,5); //此处id 固件为0--T2只有一个模块
//	}
//	
//	for(i=0;i<timers;i++){
//		platform.rf_send_data(tmp+1,64,id);
//		//platform.rf_5G8_load_send_data(tmp+1,64,id);
//		_5G8_delay_us(50);//
//	}

//}
#include 	"string.h"
#ifdef BUF_ALERT2
extern void TIM4_SetT(unsigned char mode);
//发单独点名包 this function des by Pei
//20210221,Gavin 修改函数输入参数，解除编译器警报
void base_send_beacon_getbuf(const unsigned char *info_null,unsigned char id)
{	struct link_node_STR *node;
	unsigned char info[64];
	memset(info,0,64);
	info[0] =64;
	base_core.get_match_code(info+1);	
	info[5] = 0x15;//单独点名
	info[6] =1;
	memcpy(info+13,buf_get_info.SN,4);
	node =link_queue_find_special_sn(&keypad_info,buf_get_info.SN);
	if( node!=NULL)
		{
			info[17]=node->element.re_send_slot;
			node->element.re_send_slot=0xFF;//!!否则点名键盘会丢包

		}

	platform.rf_5G8_load_send_data(info+1,64,id);

}

#endif













struct send_beacon_STR{
	unsigned char step;
	unsigned char remain_cycle_count; //一个大周期内传输的次数，语音+重传 = TRANSFER_CYCLE_MAX
	unsigned char ask_offset;				//当前点名在 SN list中的偏移;
	unsigned char re_send_offset;		//当前重传在 SN list中的偏移
};
static struct send_beacon_STR send_beacon={
	.step=1,
	.remain_cycle_count=0,
	.ask_offset=0,
	.re_send_offset=0,
};

//用于过滤语音基站心跳包的参数，
#define 	SEND_BEACON_INIT					1
#define 	SEND_BEACON_VOICE					2
#define 	SEND_BEACON_RE_SEND_INIT	3
#define 	SEND_BEACON_RE_SEND				4
#define 	SEND_BEACON_RE_SEND_BLANK				5
#define 	SEND_BEACON_ALERT					6

/* -----------------------------------------------
发送信标 总入口函数
called by timer2.5ms isr*/
void base_tx_keypad_beacon(void)
{	unsigned char tx_buf[64];
	
		#ifndef KEYPAD60
		static unsigned char beancon_count=0;		
		if(++beancon_count <13)	return; //2.5msx13 = 32.5ms!
		beancon_count=0;
		#endif
	
		if(function.updatekp__SW ){
			function.update__kp_progress();
		}	
	
		//154*32.5 =5S
//		link_queue_check_online(&keypad_info);//每个大周期开始时才更新键盘在线/离线 状态	
		
		
		switch(send_beacon.step){
			case 0:break;
			
			case SEND_BEACON_INIT://初始化
		_init_send_beacon:	
				Send_beacon_kyepad_nub++;   // 大周期自增	
				send_beacon.ask_offset=0;
				send_beacon.remain_cycle_count =TRANSFER_CYCLE_MAX;				
				link_queue_check_online(&keypad_info);//每个大周期开始时才更新键盘在线/离线 状态	
				kernel.keypad_online_cnt =get_link_queue_length(&keypad_info);//get_keypad_count();
				#ifdef BUF_ALERT2
					buf_get_info.ResendT=0;
					buf_get_info.Status=0;//!!
				#endif 
			case SEND_BEACON_VOICE:	//点名
				if(send_beacon.remain_cycle_count==0){ //没有发送周期(应该不存在此情况)
					goto _init_send_beacon;//send_beacon.step =SEND_BEACON_INIT;
				}
				else{
					//unsigned char tx_buf[64];
					mem_set(tx_buf,64,0);	//mem_set(tx_buf,sizeof(tx_buf)/sizeof(unsigned char),0);	
					#if  (MULTI_5G8==1)
					multi_chan_polling();
					#endif
					send_beacon.remain_cycle_count--;
					send_beacon.ask_offset =link_queue_outN(&keypad_info,tx_buf,send_beacon.ask_offset);//从SN list中取出SN；一次最多10个
					platform.rf_5G8_send_multi_frame(base_send_beacon_all,tx_buf,multi.modual_id[get_mainRF_usr_id()]);			//主模块的id=0?	

					if(multi.count>1){//2020.02.27 add by Gavin 
						unsigned char i;
						for(i=1;i<multi.count;i++){
							if(i ==multi.whitelist_index) continue; //白名单模块不用回复ack；
							platform.rf_5G8_send_multi_frame(base_send_ack_only,tx_buf,multi.modual_id[i]);							
							//base_send_confirm_beacon_direct(2,multi.modual_id[i]);
						}
					}
				}
				
				kernel.permit_display_flag=1;
					
				if( send_beacon.ask_offset ==0 ){					
					send_beacon.step = SEND_BEACON_RE_SEND_INIT;	//点名完毕					
				}
				else
					send_beacon.step = SEND_BEACON_VOICE;		//点名继续					
				break;
					
			case SEND_BEACON_RE_SEND_INIT:	//可以重传了！			
				if(link_queue_check_re_send(&keypad_info,0) ==0){ //没有需要重传的; 回到大周期重新开始新一轮
					#ifdef VOICE_PROTOCOL_3RD//直接重新点名
					  send_beacon.step=SEND_BEACON_INIT;
					  goto _init_send_beacon;					
					#else					
					#ifdef KEYPAD60
					if(vote_beacon.sys_mode ==16)//  ó?ò??￡ê?????óD??′?????ò?????′?
						goto goto__beacon_re_send_blank;
					else
					#endif
						goto _init_send_beacon;	
					#endif	
				}
				else{
					//进入重传，初始化参数
					send_beacon.re_send_offset =0;
					send_beacon.step = SEND_BEACON_RE_SEND;
				}		
			
			case SEND_BEACON_RE_SEND:
				/*20200226 相比以前的重传逻辑(最多一次重传机会)，修改后的重传逻辑是：
				 可以多次重传,只要还有重传周期；
				*/
				if(link_queue_check_re_send(&keypad_info,0) ==0){
					#ifdef BUF_ALERT2
					if (	buf_get_info.Status==1)//优化成可处理重传中出现过告警的
					{
						//sn=(buf_get_info.SN[0]<<24)+(buf_get_info.SN[1]<<16)+(buf_get_info.SN[2]<<8)+(buf_get_info.SN[3]);
						//DEBUG_LOG("SN[%10d] Buf Alert!-PreSET2- Start...\n",sn);
						send_beacon.step=SEND_BEACON_ALERT;
						goto _send_buf_alert;
					}
					else
					#endif
					goto _init_send_beacon;
				}
			
				if(send_beacon.remain_cycle_count>0){//发送重传
						unsigned char tx_buf[64];
						mem_set(tx_buf,64,0);//mem_set(tx_buf,sizeof(tx_buf)/sizeof(unsigned char),0);	
						#if  (MULTI_5G8==1)
						multi_chan_polling();
						#endif					
						send_beacon.remain_cycle_count--;						
						send_beacon.re_send_offset =link_queue_outN_re_send(&keypad_info,tx_buf,send_beacon.re_send_offset);
						platform.rf_5G8_send_multi_frame(base_send_beacon_all_2,tx_buf,multi.modual_id[get_mainRF_usr_id()]);	//主模块的id=0?							
				}								
				//没有重传数据 或者 没有重传周期了，都回到大周期 ！
//				if( (send_beacon.re_send_offset==0)||(send_beacon.remain_cycle_count==0) ){	
//					send_beacon.step = SEND_BEACON_INIT; //重传完毕或者没有重传周期了,回到大周期
//				}				
				else{	
					#ifdef BUF_ALERT2
					//判断有无键盘buf告警需要单独点名
					extern unsigned char check_buf_alert(struct link_queue_STR *queue,unsigned char offset);
					if (	buf_get_info.Status==1)//优化成可处理重传中出现过告警的
					{
						//sn=(buf_get_info.SN[0]<<24)+(buf_get_info.SN[1]<<16)+(buf_get_info.SN[2]<<8)+(buf_get_info.SN[3]);
						//DEBUG_LOG("SN[%10d] Buf Alert!-PreSET- Start...\n",sn);
						send_beacon.step=SEND_BEACON_ALERT;
						goto _send_buf_alert;
					}
					if (check_buf_alert(&keypad_info,0))
					{
						send_beacon.step=SEND_BEACON_ALERT;
						goto _send_buf_alert;
					}
					#endif
					goto _init_send_beacon;	//send_beacon.step = SEND_BEACON_INIT; //重传完毕或者没有重传周期了,回到大周期
				}				
				
				break;
			
			#if defined(KEYPAD60)&& !defined(VOICE_PROTOCOL_3RD)//#ifdef KEYPAD60
			case SEND_BEACON_RE_SEND_BLANK:
				goto__beacon_re_send_blank:
				if(send_beacon.remain_cycle_count>0){//发送重传
						unsigned char tx_buf[64];
						mem_set(tx_buf,sizeof(tx_buf)/sizeof(unsigned char),0);	
					
						send_beacon.remain_cycle_count--;						
						//send_beacon.re_send_offset =link_queue_outN_re_send(&keypad_info,tx_buf,send_beacon.re_send_offset);
						platform.rf_5G8_send_multi_frame(base_send_beacon_all_2,tx_buf,multi.modual_id[get_mainRF_usr_id()]);	//主模块的id=0?							
				}				
				
//				//没有重传数据 或者 没有重传周期了，都回到大周期 ！
//				if( (send_beacon.re_send_offset==0)||(send_beacon.remain_cycle_count==0) ){	
					send_beacon.step = SEND_BEACON_INIT; //重传完毕或者没有重传周期了,回到大周期
//				}				
			break;
			#endif 

#ifdef BUF_ALERT2
				//键盘buf告警需要单独点名
		case SEND_BEACON_ALERT:
			_send_buf_alert:
				if (buf_get_info.GetT<BUF_GET_T)
				{
					buf_get_info.GetT++;					
					#if  (MULTI_5G8==1)
					multi_chan_polling();
					#endif										
					#ifndef T2_2CH
					platform.rf_5G8_send_multi_frame(base_send_beacon_getbuf,tx_buf,multi.modual_id[get_mainRF_usr_id()]);
					#else
					rf_chan_switch_proc();
					platform.rf_5G8_send_multi_frame(base_send_beacon_getbuf,tx_buf,multi.modual_id[now_chan]);
					#endif
					//定时器改
					TIM4_SetT(1);
					//DEBUG_MSG(">");
				}
				else
				{
					buf_get_info.Status=0;
					TIM4_SetT(0);//定时器改回标准
					//DEBUG_MSG("!\n");
					#if 1
						send_beacon.step=SEND_BEACON_INIT;
						goto _init_send_beacon;	
					#else
						send_beacon.step=SEND_BEACON_RE_SEND_INIT;
						goto re_send_init;	
					#endif
				}
				break;
		#endif
				
			default:break;
		}//sw
}



/*
获取在线键盘的个数*/
unsigned char get_keypad_count(void)
{
	return get_link_queue_length(&keypad_info);	//keypad_info.rear-keypad_info.front;
}



/*
发送信标的开关，比如在键盘固件升级的时候就需要关闭信标发送 */
void base_send_beacon_switch(unsigned char sw)
{
	send_beacon.step =sw;
}

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



//----------------------------------------------------------------
/*
* 2020.12.01 测试发现by Pei: 指定姓名下发，键盘必须等到点名才能回复，导致响应慢；
*解决办法：记下指定的键盘SN,在下一次点名中强制加入此键盘SN
*/
struct special_trans_STR
{
	unsigned char flag;
	unsigned char spec_sn[4];

	unsigned char load_spec_sn_flag; //用于外部，禁止NFC和LCD
};
static struct special_trans_STR spec_trans;

//record 
void spec_trans__record_sn(unsigned char *trans)
{
	//单包，并且是指定SN 模式
	if( (trans[5]==0x30)&&(trans[6]==0xff)&&(trans[7]==0xff)  ){
		spec_trans.flag =1;
		mem_cpy(trans+25,spec_trans.spec_sn,4);
	}
}


void spec_trans__load_sn(unsigned char *start)
{
	struct link_node_STR *node=NULL;

	if(spec_trans.flag==0)	return;
	spec_trans.flag =0;
	spec_trans.load_spec_sn_flag =1;	//

	mem_cpy(spec_trans.spec_sn,start,4);

	if( (node =link_queue_find_special_sn(&keypad_info, start)) !=NULL){
		start[4] = node->element.re_send_slot;
	}
	else
		start[4] = 0xff;		
}


#endif 

