#include "../general/ikk-tick-handler.h"
#include "ikk-button.h"

#define BTN_UNUSED_ID						BTN_UNKNOW_ID
#define BTN_UNKNOW_INTNO					0XFF
//modify by maozj 20200303
#define BTN_CALLBACK_MAXN					(3)

#define SYS_BUTTON_DEFAULT_INDEX			0  //system key defalut index add by maozj 20200313
#define INVALID_TIME_BETWEEN_SYS_BTN_MS		300
#define SYS_BTN_FILTER_TIME_MS				100

// Button jitter timeslot
#define BUTTON_JITTER_SLOT					0	// MS
// Double click timeslot.
#define DCLICK_SLOT_DEF						350	// MS

typedef enum { EBS_UNKNOW = 0, EBS_RELEASED, EBS_PRESSED }BtnStatusEnum;
//默认索引0为系统按键
//add by maozj 20200313 repair short press other key will effect system key
//static uint8_t g_u8TimeMS = 0;
static uint8_t g_u8BtnNum = 0;

static BtnConfSt g_stBtnConfList[BTN_SUPPORT_MAXN];
// button interrupt mapping table
static uint8_t g_u8BtnIrqMapp[BTN_SUPPORT_MAXN];

// CALLBACs
pBtnActionCallback g_pBtnActionCallback[BTN_CALLBACK_MAXN] = {NULL};


typedef struct {
	BtnActionEnum eAction;	// aciton enum
	uint32_t u32ActStamp;	// action occur timestamp
	uint32_t u32ActDuration;// press duration
}ActionRecordSt;

// button click detection controller
typedef struct {
	ActionRecordSt sOldAct;
	ActionRecordSt sNewAct;

	uint32_t stamp;
	BtnActionEnum status;
	BtnActionEnum lastStatus;
	bool bValidAction;
	bool bLongPressed;//add by maozj 20200226
	uint32_t u32BtnPressedTimeCount;

	uint32_t u32CountDownCounter;
	bool bStartDect;
}ClickDetectCtrllerSt;

static ClickDetectCtrllerSt g_stClickDetectCtrller[BTN_SUPPORT_MAXN];
//add by maozj
#define BTN_PRESSED_POLL_TIME_MS	(1000)

/*	DESP: the button[index0] input mode interface.
 * 	Auth: mengmengli_frc.20200523.
 * */
static void Set_GPIO_Input(u32 pin,GPIO_PullTypeDef mode)
{
	drv_gpio_func_set(pin);
	drv_gpio_output_en(pin, 0); 			//enable output
	drv_gpio_input_en(pin, 1);				//disable input
	drv_gpio_up_down_resistor(pin, mode);
}


/*	DESP: the button[index0] active callback interface.
 * 	Auth: mengmengli_frc.20200523.
 * */
//static uint8_t kBtnGetButtonIndexByIrqNO(uint8_t irq_no )
//{
//	for(int index = 0; index < BTN_SUPPORT_MAXN; ++index ) {
//		if( g_stBtnConfList[index].u8ButtonId != BTN_UNUSED_ID ) {
//			if( g_u8BtnIrqMapp[index] == irq_no ) {
//				return index;
//			}
//		}else {
//			break;
//		}
//	}
//
//	return 0XFF;
//}

/*	DESP: the button[index0] active callback interface.
 * 	Auth: maozj.20200325.
 * */
uint8_t kBtnGetButtonIndexById(uint8_t button_id )
{
	for(int index = 0; index < BTN_SUPPORT_MAXN; ++index ) {
		if( g_stBtnConfList[index].u8ButtonId == button_id ) {
			return index;
		}
	}

	return 0XFF;
}


/*	DESP: Check whether all keys have stopped action detection.
 * 	Auth: dingmz_frc.20191107.
 * */
bool kBtnModuleActionIsGoing(void )
{
	for(int index = 0; index < BTN_SUPPORT_MAXN; ++index ) {
		if( g_stBtnConfList[index].u8ButtonId != BTN_UNUSED_ID ) {
			if( g_stClickDetectCtrller[index].u32CountDownCounter > 0 ) {
				return true;
			}
		}else {
			break;
		}
	}

	return false;
}

/*	DESP: Register button action callback notification function.
 * 	Auth: dingmz_frc.20191107.
 * */
kk_err_t kBtnaIRQCallbackRegister(pBtnActionCallback callback )
{
	if( NULL == callback ) {
		return KET_ERR_INVALID_PARAM;
	}

	int valid_index = BTN_CALLBACK_MAXN;

	for(int index = 0; index < BTN_CALLBACK_MAXN; ++index ) {
		if( g_pBtnActionCallback[index] == callback ) {
			valid_index = index;
			break;
		}else if((g_pBtnActionCallback[index] == NULL) && (valid_index == BTN_CALLBACK_MAXN)) {
			valid_index = index;
		}
	}

	if( valid_index < BTN_CALLBACK_MAXN ) {
		g_pBtnActionCallback[valid_index] = callback;
		return KET_OK;
	}

	return KET_ERR_INSUFFICIENT_SPACE;
}

/*	DESP: Recall all registered buttons action callback interface.
 * 	Auth: dingmz_frc.20191107.
 * */
void kBtnaIRQCallbackRecall(unsigned char btnIndex, BtnActionEnum action )
{
	for(int index = 0; index < BTN_CALLBACK_MAXN; ++index ) {
		if( g_pBtnActionCallback[index] != NULL ) {
			g_pBtnActionCallback[index](btnIndex, action);
		}else {
			break;
		}
	}
}
//static uint8_t state_change_flg[BTN_SUPPORT_MAXN] = {1,1,1,1,1,1,1,1};
//void kBtnModuleActionDetectCallback_self(void )
//{
//	static uint32_t key_count[BTN_SUPPORT_MAXN] = {0};
//	for(int index = 0; index < 2; index++ ) {
//		// check button status
//		unsigned int gpio_st = gpio_read(g_stBtnConfList[index].pin);
//		if(gpio_st == g_stBtnConfList[index].eActionPolarity)
//		{
//			if(key_count[index] < 0xffffffff)
//				key_count[index]++;
//
//			if( (g_stBtnConfList[index].bSupportPressedSend)&&(key_count[index] >= MS2COUNT(g_stBtnConfList[index].u32LongPressDuration) ) )
//			{
//				if(g_stClickDetectCtrller[index].lastStatus != EBA_LONGPRESS)
//				{
//					iKonkeAfSelfPrint("Button Id = %d,Long Press!!\r\n", index);
//					g_stClickDetectCtrller[index].status = EBA_LONGPRESS;
//				}
//			}
//			else if(key_count[index] >= MS2COUNT(60))
//			{
//				if(g_stClickDetectCtrller[index].lastStatus != EBA_PRESSED)
//				{
//					iKonkeAfSelfPrint("Button Id = %d,Pressed!!\r\n", index);
//					g_stClickDetectCtrller[index].status = EBA_PRESSED;
//				}
//			}
//
//		}
//		else
//		{
//			if( (key_count[index]>= MS2COUNT(60))&&(key_count[index] < MS2COUNT(g_stBtnConfList[index].u32LongPressDuration)) )
//			{
//				iKonkeAfSelfPrint("Button Id = %d,Sigal Click!!\r\n", index);
//				g_stClickDetectCtrller[index].status = EBA_CLICK;
//			}
//			key_count[index] = 0;
//		}
//		if(g_stClickDetectCtrller[index].lastStatus != g_stClickDetectCtrller[index].status)
//		{
//			kBtnaIRQCallbackRecall(g_stBtnConfList[index].u8ButtonId, g_stClickDetectCtrller[index].status);
//			g_stClickDetectCtrller[index].lastStatus = g_stClickDetectCtrller[index].status  ;
//		}
//	}
//}
/*	DESP: Button module action detection task callback interface.
 * 	Auth: dingmz_frc.20191107.
 * */
void kBtnModuleActionDetectCallback(void )
{
	static uint32_t key_count[BTN_SUPPORT_MAXN] = {0};
	for(int index = 0; index < g_u8BtnNum; index++ )
	{
		// check button status
		unsigned int gpio_st = gpio_read(g_stBtnConfList[index].pin);
		if(gpio_st == g_stBtnConfList[index].eActionPolarity)
		{
			if(key_count[index] < 0xffffffff)
				key_count[index]++;

			if( (g_stBtnConfList[index].bSupportPressedSend)&&(key_count[index] >= MS2COUNT(g_stBtnConfList[index].u32LongPressDuration) ) )
			{
				if(g_stClickDetectCtrller[index].lastStatus != EBA_LONGPRESS)
				{
					iKonkeAfSelfPrint("Button Id = %d,Long Press!!\r\n", index);
					g_stClickDetectCtrller[index].status = EBA_LONGPRESS;
				}
			}
			else if(key_count[index] >= MS2COUNT(60))
			{
				if(g_stClickDetectCtrller[index].lastStatus != EBA_PRESSED)
				{
					iKonkeAfSelfPrint("Button Id = %d,Pressed!!\r\n", index);
					g_stClickDetectCtrller[index].status = EBA_PRESSED;
				}
			}

		}
		else
		{
			if( (key_count[index]>= MS2COUNT(60))&&(key_count[index] < MS2COUNT(g_stBtnConfList[index].u32LongPressDuration)) )
			{
				iKonkeAfSelfPrint("Button Id = %d,Sigal Click!!\r\n", index);
				g_stClickDetectCtrller[index].status = EBA_CLICK;
			}
			key_count[index] = 0;
		}
		if(g_stClickDetectCtrller[index].lastStatus != g_stClickDetectCtrller[index].status)
		{
			kBtnaIRQCallbackRecall(g_stBtnConfList[index].u8ButtonId, g_stClickDetectCtrller[index].status);
			g_stClickDetectCtrller[index].lastStatus = g_stClickDetectCtrller[index].status  ;
		}
	}
}

/*	DESP: the button[index0] active callback interface.
 * 	Auth: dingmz_frc.20191107.
 * */
//static void kBtnaIRQCallback(uint8_t irq_no )
//{
//	uint8_t button_index = kBtnGetButtonIndexByIrqNO(irq_no);
//	static bool flg = false;
//	static BtnConfSt stBtnConfList[BTN_SUPPORT_MAXN] ;
//
//	if( button_index != 0XFF ) {
//		//iKonkeAfSelfPrint("BUTTON Actived[%d]: ButtonID(%d)!\r\n", button_index, g_stBtnConfList[button_index].u8ButtonId);
//
//		// trigger running button click detection.
//		g_stClickDetectCtrller[button_index].status = EBS_PRESSED;
//		g_stClickDetectCtrller[button_index].stamp  = clock_time();
//		//g_stClickDetectCtrller[button_index].bValidAction = false;
//		//g_stClickDetectCtrller[button_index].bLongPressed = false;//add by maozj 20200226
//		g_stClickDetectCtrller[button_index].u32BtnPressedTimeCount = 0; //add by maozj 20200226
//		g_stClickDetectCtrller[button_index].u32CountDownCounter
//			= (g_stBtnConfList[button_index].u32LongPressDuration + 1000) / TICK_LOOP_NMS;
//		//g_stClickDetectCtrller[button_index].bStartDect = false;
//		g_stClickDetectCtrller[button_index].lastStatus = EBS_UNKNOW;
//		if (flg != true){
//			flg = true;
//			memcpy(stBtnConfList, g_stBtnConfList, sizeof(stBtnConfList));
//		}
//
//		//change irq  ege
//		if (stBtnConfList[button_index].eActionPolarity == EBP_BOTH){
//			bool status = gpio_read(g_stBtnConfList[button_index].pin);
//			g_stBtnConfList[button_index].eActionPolarity  = status?EBP_HIGH:EBP_LOW;
//		}
//		kTickRunnningTrigger();
//	}
//}


/*	DESP:Get usefull assign irq index for other interrupt gpio include button
 * 	Auth: maozj.20200325.
 * */
uint8_t kBtnGetAssignUsefullIndex(void)
{
	for(int index = 0; index < BTN_SUPPORT_MAXN; index++ ) {
		iKonkeAfSelfPrint("g_u8BtnIrqMapp[%d] = [%d].\r\n",index,g_u8BtnIrqMapp[index]);
		if( g_u8BtnIrqMapp[index] == BTN_UNKNOW_INTNO ) {
			return index;
		}
	}
	return 0xFF;
}

/*	DESP: single Button instance register interface.
 * 	Auth: dingmz_frc.20191108. modify by maozj 20200326
 * */
kk_err_t kBtnRegister(uint8_t id, uint32_t pin, BtnPolarityEnum ePolarity, bool bSupportDClick, bool bSupportPressedSend, uint32_t u32LongPressDuration )
{
	if( BTN_UNKNOW_ID == id || BTN_ALLOPT_ID == id ) {
		return KET_ERR_INVALID_PARAM;
	}

	int valid_index = BTN_SUPPORT_MAXN;
	kk_err_t err = KET_OK;

	for(int index = 0; index < BTN_SUPPORT_MAXN; ++index ) {
		if( g_stBtnConfList[index].u8ButtonId == id ) {
			valid_index = index;
			break;
		}else if((valid_index == BTN_SUPPORT_MAXN) && (g_stBtnConfList[index].u8ButtonId == BTN_UNUSED_ID)) {
			valid_index = index;
		}
	}

	if( valid_index < BTN_SUPPORT_MAXN ) { // GET A VALID CHUNK.
		memset(&g_stClickDetectCtrller[valid_index], 0, sizeof(g_stClickDetectCtrller[valid_index]));

		g_stBtnConfList[valid_index].u8ButtonId = id;
		g_stBtnConfList[valid_index].pin  = pin;
		g_stBtnConfList[valid_index].eActionPolarity = ePolarity;
		g_stBtnConfList[valid_index].bSupportDClick  = bSupportDClick;
		g_stBtnConfList[valid_index].bSupportPressedSend = bSupportPressedSend;//add by maozj 20200326
		g_stBtnConfList[valid_index].u32LongPressDuration = u32LongPressDuration;

		iKonkeAfSelfPrint("BTN_REGISTER: id(%d),pin(%d), intno(%d), eActionPolarity(%d), bDclick(%d), longSlot(%d)\r\n"
			, g_stBtnConfList[valid_index].u8ButtonId,g_stBtnConfList[valid_index].pin, g_u8BtnIrqMapp[valid_index]
			, g_stBtnConfList[valid_index].eActionPolarity, g_stBtnConfList[valid_index].bSupportDClick
			, g_stBtnConfList[valid_index].u32LongPressDuration
			);

		#if (Z30_DEVICE_DTYPE == Z30_DEVICE_ZED_SLEEPY)
		GPIO_Mode_TypeDef mode = gpioModeInput;
		#else
		GPIO_PullTypeDef mode = PM_PIN_PULLUP_10K;
		//GPIO_Mode_TypeDef mode = gpioModeInput;
		#endif

		Set_GPIO_Input(g_stBtnConfList[valid_index].pin,mode);

	}else {
		err = KET_ERR_INSUFFICIENT_SPACE;
	}

	return err;
}

/*	DESP: button module Initialize configuration interface.
 * 	Note: Button initialization interface supports one-time registration of multiple buttons!
 * 	Auth: dingmz_frc.20191107.
 * */
kk_err_t kBtnModuleInit(BtnConfSt *btnlist, unsigned char btn_number, pBtnActionCallback pBtnActionCallback )
{
	kk_err_t err = KET_OK;

	memset(g_u8BtnIrqMapp, BTN_UNKNOW_INTNO, sizeof(g_u8BtnIrqMapp));
	memset(g_stBtnConfList, BTN_UNUSED_ID, sizeof(g_stBtnConfList));

	if( btnlist && (btn_number > 0)) {
		btn_number = (btn_number < BTN_SUPPORT_MAXN)?btn_number:BTN_SUPPORT_MAXN;

		for(int index = 0; index < btn_number; ++index ) {
			err = kBtnRegister(btnlist[index].u8ButtonId, btnlist[index].pin, btnlist[index].eActionPolarity
				, btnlist[index].bSupportDClick, btnlist[index].bSupportPressedSend,btnlist[index].u32LongPressDuration);
		}

		kBtnaIRQCallbackRegister(pBtnActionCallback);
	}
	g_u8BtnNum = btn_number;
	return err;
}


