/*
*基站核心处理
*a,初始化核心相关参数
*b,轮询基站核心函数
*/

#include "base_pc_protocol.h"
#include "platform_interface.h"
#include "function_interface.h"
#include "base_core.h"
#include "base_core_user.h"
#include "string.h"
#include "func_down_beacon_intf.h"
#include "ext_beacon_intf.h"
#include "func_multipkt_up_intf.h"
#include    "fast_beacon_intf.h"

#ifdef _DEBUG_CORE_
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_Conf.h"
#endif

//kernel variable,used in kernel only!!
struct kernel_STR kernel={
	.multi_title_flag=0,
	.ext_vbeacon_onoff_flag=0,
	.ext_vbeacon_sysmode_change_flag=0,
	.ext_vbeacon_type1_flag =0,
	.ext_vbeacon_type2_flag =0,	
	
};

//define enum used record kernel status,
//enum core_run_state_ENUM KERNEL_RUN_STATE;

/*
* 获取内核版本
*/
static void get_core_version(unsigned char *ver)
{
	ver[0] = CORE_VER0;
	ver[1] = CORE_VER1;	
	ver[2] = CORE_VER2;	
}

void base_core_force_sysmode0(void)
{
	vote_beacon.sys_mode =0; 
	mem_set(vote_beacon.vbuf,5,0);
	
	//mulit content,broadcast
	kernel.multi_title_flag =0; //
}

void base_core_set_sysmode(unsigned char sysmode)
{
    vote_beacon.sys_mode = sysmode;
}

unsigned char base_core_get_sysmode(void)
{
    return vote_beacon.sys_mode;
}

struct base_core_STR base_core={
	.get_core_ver = get_core_version,
	.core_init 	=base_core_init_all,
	.core_loop	=base_core_main_loop,
	.timer_2ms5_enter	=base_core_2ms5_isr,
	.timer_20ms_enter =base_core_20ms_isr,
	.timer4_enter = base_core_28ms_isr,
	.get_match_code =get_base_match_code,
	.get_id =get_base_id,
	.get_log_mode =get_base_log_mode,
	
	.set_main_rf_chan = process_setup_single_chan,//update_single_freq,
	.get_main_rf_chan=get_base_main_rfchannel,
	.get_mainRF_hard_id =get_main_rf_hard_id,//给外部用户
	.get_whitelistRF_hard_id =get_whitelist_rfid,
	
	.sdk_data_fifo_in =pcrx_data_save,
	.rf_data_fifo_in =keypad_rf_data_save,
	
	.send_data_to_pc =base_tx_to_pc_sub,
//	.send_data_to_pc =keypad_transfer2pc_data_save,	
	
	.get_vote_datapos =get_datapos,
	
	.get_sdk_connect_status =get_pc_connect_status,
	.get_sdk_connect_status_acc =get_pc_connect_status_acc,
	.get_run_status =get_base_status,
	
	.send_rf_data =send_to_keypad_user_hardID,
	.switch_send_beacon = base_send_beacon_switch,
	.get_send_beacon = get_base_send_beacon_status,
	.get_permit_dispaly_flag = get_permit_dispaly_status,
	.force_sysmode0 = base_core_force_sysmode0,	
	.get_sysmode = base_core_get_sysmode,
    .set_sysmode = base_core_set_sysmode,
    
	#ifdef RF_5G8
	.get_5G8_keypad_sn_list =get_link_queue_sn,
	.get_5G8_keypad_online_count =get_keypad_count,	
	#endif 	

};



//-------------------------------------------
/*
*取出标志位后，清除此标志位！！！
*/
unsigned char get_permit_dispaly_status(void)
{
	unsigned tmp =kernel.permit_display_flag;
	kernel.permit_display_flag=0;
	return tmp;
}


//--------------------------------------------------------------------------
///*
//Led1用于指示基站和pc之间的连接：
//	没有被pc usb识别：常亮
//	被pc usb 识别：0.5S间隔闪烁
//	与SDK有数据通信：频繁闪烁

//Led2用于指示基站和键盘之间的通信状态：
//	没有键盘数据：常灭
//	有收到键盘数据：频繁闪烁
//*/

/*
* indicate led, and update pc connect status
* called by base core rx function	*/
void refresh_pc_connect_status(void)
{
		platform.pc_led_ctrl(1);//常亮//platform.pc_led_ctrl(2);//闪烁

		kernel.sdk_connect_status =1;
		kernel.sdk_connect_count=0;	

		kernel.sdk_connect_status_acc =1;
		kernel.sdk_connect_count_acc=0;	
}

/*
* turn on LED if it stay OFF status;
*called by rcvRF data 
*/
void refresh_rcvRF_indicate(void)
{
	if(kernel.rf_led_status ==0) return;
	
	kernel.rf_led_status =0;
	kernel.rf_led_count=0;
	platform.rf_led_ctrl(0);
}


/*
* 获取datapos 用于广播信息	*/
unsigned char get_datapos(void)
{
	return vote_beacon.DATAPOS;
}


/*
* get pc connect status 	*/
unsigned char get_pc_connect_status(void)
{
	return kernel.sdk_connect_status;
}

unsigned char get_pc_connect_status_acc(void)
{
	return kernel.sdk_connect_status_acc;
}
/*
* get base status: 
* base status =idle,vote, trans to pc,trans to keypad,update keypad fireware。。。
* 
*/
unsigned char get_base_status(void)
{
//	if( (vote_beacon.sys_mode!=0)&&(vote_beacon.sys_mode!=40))
//		return 1;
//	else
//		return 0;
	
	if( vote_beacon.sys_mode ==40)
		kernel.run_state = _STA_FAST_MATCH;
	else if( vote_beacon.sys_mode ==16){
		if( (kernel.run_state !=_STA_VOICE_VOTEING)&&(kernel.run_state !=_STA_VOICE_START))
			kernel.run_state = _STA_VOICE_START;
		else
			kernel.run_state = _STA_VOICE_VOTEING;
	}	
	else if( vote_beacon.sys_mode !=0)
		kernel.run_state = _STA_GENERAL_VOTEING;
	else if( vote_beacon.sys_mode ==0)
		kernel.run_state =_STA_SYSMODE_0;
	else{
		kernel.run_state = _STA_IDLE;		
	}
	
	
	//此处可以完善核心的各种状态!!
	return kernel.run_state;
}



/*
* timer monitor pc connect status
*called by 20ms timer 	*/
void timer_20ms_function(void)
{	
	kernel._20ms_flag =1;
	
	//1, rf LED keep on 100ms. 
	if( (kernel.rf_led_status==0)&&(++kernel.rf_led_count>5)){
		kernel.rf_led_count=0;
		kernel.rf_led_status=1;
		platform.rf_led_ctrl(1);	
	}
	
	//2, The pc LED flashes at 500ms once ,if the usb connection is OK.
	if( ++kernel.pc_led_count>50){
		kernel.pc_led_count =0;
		//(platform.usb_connect_status())? platform.pc_led_ctrl(2):platform.pc_led_ctrl(1);
		if( platform.usb_connect_status())
			platform.pc_led_ctrl(2);
		else
			platform.pc_led_ctrl(0);//platform.pc_led_ctrl(1);
	}
	
	//3, the SDK is considered offline, if no data is received within 1S;
	if(++kernel.sdk_connect_count > 1500){//20210327由1S修改成30S sdk离线超时。50*30
		kernel.sdk_connect_status=0;
		kernel.sdk_connect_count=0;		
	}
	
	if(++kernel.sdk_connect_count_acc > 50){
		kernel.sdk_connect_status_acc=0;
		kernel.sdk_connect_count_acc=0;		
	}
    
    #if MD_FAST_BEACON
		core__fast_beacon_intf.execute();
    #endif
}

/*
* Datapos变化/ 或者Mode变化 都需要判断是否开启扩展信标
*/
void vote_beacon_change_callback(const unsigned char*rxpc)
{

	if(rxpc[5]==0){  //暂时不支持空闲信标的扩展信标支持
			#if MD_EXT_BEACON	
			core__ext_beacon_intf.startup_check(0);
			#endif
    }else{
			#if MD_EXT_BEACON	
			core__ext_beacon_intf.startup_check(1);
			#endif
		}
		
		#if MON_DBG_MD
		core__mon_dbg_intf.clear_parameter();	//mon__clear_all_parameter();
		#endif
		#if MON_MULTPKT
		func__mon_multipkt_intf.clear_parameter();
		#endif		
}




/*
设置硬件信息*/
void set_base_hard_firmware_info(void)
{
		base_hdinfo.NEWVER =0xA0;	
		base_hdinfo.MODEL = function.hdinfo_HMODEL;
		base_hdinfo.H_VER= 13;
		base_hdinfo.S_VER=1;
		base_hdinfo.SW_3B[0]=function.hdinfo_SW1;
		base_hdinfo.SW_3B[1]=function.hdinfo_SW2;
		base_hdinfo.SW_3B[2]=function.hdinfo_SW3;	
}


/* -------------------------------------------------------------------
初始化基站核心的参数
上电初始化时被调用
*/
void base_core_init_all(void)
{		
		//20200317，如下两个函数的先后顺序互换了！读取多频点信息后再去设置无线模块
        #if (MD_LIST_MGNT)	
        function.list_mgnt__init();
        #endif
//		base_clear_e2prom_parameter();//清除EEPROM, 回到生产下线初始状态, 测试默认值
        base_read_e2prom_parameter();		
		multi_chan_init();//初始化多模块相关参数

		vote_data_parameter_init();	//初始化处理投票数据相关参数
	
		base_process_pc_init();			//初始化接收pc相关参数
		base_process_keyapad_init();//初始化键盘相关参数
        
//        #if (MD_LIMIT_CAP)
//        function.limit_cap_intfp->init();
//        #endif
//        
//        #if (MD_CUSTOM_DEF)
//        function.custm_def_intfp->init();
//        #endif

        #if (MD_DOWN_BEACON)
        func__down_beacon_intf.init();
        #endif
    
        #if MD_MULTIPKT_UP
        func__multipkt_up_intf.init();
        #endif
    
		#ifdef 	_DBG_2G4_KP_
		_debug_core__init();
		#endif
}


/*
基站核心函数在主程序循环中被调用
*/
extern void _debug_core__RTT_read(void);
extern void timer_mainloop_process(void);
void base_core_main_loop(void)
{
		//keypad
		#ifdef MAINLOOP_PROCESS_VOTE
		keypad_rf_data_process();	//处理接收到的rf数据
		#endif
		//pc		
		base_process_pc_data();		//处理接收到pc的数据
	
		#ifdef MAINLOOP_PROCESS_VOTE
		vote_data_report_to_pc();	//基站上报投票数据给pc
		#endif
		keypad_transfer2pc_data_fetch();	//发送 键盘转发给pc的数据 
#ifdef _DEBUG_CORE_	
        _debug_core__RTT_read();
#endif
		
        //-------- timer process mainloop 
		timer_mainloop_process();
    
		if(kernel._20ms_flag){
			kernel._20ms_flag =0;
			function.monitor__freq_process();
		}

}


#ifdef _DEBUG_CORE_

#define DEBUG_KP_MAX    40
#define DEBUG_SUBJECT_MAX   25  // 200/8  每题用一个bit位表示

volatile unsigned char debug_rxkp[DEBUG_KP_MAX][DEBUG_SUBJECT_MAX]={0};
volatile unsigned char debug_ackkp[DEBUG_KP_MAX][DEBUG_SUBJECT_MAX]={0};
volatile unsigned char debug_txpc[DEBUG_KP_MAX][DEBUG_SUBJECT_MAX]={0};
volatile unsigned char debug_pcack[DEBUG_KP_MAX][DEBUG_SUBJECT_MAX]={0};
volatile unsigned char debug_subject=0;
volatile unsigned short debug_rxkpcnt[DEBUG_KP_MAX]={0};
volatile unsigned short debug_ackkpcnt[DEBUG_KP_MAX]={0};

void basic_delay_us( unsigned short time );

void _debug_set_subject(unsigned char val)
{
    debug_subject = val/8;
}

void debug_set_buf_bit(unsigned char *buf, unsigned int index)
{
    unsigned char i=0,j=0;
    i=index/8;
    j=index%8;
    *(buf + i)|=(0x01<<j);
    
}

unsigned char debug_check_allerr(void)
{
    unsigned char ret;
    unsigned char i,j;
    
    ret=0;
    for(i=0;i<DEBUG_KP_MAX;i++)
    {
        for(j=0;j<debug_subject;j++)
        {
            if(debug_rxkp[i][j]!=0xFF) 
            {
                ret|=0x01;
//                while(1);
            } 
//            if(debug_ackkp[i][j]!=0xFF) 
//            {
//                ret|=0x02;
//            }
//            if(debug_txpc[i][j]!=0xFF) 
//            {
//                ret|=0x04;
//            }
//            if(debug_pcack[i][j]!=0xFF) 
//            {
//                ret|=0x08;
//            }
        }
        
        if(debug_rxkpcnt[i]<(debug_subject*8) || debug_ackkpcnt[i]<(debug_subject*8))
        {
            ret|=0x02;
//            while(1);
        }
//        if(ret==0x0F)
//        {
//            break;
//        }
    }
    return ret;
}


unsigned char debug_check_err(unsigned char *buf)
{
    unsigned char ret;
    unsigned char i,j;
    
    ret=0;
    for(j=0;j<debug_subject;j++)
    {
        if(buf[j]!=0xFF)
        {
            ret = 1;
            break;
        }
    }
    
    return ret;
}


void _debug_core__init(void)
{
    
}
void _debug_core__init_parameter_datapos_change(void)
{
    for(unsigned char i=0;i<DEBUG_KP_MAX;i++)
    {
        memset(debug_rxkp[i], 0, sizeof(debug_rxkp[i]));
        memset(debug_ackkp[i], 0, sizeof(debug_ackkp[i]));
        memset(debug_txpc[i], 0, sizeof(debug_txpc[i]));
        memset(debug_pcack[i], 0, sizeof(debug_pcack[i]));
        debug_rxkpcnt[i]=0;debug_ackkpcnt[i]=0;
    }
}

void _debug_core__record_rxkp_info(const unsigned char *rx_kp)
{
    if(rx_kp[6] && rx_kp[6]<=DEBUG_KP_MAX)
    {
        debug_set_buf_bit(debug_rxkp[rx_kp[6]-1], rx_kp[11]-1);
        debug_rxkpcnt[rx_kp[6]-1]++;
    }
}

void _debug_core__record_ackkp_info(unsigned char mode_type, const unsigned char *ack_kp)
{
    if(ack_kp[3] && ack_kp[3]<=DEBUG_KP_MAX)
    {
        debug_ackkpcnt[ack_kp[3]-1]++;
    }
    
}

void _debug_core__record_txpc_info(unsigned char pkt_seq, const unsigned char *tx_pc)
{
    
}

void _debug_core__record_pcack_info(unsigned char pkt_seq)
{
    
}

void _debug_core__record_txpc_info_report(const unsigned char *tx_pc)
{
    
}

void _debug_core__printf(void)
{
    unsigned char i,j;
    unsigned char ret;
    unsigned char cnt=0;
    ret=debug_check_allerr();
    SEGGER_RTT_printf(0,"\n\n\n\n\n**************************** Datapos=%d ******************************\n", vote_beacon.DATAPOS);
//    if(ret&0x03)
    {
//        while(1);
        if(ret&0x03) SEGGER_RTT_printf(0,"Keypad RX ERR!\n");
        for(i=0;i<DEBUG_KP_MAX;i++)
        {
 //           if(debug_check_err(debug_rxkp[i]))
            {
                SEGGER_RTT_printf(0,"SN:%03d Rx_cnt:%d ACK_cnt:%d\n    ",i+1, debug_rxkpcnt[i], debug_ackkpcnt[i]);
                cnt=0;
                for(j=0;j<debug_subject;j++)
                {    
//                    if(debug_rxkp[i][j]!=0xFF)
                    {
                        SEGGER_RTT_printf(0,"rxKP[%03d]=0x%02x, ",j,debug_rxkp[i][j]);
                    }
                    cnt++;
                    if(cnt>5)
                    {
                        cnt=0;
                        SEGGER_RTT_printf(0,"\n    "); 
                        basic_delay_us(5000);
                    }
                }
                SEGGER_RTT_printf(0,"\n");
                basic_delay_us(5000);
            }
//            else
//            {
////                SEGGER_RTT_printf(0,"SN:%03d Rx_cnt:%d ACK_cnt:%d\n    ",i+1, debug_rxkpcnt[i], debug_ackkpcnt[i]); 
//            }
        }
        
    }
//    else
//    {
//        unsigned int avg_rxcnt=0,avg_ackcnt=0;
//        unsigned char rxcnt=0,ackcnt=0;
////        SEGGER_RTT_printf(0,"Keypad RX OK!\n"); 
//        SEGGER_RTT_printf(0,"OK\n"); 
//        for(i=0;i<DEBUG_KP_MAX;i++)
//        {
//            if(debug_rxkpcnt[i])
//            {
//                avg_rxcnt+=debug_rxkpcnt[i];
//                rxcnt++;
//            }
//            if(debug_ackkpcnt[i])
//            {
//                avg_ackcnt+=debug_ackkpcnt[i];
//                ackcnt++;
//            }
//        }
////        SEGGER_RTT_printf(0,"K%d ",vote_beacon.DATAPOS);
////        SEGGER_RTT_printf(0,"Average rx times:%d  Average ack times:%d\n",avg_rxcnt/rxcnt, avg_ackcnt/ackcnt); 
//    }
    
//    if(ret&0x02)
//    {
//        SEGGER_RTT_printf(0,"Keypad ACK ERR!\n");
//        for(i=0;i<DEBUG_KP_MAX;i++)
//        {
//            if(debug_check_err(debug_ackkp[i]))
//            {
//                SEGGER_RTT_printf(0,"SN:%d ",i);
//                for(j=0;j<debug_subject;j++)
//                {    
//                    if(debug_ackkp[i][j]!=0xFF)
//                    {
//                        SEGGER_RTT_printf(0,"P[%d]:%d,%02x",j,debug_ackkp[i][j]);
//                    }
//                }
//                SEGGER_RTT_printf(0,"\n");
//            }
//        }
//    }
//    
//    if(ret&0x04)
//    {
//        SEGGER_RTT_printf(0,"TX PC ERR!\n");
//        for(i=0;i<DEBUG_KP_MAX;i++)
//        {
//            if(debug_check_err(debug_txpc[i]))
//            {
//                SEGGER_RTT_printf(0,"SN:%d ",i);
//                for(j=0;j<debug_subject;j++)
//                {    
//                    if(debug_txpc[i][j]!=0xFF)
//                    {
//                        SEGGER_RTT_printf(0,"P[%d]:%d,%02x",j,debug_txpc[i][j]);
//                    }
//                }
//                SEGGER_RTT_printf(0,"\n");
//            }
//        }
//    }
//    
//    if(ret&0x08)
//    {
//        SEGGER_RTT_printf(0,"PC ACK ERR!\n");
//        for(i=0;i<DEBUG_KP_MAX;i++)
//        {
//            if(debug_check_err(debug_pcack[i]))
//            {
//                SEGGER_RTT_printf(0,"SN:%d ",i);
//                for(j=0;j<debug_subject;j++)
//                {    
//                    if(debug_pcack[i][j]!=0xFF)
//                    {
//                        SEGGER_RTT_printf(0,"P[%d]:%d,%02x",j,debug_pcack[i][j]);
//                    }
//                }
//                SEGGER_RTT_printf(0,"\n");
//            }
//        }
//    }

SEGGER_RTT_printf(0,"\n**********************************************************\n");
}

void _debug_core__RTT_read(void)
{
    unsigned char pBuffer[16]={0};
//    SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
    if(SEGGER_RTT_Read(0, pBuffer, 16))
    {
        switch(pBuffer[0])
        {
            case '1':  
                _debug_core__printf();
                break;
            case '2':
                SEGGER_RTT_printf(0,"2\n");
                break;
            default:
                SEGGER_RTT_printf(0,"Unsupported instructions!\n");
                break;
        }
    }
}


#endif


