
#define	__IN_BUTTONS_C
#include "buttons.h"
#include "trigger.h"
//----------------------------------------------------------------------------------------------------------------

#define	KEY_SCAN_NUM		2	// 软件去抖, 认为是稳定电平(100ms)
#define	KEY_LONG_DOWN_NUM	50	// 连续500ms秒钟按下, 认为是长时间按下
#define	KEY_TASK_DISABLE	50	// 500ms内没有响应按键, 那么认为按键无效

//--------------------------------------------------------


//--------------------------------------------------------
#ifndef MAX_BUTTONS_NUM
#define	MAX_BUTTONS_NUM		10	// 最大支持按钮个数
#endif

typedef struct
{
	ScanFunc scanfunc;		// 检测函数
	u8 checkState;			// 检查状态

	TaskFunc ldtaskFunc;	// 长按下任务
	TaskFunc dtaskFunc;		// 按下任务
	TaskFunc ctaskFunc;		// 点击任务
	TaskFunc dQuktaskFunc;	// 按下立即响应任务

}ButtonScan;


typedef struct
{
	ButtonScan buttonsList[MAX_BUTTONS_NUM];
	int buttonsNumber;				// 注册的按钮个数
	int buttonTask;					// 按钮响应程序 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
	int scanIndex;					// 当前正在扫描/等待执行的按钮

	u16 buttonCount;				// 按钮扫描计数器
	u16 taskCount;					// 按钮响应计数器

	u8  shakeSta[KEY_SCAN_NUM];		// 软件去抖寄存器
	u8  shakeIdx;					// 软件去抖寄存器指针

	DelayRun delay;

	int execing;		// 正在执行任务中标志
}ButtonCtrl;


ButtonCtrl g_buttonCtrl;

//----------------------------------------------------------------------------------------------------------------

//--------------------------------------------------------

void InitButtonCtrl(void)
{
	int i;

	g_buttonCtrl.buttonsNumber = 0;			// 注册的按钮个数
	g_buttonCtrl.buttonTask = 0;			// 按钮响应程序
	g_buttonCtrl.scanIndex = -1;			// 没有正在扫描的按钮

	memset(g_buttonCtrl.buttonsList, 0, sizeof(ButtonScan)*MAX_BUTTONS_NUM);
	for (i = 0; i < MAX_BUTTONS_NUM; i++)
	{
		g_buttonCtrl.buttonsList[i].scanfunc = NULL;
	}
	g_buttonCtrl.delay = NULL;

	AddTriggerToList(10, ScanButtons, NULL);		// 10ms
}

//--------------------------------------------------------
// 添加Botton到扫描列表

int AddButtonToList(ScanFunc fp, u8 sta, TaskFunc ldtsk, TaskFunc ctsk, TaskFunc dtsk, TaskFunc dqtsk)
{
	if ((fp != NULL) &&
		((ldtsk != NULL) || (ctsk != NULL) || (dtsk != NULL) || (dqtsk != NULL)) &&
		(g_buttonCtrl.buttonsNumber < MAX_BUTTONS_NUM) &&
		1 )
	{
		memset(&(g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber]), 0, sizeof(ButtonScan));
		g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].scanfunc = fp;
		g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].checkState = sta;
		g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].ldtaskFunc = ldtsk;
		g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].ctaskFunc = ctsk;
		g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].dtaskFunc = dtsk;
		g_buttonCtrl.buttonsList[g_buttonCtrl.buttonsNumber].dQuktaskFunc = dqtsk;
		g_buttonCtrl.buttonsNumber++;

	//	printf("add a new button to %d\r\n", g_buttonCtrl.buttonsNumber);

		return g_buttonCtrl.buttonsNumber;
	}
	else
	{
		printf("add button more than enable\r\n");
		return -1;
	}
}

//--------------------------------------------------------
// 每10ms扫描一次

void ScanButtons(void)
{
	u8 sta,staOk;
	int i;
	ButtonScan * pScan;

	if (g_buttonCtrl.scanIndex == -1)
	{// 没有确定目标按钮
		for (i = 0; i < g_buttonCtrl.buttonsNumber; i++)
		{
			pScan = (&(g_buttonCtrl.buttonsList[i]));
			if (pScan->scanfunc == NULL)
			{
				continue;
			}

			sta = pScan->scanfunc();
			if (sta == pScan->checkState)	// 有按键处于按下状态
			{
				g_buttonCtrl.scanIndex = i;		// 当前正在扫描/等待执行的按钮
				g_buttonCtrl.shakeIdx = 0;		// 软件去抖寄存器指针
				g_buttonCtrl.taskCount = 0;		// 按钮响应计数器
				g_buttonCtrl.buttonCount = 0; 	// 按钮扫描计数器
				memset(g_buttonCtrl.shakeSta, (~pScan->checkState), KEY_SCAN_NUM);	// 去抖寄存器数组
				break;
			}
		}
	}
	else if (g_buttonCtrl.scanIndex < g_buttonCtrl.buttonsNumber)
	{// 判断按钮状态
		pScan = (&(g_buttonCtrl.buttonsList[g_buttonCtrl.scanIndex]));
		if (pScan->scanfunc != NULL)
		{
			sta = pScan->scanfunc();		// 最新值
			staOk = 1;						// 滤波数组內数据相同时为1,否则为0

			// 软件去抖
			if (KEY_SCAN_NUM > 1)
			{
				g_buttonCtrl.shakeSta[g_buttonCtrl.shakeIdx++] = sta;
				g_buttonCtrl.shakeIdx %= KEY_SCAN_NUM;

				for (i = 0; i < KEY_SCAN_NUM-1; i++)
				{
					if (g_buttonCtrl.shakeSta[i] != g_buttonCtrl.shakeSta[i+1])
					{
						staOk = 0;
						break;
					}
				}
			}

			// 按钮任务生效判断
			if (g_buttonCtrl.buttonCount == 0)
			{// 初次生效
				if ((sta == pScan->checkState) && (staOk == 1))
				{// 按下任务生效
					g_buttonCtrl.buttonCount = 1;
					if (pScan->dQuktaskFunc != NULL)
					{// 按下立即响应任务
						pScan->dQuktaskFunc();
					}

					if (pScan->dtaskFunc != NULL)
					{// 按下任务
						g_buttonCtrl.buttonTask = 1;				// 创建按钮任务 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
						g_buttonCtrl.taskCount = KEY_TASK_DISABLE;	// 按钮响应计数器
					}
				}
			}
			else if (g_buttonCtrl.buttonTask != 3)
			{// 长按和单击事件检测,单击事件有效后不继续检测
				if (sta == pScan->checkState)
				{// 按钮按住
					if (g_buttonCtrl.buttonCount < KEY_LONG_DOWN_NUM)
					{
						g_buttonCtrl.buttonCount++;
					}
					else if (g_buttonCtrl.buttonCount == KEY_LONG_DOWN_NUM)
					{// 长按任务
						if (pScan->ldtaskFunc != NULL)
						{ 
							g_buttonCtrl.taskCount = KEY_TASK_DISABLE;	// 按钮响应计数器
							g_buttonCtrl.buttonTask = 2;				// 创建按钮任务 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
						}
						g_buttonCtrl.buttonCount++;
					}
				}
				else
				{// 按钮抬起
					if (staOk == 1)		// 按钮抬起滤波
					{// 单击任务
						if (pScan->ctaskFunc != NULL)
						{
							g_buttonCtrl.taskCount = KEY_TASK_DISABLE;	// 按钮响应计数器
							g_buttonCtrl.buttonTask = 3;				// 创建按钮任务 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
						}
						else
						{ 
							if (((pScan->dtaskFunc == NULL) && (pScan->ldtaskFunc == NULL) && (pScan->ctaskFunc == NULL)) ||		// 只注册了快速响应函数
							   (g_buttonCtrl.buttonTask == -1) ||			// 按下或长按任务已响应
								0 )
							{
								g_buttonCtrl.buttonTask = 0;
								g_buttonCtrl.scanIndex = -1;			// 无按钮任务
								return;
							} 
						}
					}
				}
			}

			// 按钮任务无响应判断
			if ((g_buttonCtrl.buttonTask > 0) &&	// 有任务需要执行
				(g_buttonCtrl.taskCount != 0) &&	// 未超时
				1 )
			{
				if (--g_buttonCtrl.taskCount == 0)
				{
					if (g_buttonCtrl.buttonTask == 3)
					{
						g_buttonCtrl.scanIndex = -1;			// 无按钮任务
					}
					g_buttonCtrl.buttonTask = -1;
				}
			}
		}
	}
}

//--------------------------------------------------------

int WaitAllButtonUp(void)
{
	int i, j;
	int rslt;
	u32 startTime,loopTime;		//运行时间 单位:s
	ButtonScan * pScan;

	rslt = 0;
	startTime = GetMsSoftTimer();
	do
	{
		j = 0;
		for (i = 0; i < g_buttonCtrl.buttonsNumber; i++)
		{
			pScan = (&(g_buttonCtrl.buttonsList[i]));
			if (pScan->scanfunc == NULL)
			{
				continue;
			}
			if (pScan->scanfunc() != pScan->checkState)
			{
				j++;
			}
		}

		if (g_buttonCtrl.buttonsNumber == j)
		{
			break;
		}

		ScanButtons();		// 扫描按键		// 有按钮未抬起,执行按钮任务

		if (g_buttonCtrl.delay != NULL)
		{
			g_buttonCtrl.delay(1);
		}

		loopTime = GetMsSoftTimer();
		if ((loopTime - startTime) > 5000)		// 最多只等待5s时长
		{
			rslt = -1;
			break;
		}
	}while(1);

	g_buttonCtrl.buttonTask = 0;
	g_buttonCtrl.scanIndex = -1;        // 当前正在扫描/等待执行的按钮

	return rslt;
}

void RegDelayFun(DelayRun delay)
{
	g_buttonCtrl.delay = delay;
}

void CleanButtonTask(void)
{
	g_buttonCtrl.buttonTask = 0;		// 按钮响应程序 -1:任务响应完毕 0: 无任务 1:按下任务 2:长按任务 3:单击任务
	g_buttonCtrl.scanIndex = -1;        // 当前正在扫描/等待执行的按钮
}

void ButtonsTask()
{
	int i, rslt;
	u8 sta;
	ButtonScan * pScan;

	if (g_buttonCtrl.execing != 0)		// 只允许执行一次按键任务, 不能嵌套调用
	{
		return;
	}

	g_buttonCtrl.execing++;

	if ((g_buttonCtrl.buttonTask > 0) &&
		(g_buttonCtrl.scanIndex >= 0) &&
		1 )
	{ 
		rslt = 0;
		for (i = 0; i < g_buttonCtrl.buttonsNumber; i++)
		{// 当有两个以上按钮按下时,不响应当前程序
			pScan = (&(g_buttonCtrl.buttonsList[i]));
			if (pScan->scanfunc == NULL)
			{
				continue;
			}

			sta = pScan->scanfunc();
			if (sta == pScan->checkState)
			{
				if (i == g_buttonCtrl.scanIndex)
				{// 指定按钮
					rslt++;
				}
				else
				{// 异常按钮
					rslt--;
					printf("button%d state error\r\n", g_buttonCtrl.scanIndex);
				}
			}
		}

		if (((g_buttonCtrl.buttonTask != 3) && (rslt == 1)) ||
			((g_buttonCtrl.buttonTask == 3) && (rslt == 0)) ||
			0 )
		{// 只有一个制定按钮按下时,执行事件任务
			pScan = (&(g_buttonCtrl.buttonsList[g_buttonCtrl.scanIndex]));
			if (pScan != NULL)
			{

				if (g_buttonCtrl.buttonTask == 1)
				{// 1:按下任务
					if (pScan->dtaskFunc != NULL)
					{
						rslt = pScan->dtaskFunc();
					}
				}
				else if (g_buttonCtrl.buttonTask == 2)
				{// 2:长按任务
					if (pScan->ldtaskFunc != NULL)
					{
						rslt = pScan->ldtaskFunc();
					}
				}
				else if (g_buttonCtrl.buttonTask == 3)
				{// 3:单击任务
					if (pScan->ctaskFunc != NULL)
					{
						rslt = pScan->ctaskFunc();
						CleanButtonTask();			// 清除按钮任务
					}
				}
			}
		}
		g_buttonCtrl.buttonTask = -1;		// 执行完成
	}

	g_buttonCtrl.execing = 0;
}


