#include    "base_config.h"
//#include    "platform_extern.h"
//#include    "func_extern.h"
//#include    "core_extern.h"
//#include    "my_headfile.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_LIST_MGNT)

GEN_LINKLIST_DEF(list_mgnt,kp_ele_str,LIST_MGNT_CNT);

#define 	MD_LIST_MGNT_CRC 		0
#define 	CRC_LEN							53
/*
*
*/
void list__init_all(void)
{
	list_mgnt__init();
	list_mgnt__init_ele();
}


//init pele
void list__pele_init(kp_ele_str *pele)
{
		//memset(pele,0,sizeof(kp_ele_str) );
		//pele->status = _ELE_STAT_VALID;
}


//---------------------------获取键盘sn及其个数 ------------------------------------------
/*
* 获取当前名单sn和个数
*/
unsigned short list__get_cnt_and_SN(unsigned char *sn)
{
		kp_ele_str *pele;	
		unsigned short cnt=0;
		for(unsigned short i=0;i< list_mgnt__get_len();i++){
			pele = list_mgnt__get_ele(i);
			memcpy(sn+cnt*4,pele->id_sn,SN_LEN);
			cnt++;								
		}//for
		return cnt;	
}


/*----------------------------------------- search -------------------------------
*  遍历整个链表，查找指定的sn是否存在于链表中
* input:要查找的键盘sn,每次查找一个sn,找到后无需继续直接返回;
* return: NULL 没有找到 
*/
kp_ele_str * list__search_special_sn(const unsigned char *sn)
{
	kp_ele_str *pele;	
	for(unsigned char i=0;i< list_mgnt__get_len();i++){
		pele = list_mgnt__get_ele(i);
		if( memcmp(pele->id_sn,sn,SN_LEN) ==0){
			pele->index = i;
//			my_debug.printf(1,"%s() search sn=%d success\n",__FUNCTION__,HBYTEL_COMB_INT(sn) );	
			return (pele);
		}
	}//for	

//	my_debug.printf(1,"%s() search sn=%d is NOT exist\n",__FUNCTION__,HBYTEL_COMB_INT(sn) );	
	return NULL;        
}

/*------------------------------------- in-------------------------------------
*将一个节点数据保存到链表尾部
*/

static void ele_copy(kp_ele_str * dist,const kp_ele_str * src )
{
	#if 1
	//是否可以用memcpy????
	memcpy(dist,src,sizeof(kp_ele_str) );
	#else

	#endif
}

unsigned char list__in(kp_ele_str *in_ele)
{
    kp_ele_str *pele =NULL;
	
		//是否去重?
		if( (pele =list__search_special_sn(in_ele->id_sn) ) !=NULL){
//			my_debug.printf(1,"%s() det sn=%d is exist \n",__FUNCTION__,HBYTEL_COMB_INT(in_ele->id_sn) );
			return 1; 		
		}

    if( (pele= list_mgnt__malloc_ele()) ==NULL){//no space to save
        return 0;
    }
    else{
        //cope ele and save rear of linklist
				ele_copy(pele,in_ele);
        list_mgnt__insert(pele,list_mgnt__get_len() );
        return 1; 
    }
}

/*
* 将多个sn写入到名单管理链表中
*/
void list__in_N(const unsigned char *sn,unsigned char cnt)
{
	kp_ele_str ele;
	//debug only
//	my_debug.printf(1,"%s() cnt=%d \n",__FUNCTION__,cnt);
	
	for(unsigned char i=0;i<cnt;i++){
		memcpy(ele.id_sn,sn+i*4,SN_LEN);	
		list__in(&ele);	
//		if(list__in(&ele) ==0)
////			my_debug.printf(1,"%s() save in linklist fail \n",__FUNCTION__);
		
	}//for
		
}



/*--------------------------- detele --------------------------------------------------
*
*/
unsigned char list__detele(const unsigned char *sn)
{
	kp_ele_str *pele=NULL;
	
	if( (pele =list__search_special_sn(sn)) ==NULL){
		return 0; //fail
	}
	else{
		if( list_mgnt__detele(pele,pele->index) !=NULL)
			return 1;
		else 
			return 0;
	}
	
}

/*
* 删除多个??
*/
unsigned char list__detele_2(const unsigned char *sn,unsigned char cnt)
{
	list__detele(sn);
	
	
}


//-------------------------- e2prom save --------------------------------
/*
* called when list is modifyed
*/
void list__save_e2prom(void)
{
	unsigned char sn[LIST_MGNT_CNT];
	unsigned char cnt = list__get_cnt_and_SN(sn);
	
	base_write_e2prom(STORE_LISTMGNT_CNT_ADDR,&cnt,1); 
	platform.delay_ms(5);	
	base_write_e2prom(STORE_LISTMGNT_SN_ADDR,sn,cnt*4);	
}

//return list and count
unsigned short list__fetch_e2prom(void)
{
	unsigned char total;
	if(base_read_e2prom(STORE_LISTMGNT_CNT_ADDR,&total,1) ==0) return 0;	//is default 

	if( total>LIST_MGNT_CNT)
		total = LIST_MGNT_CNT;
	
	unsigned char sn[LIST_MGNT_CNT];
	base_read_e2prom(STORE_LISTMGNT_SN_ADDR,sn,4*total);

	list__in_N(sn,total);	//save to linklist
	
	return total;		
}




#define 	LIST_CNT_PER_PKT			10

//----------------------------------- communication with pc ------------------------------------------------
/*
*
*///ack sdk
static void pc_cmd_0x61_ack_listmgnt(const unsigned char *ack_buf,unsigned short len,unsigned char pkt_max,unsigned char pkt_cur)
{
		unsigned char tmp[USB_REPORT_MAX]; 
		memset(tmp,0,USB_REPORT_MAX);
		tmp[0] =0xF5;	
		tmp[1] =0xAA;
		tmp[2] =0xAA;	
		tmp[3]= len+8;	//len
		tmp[4]= 0xE1;
		tmp[5]= base_core.get_id();
		tmp[6]= 19;
		tmp[7]= pkt_max;
		tmp[8]= pkt_cur;	
		tmp[11]= 18;
		//tmp[12]= 0;			
		memcpy( tmp+12,ack_buf,len);
		
		#if (MD_LIST_MGNT_CRC)
		unsigned short crc = crc16(tmp+11,CRC_LEN);
		tmp[9]= crc>>8;			//crc
		tmp[10]= crc;			
		#else
		tmp[9]= 0;			
		tmp[10]= 0;	
		#endif
		
		//send to pc 
		platform.base_send_data_to_pc(tmp,USB_REPORT_MAX); 
}

/*
*sdk ops linklist section5.3.4  type18
*/
void user_ops_list(const unsigned char *rxpc)
{
	
	if(rxpc[8] != 18) return;
	
//	my_debug.print_buf(1,"rxpc data:",rxpc,60);//debug only
//	#if (MD_LIST_MGNT_CRC)
//	if( (rxpc[6]<<8)+rxpc[7] != crc16(rxpc+8,CRC_LEN) ){
//		my_debug.printf(1,"crc check fail=%x\n",crc16(rxpc+8,CRC_LEN));
//	}
//	#endif
	
	unsigned char pkt_max,pkt_cur,cnt;
	pkt_max = rxpc[4];
	pkt_cur = rxpc[5];	
	unsigned char ack_buf[64];	
	unsigned char list_cnt =list__get_cnt_and_SN(ack_buf+3);	//get online sn and cnt
		
	switch( rxpc[9]){
		case 1://read		
			if( (pkt_max ==1)&&(pkt_cur==1) ){//first pkt 
				pkt_max = list_cnt/LIST_CNT_PER_PKT + ((list_cnt%LIST_CNT_PER_PKT) !=0);
				pkt_cur = 1 ;
				cnt =(pkt_max>1)?LIST_CNT_PER_PKT:list_cnt;				
//				my_debug.printf(1,"calc pkt max =%d;;firt cnt=%d \n",pkt_max,cnt);
				ack_buf[0] = rxpc[9];
				ack_buf[1] = 1;
				ack_buf[2] = cnt;
				pc_cmd_0x61_ack_listmgnt(ack_buf,(cnt<<2)+3,pkt_max,pkt_cur );
			}
			else{//根据sdk的pkt max and cur 报告数据
				//判断是否超出
				if((list_cnt==0) || (pkt_max < pkt_cur) ||  (pkt_cur==0) ||  ( (pkt_cur-1)*LIST_CNT_PER_PKT < list_cnt) )
					cnt =0;
				else
					cnt = (pkt_cur== pkt_max)?list_cnt-(pkt_cur*LIST_CNT_PER_PKT):LIST_CNT_PER_PKT;
				ack_buf[0] = rxpc[9];
				ack_buf[1] = 1;
				ack_buf[2] = cnt;
				memcpy(ack_buf+3,ack_buf+pkt_cur*LIST_CNT_PER_PKT,cnt<<2 );	//4bytes SN
				pc_cmd_0x61_ack_listmgnt(ack_buf,(cnt<<2)+3,pkt_max,pkt_cur );				
			}
			break;
		
		case 2://write			
			cnt = rxpc[11];
			list__in_N(rxpc+12,cnt);
			list__save_e2prom();
		
			//for ack 
			ack_buf[0] = rxpc[9];
			ack_buf[1] = 1;
			ack_buf[2] = cnt;		
			memcpy(ack_buf+3,rxpc+12,cnt<<2 );
			pc_cmd_0x61_ack_listmgnt(ack_buf,(cnt<<2)+3,pkt_max,pkt_cur );	
			break;
		
		case 9://detele special sn
			cnt = rxpc[11];
			for(unsigned char i=0;i<rxpc[11];i++){
				list__detele(rxpc+12+i*4);				
			}//for
			list__save_e2prom();
			
			ack_buf[0] = rxpc[9];
			ack_buf[1] = 1;
			ack_buf[2] = cnt;
			memcpy(ack_buf+3,rxpc+12,cnt<<2 );
			pc_cmd_0x61_ack_listmgnt(ack_buf,(cnt<<2)+3,pkt_max,pkt_cur );				
			break;
		
		case 8://detele all list
			list_mgnt__init();
			list__save_e2prom();
		
			cnt =0;
			ack_buf[0] = rxpc[9];
			ack_buf[1] = 1;
			ack_buf[2] = cnt;
			//memcpy(ack_buf+3,rxpc+12,cnt<<2 );
			pc_cmd_0x61_ack_listmgnt(ack_buf,(cnt<<2)+3,pkt_max,pkt_cur );				
			break;		
		
		default:break;
	}
		
//	my_debug.printf(1,"after func,list cnt=%d \n",list_mgnt__get_len()); 
}





//struct list_mgnt_intf_STR list_mgnt_intf={
//		.init =list__init_all,
//		.pc_rx = user_ops_list,
//		.read_list_from_e2prom = list__fetch_e2prom,
//};





//----------------------------------------next is debug only --------------------------------------------------------------
//#include    "platform_extern.h"

static unsigned char trav_func__print_kplist_info(kp_ele_str * pele,unsigned char index)
{
//		my_debug.printf(1,"%02d: \
//SN=%10d \
// \n",
//										index+1,
//										HBYTEL_COMB_INT(pele->id_sn) );
//	
//		platform.delay_us(800);
		return 1;
}



/*
*打印点名队列里的所有键盘的信息
*/
unsigned char dbg__print_kplist(unsigned char *sn)
{	
		unsigned char cnt =list_mgnt__get_len() ;	
//		my_debug.printf(1,"list keypad cnt: %d \n\r",cnt );
		if(cnt ==0)			
			return 0;
		if( HBYTEL_COMB_INT(sn) == 0){
			list_mgnt__traverse(trav_func__print_kplist_info);
		}
		else{
			kp_ele_str * pele =NULL;
//			my_debug.printf(1,"printf sn=%d basic info \n",HBYTEL_COMB_INT(sn) );
			
			if( (pele =list__search_special_sn(sn) ) ==NULL){
//				my_debug.printf(1,"keypad sn:%d NOT in list\n\r",HBYTEL_COMB_INT(sn));
			}
			else{
				trav_func__print_kplist_info(pele,pele->index);
			}	
			
		}

	return 0;
}


#endif 
