/*
-------------------------------------------------------------------
							基站频点说明													|	SDK	| E2prom
--------------------------------------------------------------------
a,	单频点 base_config.chan												  | YES	| YES
--------------------------------------------------------------------
b,	多频点 multi_freq_setup.chan_freq and chan_count|	YES	| YES
--------------------------------------------------------------------
c,  多频点 multi.modual_chan and count						  | NO 	| NO 
--------------------------------------------------------------------

各个频点的处理:
1, 上电后首先从E2prom中读取单频点信息 base_config.chan
2，然后从E2prom中读取多频点信息 multi_freq_setup
3, 在无线模块初始时，复制multi_freq_setup 到 multi 然后设置频点到无线模块 setup_multi_info
3，sdk设置单频点后 process_setup_single_chan
4，sdk设置多频点后 process_setup_multi_chan
*/

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

struct multi_modual_STR multi;

/*
2019.12.04 实测1ms;
环境：主频168MHz,关闭中断,IO取反用示波器测试!!	*/
static void e2prom_write_delay_ms( unsigned short  time )
{
    unsigned short  i = 0;
    while( time-- ){
			i = 33400;
			while( i-- );
    }
}


//-------------------------- multi 相关函数 -----------------------------------
/*获取主频点 内部记录数组下标，作为multi.modual_id的下标 表示主模块的硬件标号
固定在[0]的位置*/
unsigned char get_mainRF_usr_id(void)
{
	return 0;
//	return multi.main_index;
}

/*
获取 主频点对应的硬件编号！！！！,		*/
unsigned char get_main_rf_hard_id(void)
{
	return multi.modual_id[0];
	//return multi.modual_id[multi.main_index];	
}


/*获取主频点*/
unsigned char get_base_main_rfchannel(void)
{	
	return multi.modual_chan[0];
	//return multi.modual_chan[multi.main_index];
}


/*获取白名单模块编号*/
unsigned char get_whitelist_rfid(void)
{
	return multi.modual_id[multi.whitelist_index];
}



/*
将协议中的多频点复制到内核中的多频点参数中,然后设置到无线模块中
为便于内核对多频点的管理，没有直接使用协议中定义的 multi_freq_setup
而是使用自定义的multi !!!*/
static void setup_multi_info(void)	
{
		unsigned char i;
	
//		if(function.match_keypad_type ==KP_E11_V010){
//		multi.count =multi_freq_setup.chan_count;	
//		mem_cpy(multi_freq_setup.chan_freq,multi.modual_chan,4);	//copy channel
//		}
//		else {
		multi.count =multi_freq_setup.chan_count;
		mem_set(multi.modual_chan,4,0);
		//}

		mem_cpy(multi_freq_setup.chan_freq,multi.modual_chan,multi.count);	//copy channel
		
	
			/* 特别设置白名单模块的频点 为0*/
		if(multi.whitelist_index <multi.count) {//如果有白名单模块,固定0 频点
			multi.modual_chan[multi.whitelist_index] =0; 
		}
		//所有模块都要初始化!!包括白名单模块
		for(i=0;i<multi.hard_rf_modual_cnt;i++){
			platform.rf_set_freq(multi.modual_chan[i],multi.modual_id[i]); //base_set_rf_freq(i);
		}	
}


/*
+8不超过最大频点数	*/
static unsigned char calc_next_multi_chan(unsigned char cur)
{
	unsigned char tmp;
	if( (tmp= cur+8)>function.rf_channel_max)
		return 1;
	else
		return tmp;
}

/*
通过单频点关联多频点,不关联有效频点个数*/
void single_relevant_to_multi_chan(unsigned char single_chan)
{
	multi_freq_setup.chan_freq[0] = single_chan;
	multi_freq_setup.chan_freq[1] =calc_next_multi_chan(multi_freq_setup.chan_freq[0]);	
	multi_freq_setup.chan_freq[2] =calc_next_multi_chan(multi_freq_setup.chan_freq[1]);	
	multi_freq_setup.chan_freq[3] =calc_next_multi_chan(multi_freq_setup.chan_freq[2]);
}



/*
设置多频点时的处理： called by pc设置单模块操作时
	a 同步到多频点
	b 复制到内核multi变量
	c E2prom保存两个频点*/
void process_setup_single_chan(unsigned char single_rf)
{
	single_relevant_to_multi_chan(single_rf);
	setup_multi_info();	
	//更新后保存主频点，考虑到接着会保存单模块频点，所以做延时
	base_write_e2prom(STORE_MULTI_CHAN_ADDR,&multi_freq_setup.head_addr+1,MULTI_FREQ_LEN);
	e2prom_write_delay_ms(10);
	base_config.chan = single_rf; //add by Gavin20200807 频点冲突，找到新频点后无法同步更新
	base_write_e2prom(STORE_BASE_CONFIG_ADDR,&base_config.head_addr+1,BASE_CONFIG_LEN);
}

/*
设置多频点时的处理： called by multi setup 
	a 同步到单频点
	b 复制到内核multi变量
	c E2prom保存两个频点*/
void process_setup_multi_chan(unsigned char multi_freq)
{	
	base_config.chan = multi_freq; 
	setup_multi_info();	
	//更新后保存主频点，考虑到接着会保存单模块频点，所以做延时
	base_write_e2prom(STORE_MULTI_CHAN_ADDR,&multi_freq_setup.head_addr+1,MULTI_FREQ_LEN);
	e2prom_write_delay_ms(10);
	base_write_e2prom(STORE_BASE_CONFIG_ADDR,&base_config.head_addr+1,BASE_CONFIG_LEN);	
}




/*
根据用户配置，计算无线模块个数
将硬件的排序转换成自己的顺序
called by base core init	*/
void multi_chan_init(void)
{
	unsigned char i,id=1;//
	multi.hard_rf_modual_cnt =0;
	
	/*1，清空内核多频点记录数组，
	然后计算funcion 设置的无线模块个数rf_count -必须与硬件实际焊接模块个数一样，否则可能会影响正常模块通信*/
	for(i=0;i<4;i++){ 
		multi.modual_id[i] =0xff;//init is 0xff
		if((function.rf_id[i]==0xff)||(function.rf_id[i]==0xfe)||(function.rf_id[i]==0xfb) )
			multi.hard_rf_modual_cnt++;
	}//for
	
	multi.whitelist_index =0xff;	
	//c, record the function of the rf modual 
	for(i=0;i<4;i++){//用户设置的硬件编号0-3放在multi.modual_id[]中
		switch(function.rf_id[i]){
			case 0xff://主模块编号指定写在[0];				
				multi.modual_id[0] =i;
				multi.main_index =0;	//预留，目前，主频点固定在0
				break;
			case 0xfe://副模块从[1]开始id=1;
				multi.modual_id[id++] =i;
				break;
			case 0xfb://白名单模块在最后一个,
				multi.whitelist_index =id;
				multi.modual_id[id++] =i;				
				break;
			
			default:
				//multi.modual_id[i] =0xff;
			break;
		}//sw			
	}//for	

	for(i=0;i<multi.hard_rf_modual_cnt;i++)	//根据id初始化无线模块
		platform.rf_init(multi.modual_id[i]); 

	//sdk设置的无线模块个数不能大于硬件实际模块个数
	if(multi_freq_setup.chan_count >multi.hard_rf_modual_cnt)
		multi_freq_setup.chan_count =	multi.hard_rf_modual_cnt;
	
	//频点信息写入到各个无线模块
	setup_multi_info();	
	if(kernel.custom_rf_sync_code)
		platform.rf_update_sync_code( kernel.custom_rf_sync_code,4,get_main_rf_hard_id());	
}



/*
根据来自中断的模块序号查询自己在 modual_id[]中的index
return :查询到了就直接返回序号
0xff -没有在表格中查询到。
called by rx keypad data */
unsigned char conver_id(unsigned char hard_id)
{
	unsigned char i;
	//涉及 副模块也发信标和频点频点轮转;
	for(i=0;i<multi.hard_rf_modual_cnt;i++)
		if(multi.modual_id[i] ==hard_id) return i;
	return 0xff;
}


/*
多模块切换，模拟天线摇晃效果，必须保证核心的rf缓冲区为空(都处理完了)
保持multi.modual_freq[]不变
循环multi.modual_id[] */
void multi_chan_polling(void)
{
	static unsigned char switch_cycle_cnt;
	unsigned char i,tmp;
	#ifdef 	RF_MODUAL_5G8_MONITOR
	rf_modual_5G8__check();
	#endif
	if(multi.hard_rf_modual_cnt<=1)	return;
	if(function.fastmatch__get_status() ) return;	//20210415 快速配对模式下不polling
	if(++switch_cycle_cnt <10) return;//	if(++switch_cycle_cnt <36) return;
	switch_cycle_cnt =0;
	
	rf_modual__check();

	tmp = multi.modual_id[0];
	for(i=0;i<multi.hard_rf_modual_cnt-1;i++)
		multi.modual_id[i] =multi.modual_id[i+1];
	multi.modual_id[multi.hard_rf_modual_cnt-1] = tmp;
	
	//修改后重新设置所有模块无线模块;
	for(i=0;i<multi.hard_rf_modual_cnt;i++)
		platform.rf_set_freq(multi.modual_chan[i],multi.modual_id[i]);
}





/*---------------------- 2.4G 模块监测 ----------------------------------
* 监测模块发送信标的次数;和在此期间发送的发送中断的次数做比对。
* 
*/
struct rf_modual_STR
{
#define 	THRESHOLD_RF_CNT	5
#define 	RF_FAIL_CNT			8
	unsigned char tx_cnt;
	unsigned char tx_interrupt_cnt;
	unsigned char failure;
	
	unsigned short error_cnt;
};
volatile struct rf_modual_STR rf_modual[4+1]; //模块从1开始，最大4个


//-------------------- 告警处理 20210415--------------------------------


struct rf_error_STR
{
	unsigned char state;
	unsigned int timer_cnt;
};
static struct rf_error_STR rf_error={
	.state =0,
	.timer_cnt =0,
};

//
static void get_error_info(unsigned char *err)
{
	unsigned char i,id,cnt=0;
	for(i=0;i<multi.hard_rf_modual_cnt;i++){
		id = multi.modual_id[i];
		if(rf_modual[id].failure >RF_FAIL_CNT){			
			err[1+cnt] =i+1; //start from 1
			cnt +=1;
		}
	}//for
	err[0] = cnt;
}

static void rf_error_ack_pc(void)
{
		unsigned char tmp[64]; //whitelist 需要的buf长些
		mem_set(tmp,sizeof(tmp)/sizeof(tmp[0]),0);
		tmp[0]= 31;
		tmp[1]= 0xE1;
		tmp[2]= base_core.get_id();//
		tmp[3]= 10;//type;
		tmp[4]= 6; //
		get_error_info(tmp+5);
		//memcpy( tmp+4,ack_buf,type_data_len);	
		//send to pc 
		base_core.send_data_to_pc(tmp);
}

//called by 20ms 
void rf_error_warning(void)
{
	if(rf_error.state != 1) return;

	if(++rf_error.timer_cnt < 1500){	//20ms 
		if(rf_error.timer_cnt%100 ==0){
			platform.buzzer_ctrl(1);
			rf_error_ack_pc();		//send error info to sdk
		}		
	}
	else{
		rf_error.state =2;
		rf_error.timer_cnt=0;
	}	
}


/*----------------------- 监测处理 --------------------------------
* called by tx beacon
*/
void rf_modual__tx_counter(unsigned char id)
{
	rf_modual[id].tx_cnt++;
}

//called by rf IO intettupt 
void rf_modual__tx_interrupt_counter(unsigned char id)
{
	rf_modual[id].tx_interrupt_cnt++;
}

//
void rf_modual__check(void)
{
#ifdef RF_MODUAL_MONITOR
	unsigned char i,id;
	if(rf_error.state !=0) return;
	id = multi.modual_id[0];	//current channel!!
	i=0;
	if(rf_modual[id].tx_cnt > rf_modual[id].tx_interrupt_cnt){
		if(rf_modual[id].tx_cnt - rf_modual[id].tx_interrupt_cnt > THRESHOLD_RF_CNT){
			if( ++rf_modual[id].failure % 3 ==0){
				if(rf_modual[id].failure >= RF_FAIL_CNT){
					rf_error.state =1; 			//20210415 set warning flag
					rf_error.timer_cnt =0;
				}
				rf_modual[id].error_cnt++;	//debug only!!
				//re-init the failure rf modual
				platform.rf_init(multi.modual_id[i]); 
				platform.rf_set_freq(multi.modual_chan[i],multi.modual_id[i]);					
			}
		}
		else{
			rf_modual[id].failure =0;
		}
	}
	else{
		rf_modual[id].failure =0;
	}
	//clear this period paramter, ready for next period
	rf_modual[id].tx_cnt=0;
	rf_modual[id].tx_interrupt_cnt=0; 		
	
#endif
}

#ifdef RF_MODUAL_MONITOR
unsigned char get_rf_error_cnt(unsigned char *buf)
{	
	unsigned char i,id,cnt=0;
	for(i=0;i<multi.hard_rf_modual_cnt;i++){
		id = multi.modual_id[i];
		
		buf[0+cnt] = id;
		buf[1+cnt] = rf_modual[id].error_cnt >>8;	
		buf[2+cnt] = rf_modual[id].error_cnt;	
		cnt +=3;	
	}//for
	
	return cnt;
}
#endif


//----------------------------------------------
/*
* 5.8G模块监测，单模块和多模块都适用
*/
#ifdef 	RF_MODUAL_5G8_MONITOR

static unsigned char rf_modual_5G8_invalid_flag;
void rf_modual_5G8_invalid_set(void)
{
	rf_modual_5G8_invalid_flag=1;
}


void rf_modual_5G8__check(void)
{
		if(rf_modual_5G8_invalid_flag==0) return;
		rf_modual_5G8_invalid_flag =0;
		platform.rf_init(multi.modual_id[0]); 
		platform.rf_set_freq(multi.modual_chan[0],multi.modual_id[0]);
}

#endif




