#include    "base_config.h"
//#include    "platform_extern.h"
//#include    "func_extern.h"
//#include    "core_extern.h"
#include "func_down_beacon_intf.h"
#include "gen_lgpkt_ch_intf.h"
#include "function_interface.h"
#include "platform_interface.h"
#include "base_core_user.h"
#include "base_core.h"
#include "function.h"
#include "string.h"
#include <stdlib.h>
#include "HW_MCUIO.h"
#include    "my_headfile.h"

#if (MD_DOWN_BEACON)

#define 	DOWN_BEACON_DBG		1


static unsigned int get_cur_2ms5_tick(void);


//------------------------- linklist process -----------------------------
#define 	DOWN_DATA_LEN								93
#define 	TX_TIME_MAX_Nx2MS5					12000		//400*2.5ms=1000ms =1s

typedef struct {
	unsigned char status;
	unsigned char index;
	unsigned char kp_buf[DOWN_DATA_LEN];
	unsigned char buf_len;
	unsigned char sn[4];
	unsigned char tr_cnt;
	
	unsigned int start_time;
	
	unsigned short tx_times;//debug only
}down_ele_str;
GEN_LINKLIST_DEF(down_linklist,down_ele_str,255);


//---next is debug only--------
void _print_down_ele(const down_ele_str *pele)
{
    ;
//	my_debug.printf(DOWN_BEACON_DBG,"down link ele:sn=%d ,tr_cnt=%d start time=%x buf_len=%d ",HBYTEL_COMB_INT(pele->sn),pele->tr_cnt,pele->start_time, pele->buf_len);
//	my_debug.print_buf(DOWN_BEACON_DBG,"data:",pele->kp_buf,pele->buf_len);
}

/*
* add
* 0- fail ;1- success
*/
#if 0
static unsigned char _down_link__in(const unsigned char *rx)
{
    down_ele_str *pele =NULL;

		if( (pele= down_linklist__malloc_ele()) ==NULL){//no space to save
			return 0;
		}
		else{		
			memcpy(pele->kp_buf,rx,DOWN_DATA_LEN);//copy ele and save rear of linklist
			down_linklist__insert(pele,down_linklist__get_len() );	//save at rear
			return 1; 
		}
}
#endif

static unsigned char _down_link__in2(down_ele_str *in_ele)
{
    down_ele_str *pele =NULL;

		if( (pele= down_linklist__malloc_ele()) ==NULL){//no space to save
			return 0;
		}
		else{		
			memcpy(pele,in_ele,sizeof(down_ele_str) );//memcpy(pele->kp_buf,rx,DOWN_DATA_LEN);//copy ele and save rear of linklist		
			down_linklist__insert(pele,down_linklist__get_len() );	//save at rear
			return 1; 
		}
}


/*
* search special sn;return struct point
*/
static down_ele_str* _down_link__search(const unsigned char *sn,unsigned char tr_cnt)
{
		down_ele_str *pele;	
		
		for(unsigned short i=0;i<down_linklist__get_len();i++){
			if( (pele = down_linklist__get_ele(i)) ==NULL) break;//continue;
			if(memcmp(pele->sn,sn,4) == 0 && (tr_cnt == pele->tr_cnt)){
				pele->index = i;
				return pele;			
			}						
		}//for	
		return NULL;	
}


/*
* detele
* 0- fail ;1- success
*/
static unsigned char _down_link__detele(const unsigned char *rx,unsigned char tr_cnt)
{
	down_ele_str *pele;
	if( (pele =_down_link__search(rx,tr_cnt) ) == NULL){
		return 0; //fail
	}
	else{
		if( down_linklist__detele(pele,pele->index) == NULL)
			return 0;
		else 
			return 1;
	}
}



/*
* init linklist all parameter
*/
static void _down_link__init_all(void)
{
//	my_debug.printf(DOWN_BEACON_DBG,"down link init all\n");
	down_linklist__init();
	down_linklist__init_ele();
}



//=============================================================================================================================

unsigned char down_time=0;

static void clear_record(void)
{
	down_time=0;
}
////----------------------------- comm with pc ----------------------------------------
//base protocol 5.8.2
//called by pc 0x61
void down_beacon__rxpc(const unsigned char  *rxpc)
{
		//rxpc[0] =1 //cmd type
//		my_debug.print_buf(DOWN_BEACON_DBG,"down data:",rxpc,DOWN_DATA_LEN);
		//去重
		if(down_time == rxpc[1]) return;
			down_time = rxpc[1];
	
		unsigned int pos =2;	//see protocol detail		
		do{
				if(rxpc[pos+0] < 5 ){ //len = 0 ?
//					my_debug.printf(DOWN_BEACON_DBG,"DET data end;pos=%d rxpc[pos+0]=%d\n",pos,rxpc[pos+0]);
					break;
				}
				else{
					down_ele_str ele;
					ele.buf_len = rxpc[pos+0] -5;
					memcpy(ele.sn,&rxpc[pos+1],4);		
					ele.tr_cnt = rxpc[pos+5];
					memset(ele.kp_buf,0,DOWN_DATA_LEN);
					memcpy(ele.kp_buf,&rxpc[pos+6],ele.buf_len);
					//
					ele.start_time = get_cur_2ms5_tick();
					ele.tx_times = 0;				//debug only
					_print_down_ele(&ele); //debug only
					if(_down_link__in2(&ele) ){;
//						my_debug.printf(DOWN_BEACON_DBG,"save success link len=%d\n",down_linklist__get_len() );
					}
					else{;
//						my_debug.printf(DOWN_BEACON_DBG,"save fail\n");
					}
					
					pos +=rxpc[pos]+1;
				}
			
		}while(1);
		
}

//void down_data_check(void)
//{
//	unsigned char tmp[1024];
//	if( core__gen_lgpkt_intf.fetch_data(tmp) ){
//		down_beacon__rxpc(tmp);
//	}
//}

/*
* section 3.2.1
*0 -fail
*1-success
*/
static  void down_rslt_report(unsigned char rslt,const unsigned char *sn,unsigned char tr_cnt)
{
	unsigned char tmp[64];
	tmp[0] = (rslt!=0)?2:1;			
	memcpy(tmp+1,sn,4);
	memset(tmp+5,0,3);
	tmp[8] = tr_cnt;
	Core_PC_active_rpt(tmp,9);//core__pc_intf.active_rpt(tmp,9);

//	my_debug.printf(DOWN_BEACON_DBG,"%s() sn=%d rpt status=%d \n",__FUNCTION__,HBYTEL_COMB_INT(sn),rslt );	
}


//----------------------------- rx keypad  ----------------------------------------
void down_beacon__rxkp(const unsigned char  *rxkp)
{
	//rxkp[1] =0xB7
//	my_debug.print_buf(DOWN_BEACON_DBG,"rxkp resp:",rxkp,16 );
#ifdef DEBUG_IO	
	HW_DEBUG_0_L;
	HW_DEBUG_0_H;
#endif	
	down_ele_str *pele;
	
#if 0
	platform__system_intfp->disable_INT();
	if( (pele =_down_link__search(rxkp+2) ) == NULL){
//		my_debug.printf(DOWN_BEACON_DBG,"%s() fail: search sn=%d fail\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2) );//fail
	}
	else{
		if( pele->tr_cnt == rxkp[9]){
			unsigned short times = pele->tx_times;//debug only
			if( down_linklist__detele(pele,pele->index) == NULL)
//				my_debug.printf(DOWN_BEACON_DBG,"%s() fail: detele sn=%d fail\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2) );//fail
			else 
//				my_debug.printf(DOWN_BEACON_DBG,"%s() success: sn=%d tx_times=%d\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2),times );//success
		}
		else{
//			my_debug.printf(DOWN_BEACON_DBG,"%s() fail: sn=%d tx tr_cnt=%d;rsp tr_cnt=%d\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2),pele->tr_cnt, rxkp[9]);//fail
		}						
	}
	
	platform__system_intfp->enable_INT();
#else
	//if( ((pele =_down_link__search(rxkp+2) ) != NULL) &&(pele->tr_cnt == rxkp[9]) ){
    if( (pele =_down_link__search(rxkp+2,rxkp[9]) ) != NULL ){
			unsigned short times = pele->tx_times;//debug only
			if( down_linklist__detele(pele,pele->index) == NULL)
                ;
//				my_debug.printf(DOWN_BEACON_DBG,"%s() fail: detele sn=%d fail\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2) );//fail
			else{
//				down_rslt_report(1,rxkp+2,rxkp[9]);	
				down_rslt_report(1,rxkp+2,pele->tr_cnt);
//				my_debug.printf(DOWN_BEACON_DBG,"%s() success: sn=%d tx_times=%d\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2),times );//success
			}				
	}
	else{
//		my_debug.printf(DOWN_BEACON_DBG,"%s() sn=%d fail:  search fail or tr_cnt not equal:pele->tr_cnt=%d; rxkp[9]=%d\n",__FUNCTION__,HBYTEL_COMB_INT(rxkp+2),pele->tr_cnt,rxkp[9] );//fail
	}	
#ifdef DEBUG_IO		
	HW_DEBUG_0_L;
#endif
	
#endif
}




//--------------------------------- send process -----------------------------------------
struct db_STR{
	unsigned char status;
    
	unsigned char cur_pos;		//当前数据在链表中的位置，依次处理
	unsigned char tx_pkt_max;
	unsigned char tx_pkt_cur;
	down_ele_str cur_ele;
	unsigned char tx_step;
	unsigned char tx_repet;
	volatile unsigned int _2ms5_tick;
    unsigned char continue_tx_kp_cnt;
	#define 	CONTINUE_TXKP_MAX		10   
    
    unsigned char normal_beacon_hold_time;
};
struct db_STR  db={
	.status = 0,
	.cur_pos =0,
	.tx_pkt_max =0,
	.tx_step=0,
};
#define		FIRST_PKT_LEN			19 
#define		GEN_PKT_LEN				32 


//根据数据长度计算出需要的数据包个数
static unsigned char calc_pkt_cnt(unsigned char data_len)
{
	return GET_PKT_CNT(data_len,FIRST_PKT_LEN,GEN_PKT_LEN);
}

/*
*获取发送的数据不同包号的长度
* seq = 0-2
*/
static unsigned char calc_pkt_len(unsigned char data_len,unsigned char seq)
{
	return GET_PKT_LEN(data_len,FIRST_PKT_LEN,GEN_PKT_LEN,0,db.tx_pkt_max);
}


/*
*计算数据包的起始位置
*/
static unsigned char calc_pkt_index(unsigned char seq)
{
	return GET_PKT_INDEX(FIRST_PKT_LEN,GEN_PKT_LEN,seq);
}

//计算CRC数据长度
static unsigned char calc_crc_len(unsigned char pkt_max)
{
	return GET_CRC_DATA_LEN(db.tx_pkt_max,FIRST_PKT_LEN,GEN_PKT_LEN);
}

/*
* 发送第一包数据
keypad protocol 5.5.1
*/
static void down_first_pkt_sub(down_ele_str *pele,unsigned char pkt_cnt)
{			
#if 1
		unsigned char tmp[33];
	
		memset(tmp,0,33);
		tmp[0] =32;	
		base_core.get_match_code(tmp+1);//core__attr_intf.get_matchcode(tmp+1);
		tmp[5] =0x37;	
		if( HBYTEL_COMB_INT( pele->sn) != 0)
			memcpy(tmp+6,pele->sn,4);
		else
			memset(tmp+6,0,4);
		tmp[10] = pkt_cnt;	//max =3
		tmp[13] = pele->tr_cnt;

		//cmd data 19 byte
		memcpy(tmp+14,pele->kp_buf,calc_pkt_len(pele->buf_len,0) );
		
		//crc	
		unsigned short crc = crc16(pele->kp_buf,calc_crc_len(pkt_cnt) ); // crc16(pele->kp_buf,pele->buf_len); //
		tmp[11] = crc>>8;
		tmp[12] = crc;
		
		platform.rf_send_data(tmp+1,tmp[0],get_main_rf_hard_id());//platform__rf_intf.write_buf(tmp+1,tmp[0],core__multi_intf.get_main_hardid() );		
#else
        struct {
		unsigned char mac[4];
		unsigned char key_cmd; //byte1
		unsigned char sn[4];
		unsigned char pkt_max;	
		unsigned char crc[2];
		unsigned char tr_cnt;	
		unsigned char data[19];		
	}first_pkt;
	
	core__attr_intf.get_matchcode(first_pkt.mac);
	first_pkt.key_cmd = 0x37;
	memcpy(first_pkt.sn,pele->sn,4);
	first_pkt.pkt_max = pkt_cnt;
	unsigned short crc = crc16(pele->kp_buf,calc_crc_len(pkt_cnt) ); 
	first_pkt.crc[0] = crc>>8;
	first_pkt.crc[1] = crc;	
	first_pkt.tr_cnt = pele->tr_cnt;
	memcpy(first_pkt.data,pele->kp_buf,calc_pkt_len(pele->buf_len,0) );
	
	platform__rf_intf.write_buf( (unsigned char*)(&first_pkt),32,core__multi_intf.get_main_hardid() );
#endif
}

static void down__tx_pkt_comb(unsigned char pkt_no)
{
//	my_debug.printf(1,"%s() pkt nub=%d \n",__FUNCTION__,pkt_no);
	if(pkt_no ==0 )
		down_first_pkt_sub(&db.cur_ele,db.tx_pkt_max);
	else{
		platform.rf_send_data(db.cur_ele.kp_buf+calc_pkt_index(pkt_no),\
																	calc_pkt_len(db.cur_ele.buf_len,pkt_no),\
																	get_main_rf_hard_id() );		
	}
	
}

/*
* 从链表头取出一个键盘的数据
*/
static down_ele_str * fetch_data_from_linklist(unsigned char pos)
{
	down_ele_str *pele=NULL;
	
//	do{
		if( (pele = down_linklist__get_ele(pos)) == NULL){;
			//my_debug.printf_error("error! %s()linklist ele is null\n",__FUNCTION__);//error?					
		}
		else{	
			unsigned int time =ABS(get_cur_2ms5_tick(),pele->start_time);
			//my_debug.printf(DOWN_BEACON_DBG,"time =%x;max =%x\n",time,TX_TIME_MAX_Nx2MS5 );
			if(  time >= TX_TIME_MAX_Nx2MS5 ){
				//detele			
				if( _down_link__detele(pele->sn,pele->tr_cnt) ==0){;
//					my_debug.printf(DOWN_BEACON_DBG,"sn=%d timeout; detele fail; tx_times=%d\n",HBYTEL_COMB_INT(pele->sn),pele->tx_times );
				}
				else{
					down_rslt_report(0,pele->sn,pele->tr_cnt);
//					my_debug.printf(DOWN_BEACON_DBG,"sn=%d timeout; detele success; tx_times=%d\n",HBYTEL_COMB_INT(pele->sn),pele->tx_times );
				}
                return NULL;
			}
			else{
				pele->tx_times++; //debug only
//				break; //exist
			}
		}
//	}while(1);
	
	return pele;
}


//获取当前2.5ms tick
static unsigned int get_cur_2ms5_tick(void)
{
	return db._2ms5_tick;
}

/*------------------------
*
*/
unsigned char down_tx__ctrl(void)
{
		db._2ms5_tick++;	
		unsigned char ret_val=0;	

		switch(db.tx_step){
			case 0:	
			{				
				if(down_linklist__get_len() ==0) 
                {
//                    down_data_check();
                    break;
                }                    
				down_ele_str *pele=NULL;
				if( (pele = fetch_data_from_linklist(db.cur_pos)) == NULL) 
                {
					if( ++db.cur_pos >= down_linklist__get_len() ) //循环处理
						db.cur_pos =0;
					break;	
				}
				memset(&db.cur_ele,0,sizeof(down_ele_str) );
				memcpy(&db.cur_ele,pele,sizeof(down_ele_str) );
				db.tx_pkt_cur =0;	
				db.tx_pkt_max = calc_pkt_cnt(db.cur_ele.buf_len);		
//				my_debug.printf(1,"%s() link pos=%d pkt max=%d continue cnt=%d\n",__FUNCTION__,db.cur_pos,db.tx_pkt_max,db.continue_tx_kp_cnt); //debug only
				db.tx_step = 1;		
			}				
				
			case 1://重发/发送第一包
				down__tx_pkt_comb(db.tx_pkt_cur);
				if( ++db.tx_pkt_cur >= db.tx_pkt_max){//一个键盘的所有pkt都发送完毕
					if( ++db.continue_tx_kp_cnt >= CONTINUE_TXKP_MAX){
						db.continue_tx_kp_cnt =0;
						ret_val = 1;	
						db.tx_step = 2;
//						my_debug.printf(1,"sw to 0x17\n");
                        base_core.switch_send_beacon(2);//直接切换到投票信标
						db.normal_beacon_hold_time = 12;//4;//12;
					}
					else{ 
						if( ++db.cur_pos >= down_linklist__get_len() ) //循环处理
							db.cur_pos =0;
						ret_val =1;
						db.tx_step = 0;
					}				
				}
				else{
					ret_val =1;
				}
				break;
				
			case 2:	//发送第2,3包
//				my_debug.printf(1,"will sw to down beacon from 0x17\n");
				ret_val = 2;
				if(db.normal_beacon_hold_time-- == 0){
					db.tx_step = 0;		//下次重新开始	
				}
				break;
			
			default:break;
		}//sw
		
	return ret_val;
}

unsigned char get_cur_status(void)
{
	if( (db.tx_step == 0) && (down_linklist__get_len() == 0) ) 
        return 0;
    else
        return 1;
}



struct down_beacon_intf_STR func__down_beacon_intf={
		.init = _down_link__init_all,
		.pc_rx = down_beacon__rxpc,
		.kp_rx = down_beacon__rxkp,
        .execute = down_tx__ctrl,
		.get_status = get_cur_status,
		.clear_pkt_record = clear_record, 
};















#endif
