/**
 *@file    sr_key.c
 *@brief   KEY抽象接口源码
 *@details 提供按键事件注册、状态扫描任务等具体功能实现
 *@copyright Copyright (c) 2024 lierda. All rights reserved.
 *@author  Lierda-RDC
 *@date    2024-04-01
 *@example ZhaoyangSDK\example\component\key_example.c
 */

#include "sr_key.h"
#include "sr_gpio.h"
#include "sr_log.h"

#ifdef SR_USE_KEY

// KEY电平读取
#ifndef KEY_LVL_GET
#define SR_KEY_LEVEL_GET(id) SR_HalGpioRead(keyTable[id].gpioId)

#else
#define SR_KEY_LEVEL_GET(id) KEY_LVL_GET(id)
#endif

   
/*
*  注意事项：按键列表和实际按键数量在board_cfg.h中定义
*/



// KEY管理器数组
static SR_KEY_MNG_T KEY_MNG[SR_KEY_NUM] = {0};

// 按键列表，绑定gpio和KEY ID,指定按下有效电平
SR_GPIO_ACT_LVL_T  keyTable[] = SR_KEY_TABLE; 

//按键默认的事件回调函数
static void _KeyCbFunDef(SR_KEY_ID_E id, SR_KEY_EVT_E state, uint16_t time, void *args)
{
    SR_LOG(DEBUG, "[key] id=%d state=%d time=%d\n", id, state, time);
}
static SR_KEY_CB_T gs_keyCb = {.cb = _KeyCbFunDef, .args = SR_NULL};



//@brief    按键按下检测
//@return   0:松开       1：按下
static int _KeyPressDetect(uint16_t id)
{
    int level = 0;

    level = SR_KEY_LEVEL_GET(id); // 读取按键实际电平
    
    return !(level ^ keyTable[id].actLvl); // 计算按键逻辑电平
}

//@brief  按键扫描任务，需要周期执行（10ms 或 1S周期）,支持多键同时检测
void SR_KeyScanTask(void)
{
    uint8_t i, j;
    for (i = 0; i < SR_KEY_NUM; i++) // 轮询所有KEY
    {
        if (SR_LVL_PRESSED == _KeyPressDetect(i)) // 按下
        {     
            KEY_MNG[i].state = 1; 
            //按下检测
            if (KEY_MNG[i].pressEvt) // 如果回调事件不为空
            {
                for (j = 0; j < KEY_MNG[i].pressEvtNum; j++)
                {
                    if (KEY_MNG[i].delay == KEY_MNG[i].pressEvt[j].time)
                    {
                        // 5、自定义按下事件
                        gs_keyCb.cb(i,  KEY_MNG[i].pressEvt[j].evtId, KEY_MNG[i].delay * _TIME_UNIT, gs_keyCb.args);
                    }
                }
            }
            KEY_MNG[i].delay++;
            
        }
        else // 松开
        {
            if (KEY_MNG[i].rlsEvt) // 如果回调事件不为空
            {
                for (j = 0; j < KEY_MNG[i].rlsEvtNum; j++)
                {
                    if ((KEY_MNG[i].delay >= KEY_MNG[i].rlsEvt[j].startTime) &&
                        (KEY_MNG[i].delay < KEY_MNG[i].rlsEvt[j].endTime))
                    {        
                        // 4、自定义松开事件
                        gs_keyCb.cb(i, KEY_MNG[i].rlsEvt[j].evtId, KEY_MNG[i].delay * _TIME_UNIT, gs_keyCb.args);
                    }
                }
            }

            if ((KEY_MNG[i].delay >= SR_KEY_DELAY_LONG))
            {
                // 3、长按x毫秒后，松开
                gs_keyCb.cb(i, SR_KEY_LONG_PRESS, KEY_MNG[i].delay * _TIME_UNIT, gs_keyCb.args);
            }
#if (SR_KEY_SCAN_PERIOD == 10)
            else if (KEY_MNG[i].delay > SR_KEY_DELAY_SHORT)
            {
                // 短按松开
                KEY_MNG[i].multi_press++;
            }
#endif

            KEY_MNG[i].delay = 0; 
            KEY_MNG[i].state = 0; 

        }

#if (SR_KEY_SCAN_PERIOD == 10)

        // 连按检测
        if (KEY_MNG[i].multi_press > 0)
        {
            if (KEY_MNG[i].multi_delay++ >= 50)
            {
                KEY_MNG[i].multi_delay = 0;
                KEY_MNG[i].multi_press = 0;

                // 1、单击
                gs_keyCb.cb(i, SR_KEY_SHORT_PRESS, 0, gs_keyCb.args);
            }
            else
            {
                if (KEY_MNG[i].multi_press == 2)
                {
                    KEY_MNG[i].multi_delay = 0;
                    KEY_MNG[i].multi_press = 0;

                    // 2、双击
                    gs_keyCb.cb(i, SR_KEY_DOUBLE_PRESS, 0, gs_keyCb.args);
                }
            }
        }
#endif
    }
}
SR_POLL_TASK_EXPORT(SR_KeyScanTask, 1, SR_PRIORITY_0);


int SR_KeySetEvtCb(KeyEventCb cb, void *args)
{

    if (cb == SR_NULL)
        return SR_INVALID;
    else
    {
        gs_keyCb.cb = cb;
        gs_keyCb.args = args;
    }

    return SR_OK;
}


int SR_KeyPressEvtReg(SR_KEY_ID_E keyId, SR_KEY_PRES_T *pressEvt, uint8_t evtNum)
{
    for (uint8_t i = 0; i < evtNum; i++)
    {
        pressEvt[i].time /= _TIME_UNIT;
    }

    KEY_MNG[keyId].pressEvt = pressEvt;
    KEY_MNG[keyId].pressEvtNum = evtNum;

    return 0;
}


int SR_KeyRlsEvtReg(SR_KEY_ID_E keyId, SR_KEY_RLS_T *rlsEvt, uint8_t evtNum)
{
    for (uint8_t i = 0; i < evtNum; i++)
    {
        rlsEvt[i].startTime /= _TIME_UNIT;
        if(rlsEvt[i].startTime == 0) rlsEvt[i].startTime +=1;
        rlsEvt[i].endTime /= _TIME_UNIT;
    }

    KEY_MNG[keyId].rlsEvt = rlsEvt;
    KEY_MNG[keyId].rlsEvtNum = evtNum;

    return 0;
}

uint8_t SR_KeyGetState(SR_KEY_ID_E keyId)
{
     return KEY_MNG[keyId].state;
}

uint16_t SR_KeyGetCnt(SR_KEY_ID_E keyId)
{
     return KEY_MNG[keyId].delay*_TIME_UNIT;
}

#endif

