/*
广播数据（信标）
基站协议V0.95 section2.3设置发信息信标
键盘协议V0.99-11 section 2.4 广播信息信标
*/
#include "base_core_user.h"
#include "string.h"
#include "function.h"
#include "function_interface.h"

#define 	SLOT_MAX  	255//128	//Max is 0xff from protocol!!

struct content_STR{
	//2.3.2发送的内容
	unsigned char dcmd;
	unsigned char slotmax;
//	unsigned char slotn;
	unsigned char data[SLOT_MAX][16];	//128,Max=0xff
};

struct broadcast_STR{
	//2.3.1发送参数
	unsigned char type;
	unsigned char times;
	unsigned char slots; 	
	
	//2.3.2发送的内容
	struct content_STR content[2];
	
	//2.3.3启动发送和结果
	unsigned char id_sn_broad;
	unsigned char id_sn[6];
	unsigned char startup_dcmd;
	
	//user var
	unsigned char on_off_flag;
	unsigned char execute_times;
	unsigned char slot_seq;
	unsigned char cur_type;
	
	//keypad request
	unsigned char keypad_request_step;
	
	unsigned char data_pos;
};
struct broadcast_STR broadcast={
	.data_pos =0,
	
};


/* --------------------------------------------------------
基站保存来自sdk的广播数据
*/
void broadcast_config(const unsigned char *rx_pc)
{
		unsigned char type;//题型
//		unsigned char ack_flag=1;
		unsigned char ack_buf[20]={1};
		unsigned char ack_buf_len=1;	
	
		switch(rx_pc[3]){
			case 11:
				memcpy(&broadcast.type,rx_pc+4,3);
				break;
			
			case 12:
				//20200811,增加sdk从基站读回题型数据。基站部分V0.96 section2.3.2
				//if( (rx_pc[4] !=1) && (rx_pc[4] !=2) ) break;
				if( (rx_pc[4] ==1) || (rx_pc[4] ==2) )
				{
					if( rx_pc[6] >=SLOT_MAX) break;//防止数组溢出
					type=rx_pc[4]-1;
					broadcast.content[type].dcmd = rx_pc[4];
                    broadcast.cur_type =type;
					broadcast.content[type].slotmax =rx_pc[5];			
					memcpy(&broadcast.content[type].data[rx_pc[6]] ,rx_pc+7,16);
				}
				else if(rx_pc[4] &0x80){	//sdk读题型数据
					if( rx_pc[6] >=SLOT_MAX) break;//防止数组溢出
					type=(rx_pc[4]&~0x80) -1;
					ack_buf[1] =broadcast.content[type].slotmax;	//byte5
					ack_buf[2] =rx_pc[6];
					memcpy(ack_buf+3,&broadcast.content[type].data[rx_pc[6]] ,16);
					ack_buf_len =19;
				}
				break;			
			
			case 13:
				memcpy(&broadcast.id_sn_broad,rx_pc+4,8);
				break;			
			
			default:ack_buf_len=0;break;
		}//sw
		if(ack_buf_len)
		user__pc_cmd_ack(0x60,rx_pc[3],ack_buf,ack_buf_len);
}

//unsigned char broad_cast_cnt;

/*---------------------------------------------
发送广播信标子函数
input:
	type -题型
	seq  -数据包号
*/
static void base_broadcast_sub(unsigned char type,unsigned char seq)
{
		unsigned char tmp[32+1];
		tmp[0] = 32;//31;
		base_core.get_match_code(tmp+1);

		tmp[5] = ( base_core.get_log_mode() <=3)?0x31:0x32; //id or SN
	
		tmp[6] = 0x00;
		tmp[7] = 0x00;
		//byte8-11 Keypad SN
	
//		tmp[12] = broadcast.content[type].dcmd | (broadcast.data_pos <<4); //DCMD,High 4bit is datapos
		tmp[12] = (broadcast.content[type].dcmd&0x0f) | (base_core.get_vote_datapos() <<4); //DCMD,High 4bit is datapos
		tmp[13] = 0;
		tmp[14] =broadcast.content[type].slotmax ;//slotMax
		tmp[15] = seq;	//broadcast.content[type].slotn	; //slot_seq
		memcpy(tmp+16,broadcast.content[type].data[seq],16);
		tmp[32] =crc16(tmp+5,27)&0xff;	//CRC	
	
//broad_cast_cnt++;
#ifdef _DEBUG_CORE_
        SEGGER_RTT_printf(0,"pd:%02x,seq:%d\n",tmp[12],tmp[15]);
#endif
		base_core.send_rf_data(tmp,base_core.get_mainRF_hard_id());
}


/*
启动广播的条件
a,监测到 测验题-多题型; 表决器V0.99-11 section2.2.13
b,接收到 键盘没有收齐数据的 请求; 教育新版-表决器V0.99-11 section3.2.6
*/
void startup_broadcast(void)
{
		if( !function.BROADCAST__SW) return;
		if(broadcast.on_off_flag==1) return;	//如果正在进行广播信息，就不要再启动了!!!!
		base_core.switch_send_beacon(0);// turn off send beacon
		broadcast.data_pos++;
		broadcast.on_off_flag =1;
		broadcast.execute_times = 0;
		broadcast.slot_seq =0;	
//		broadcast.cur_type =0;//由进入的模式决定debug only
}

/*
//2021.05.10 客诉描述：多题型模式下，重新拔插基站后导致键盘无法开机--其实是键盘显示白屏;
原因：多题型模式下，题型内容不保存，拔插基站后题型内容丢失;但是还是在多题型模式下。
解决办法：在开始广播多题型时，增加判断是否存在题型内容；如果没有就强制退出并切换到空闲模式下。
*/
unsigned char det_blank_content(void)
{
	if( (broadcast.content[0].slotmax==0) &&(broadcast.content[1].slotmax==0)   ){
		//force exit multi content,exit sysmode0;
		broadcast.on_off_flag =0;
		base_core.force_sysmode0();
		base_core.switch_send_beacon(1);
		
		return 1;
	}
	return 0;
}


/*----------------------------------------------------------
* 特殊处理 来自键盘的“广播信息不完整”的请求;
* 基站收到键盘请求后,需要按正常周期给键盘ack，然后才开始启动广播发送；
* 当然如果当前正在发广播信号，就不必再启动发送了！！
*具体做法：在发送基础/投票信标时(此时基站一定是已经发送了对键盘请求的ack)判断是如果收到了键盘请求，就开启广播模式;
* input:request =1 ,接收键盘申请输入参数;other:startup
* return
*/
unsigned char process_keypad_broadcast_requst(unsigned char request)
{
	if( !function.BROADCAST__SW) return 0;
	
	if( request ==1){
		if(det_blank_content() )	return 0;
		broadcast.keypad_request_step = request;
	}
	else{
		if(broadcast.keypad_request_step){
			broadcast.keypad_request_step=0;
			startup_broadcast();
			return 1;
		}
	}	
	return 0;
}







unsigned char led_cnt;//debug only
/*
called by 2.5ms and turn off  send beacon!!
*/
void base_broadcast_process_2ms5(void)
{
		if( !function.BROADCAST__SW) return;
		if( !broadcast.on_off_flag) return;
		if(broadcast.slot_seq >= SLOT_MAX) return;
		
		base_broadcast_sub(broadcast.cur_type,broadcast.slot_seq);
		
//		if(++led_cnt>=3){//debug only
//			led_cnt=0;
//			operation_debug_io(5);//debug only
//		}
			
		if(++broadcast.slot_seq >= broadcast.content[broadcast.cur_type].slotmax ){
			//发送完一个周期了;
			broadcast.slot_seq =0;
			if(++broadcast.execute_times >=10){
				broadcast.on_off_flag=0;	
				base_core.switch_send_beacon(1);
			}			
		}
}


