#include "stdint.h"
#include "stdbool.h"
#include "dm_button_gpio.h"
#include "dm_key_event.h"
#include "app_trace.h"


#define DM_KEY_EVENT_PRESENT 1
#if (DM_KEY_EVENT_PRESENT)

#define DM_KEY_EV_REPEAT_BEGIN              (DM_KEY_EV_CLICK_SLOT_TOP+DM_KEY_EV_REPEAT_INTVL)

enum
{
    DM_KEY_EV_STATE_IDLE,
    DM_KEY_EV_STATE_PRESSED,
    DM_KEY_EV_STATE_COMBO_RELEASE,
    DM_KEY_EV_STATE_DBCLICK_WAITING,
    DM_KEY_EV_STATE_DBCLICK_PRESSED,
    DM_KEY_EV_STATE_REPEAT,
};

enum
{
    DM_KEY_EV_EVENT_CONFIG,
    DM_KEY_EV_EVENT_REPORT_IND,
    DM_KEY_EV_EVENT_TIMER,
};
typedef uint8_t (*dm_fsm_action_t)(uint8_t inst, void* p_param);
typedef struct
{
    uint8_t             state;              ///< current state
    uint8_t             event;              ///< trigger event
                                            ///< state and event could be combined into
                                            ///< a 16-bit ke_msg_id_t as a message proccesed
                                            ///< by DM task
    dm_fsm_action_t     action;             ///< transition function
} dm_fsm_t;

typedef dm_key_ev_conf_t dm_key_ev_conf_evt_t;

typedef dm_btn_report_t dm_key_ev_rpt_ind_evt_t;

typedef struct
{
    dm_key_ev_map_t*      ev_map;
    uint16_t              map_item_num;
    dm_btn_id_t           btn[DM_KEY_EV_COMBO_BTN_NUM];
    dm_btn_id_t           btn_bak[DM_KEY_EV_COMBO_BTN_NUM];
    uint32_t              run_time;
    struct fsm_timer      *timer;
    uint8_t               state;
    dm_key_ev_cbk_t       cbk;
} dm_key_ev_env_t;

static dm_key_ev_env_t dm_key_ev_env;
static uint32_t flag = 0;




static void _dm_key_ev_set_slot_timer(void)
{
    dm_key_ev_env.timer = FsmAddTimerCx(DM_KEY_EV_SLOT_UNIT,DM_KEY_EV_EVENT_TIMER,key_event_fsm,NULL);
}

static void _dm_key_ev_clear_slot_timer(void)
{
    if (dm_key_ev_env.timer != NULL)
    {
        FSM_DelTimer(&dm_key_ev_env.timer);
        dm_key_ev_env.timer = NULL;
    }
}

static bool _dm_key_ev_check_slot_timer(uint8_t group)
{
        uint8_t flag;
#if 0
        if (dm_key_ev_env.timer > 0)
        {
            flag = DM_SPLIT_MSG_GRP(dm_key_ev_env.timer);
            return (flag == group);
        }
        else
        {
            return FALSE;
        }
#endif
        return true;

}

static int16_t _dm_key_ev_alloc_btn_item(void)
{
    int16_t ret = -1;
    uint8_t i;

    for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
    {
        if (dm_key_ev_env.btn[i] == DM_KEY_EV_INVALID_BTN_ID)
        {
            ret = (int16_t)i;
            break;
        }
    }

    return ret;
}

static int16_t _dm_key_ev_find_btn_item(dm_btn_id_t btn_id)
{
    int16_t ret = -1;
    uint8_t i;

    for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
    {
        if (dm_key_ev_env.btn[i] == btn_id)
        {
            ret = (int16_t)i;
            break;
        }
    }

    return ret;
}

static int16_t _dm_key_ev_find_btn_bak_item(dm_btn_id_t btn_id)
{
    int16_t ret = -1;
    uint8_t i;

    for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
    {
        if (dm_key_ev_env.btn_bak[i] == btn_id)
        {
            ret = (int16_t)i;
            break;
        }
    }

    return ret;
}

static uint8_t _dm_key_ev_get_valid_btn_num(void)
{
    uint8_t i, n;

    n = 0;
    for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
    {
        if (dm_key_ev_env.btn[i] != DM_KEY_EV_INVALID_BTN_ID)
        {
            n++;
        }
    }

    return n;
}

static void _dm_key_ev_reset_runtime_env(void)
{
    uint8_t i;
    uint32_t flag = 0;
    _dm_key_ev_clear_slot_timer();
    dm_key_ev_env.run_time = 0;
    for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
    {
        dm_key_ev_env.btn_bak[i] = dm_key_ev_env.btn[i] = DM_KEY_EV_INVALID_BTN_ID;
    }
}    

static bool _dm_key_ev_find_event(dm_btn_id_t* p_combo_keys, uint8_t key_num, 
                                           dm_key_ev_action_t action, uint16_t* p_evt)
{
    bool find = FALSE;
    uint8_t i, n;
    uint16_t j;
    uint32_t s0, s1;
    uint8_t n0, n1;
    dm_key_ev_map_t* ev;
    
    if (key_num > DM_KEY_EV_COMBO_BTN_NUM)
        return find;

    ev = dm_key_ev_env.ev_map;
    for (j = 0;j < dm_key_ev_env.map_item_num;j++)
    {
        if (ev[j].action != action)
            continue;
        
        /* 1. summary check */
        s0 = s1 = 0;
        n0 = n1 = 0;
        for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
        {
            if (ev[j].btn[i] != DM_KEY_EV_INVALID_BTN_ID)
            {
                s0 += ev[j].btn[i];
                n0++;
            }
            if (i < key_num && p_combo_keys[i] != DM_KEY_EV_INVALID_BTN_ID)
            {
                s1 += p_combo_keys[i];
                n1++;
            }
        }
        /* 2. id to id compare */
        if (s0 == s1 && n0 == n1)
        {
            find = TRUE;
            for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
            {
                if (ev[j].btn[i] == DM_KEY_EV_INVALID_BTN_ID)
                    continue;
                
                for (n = 0;n < key_num;n++)
                {
                    if (ev[j].btn[i] == p_combo_keys[n])
                        break;
                }
                if (n == key_num)
                {
                    find = FALSE;
                    break;
                }
            }
            break;
        }
    }
    
    if (find == TRUE)
    {
        *p_evt = ev[j].event;
    }

    return find;
}


static void _dm_key_ev_button_report_callback(dm_btn_report_t* p_rpt)
{
    dm_key_ev_rpt_ind_evt_t* rpt_ind;

    dbg_printf("btn report 0x%x,0x%x\r\n",p_rpt->btn_id,p_rpt->action);
    rpt_ind = NEW(sizeof(dm_key_ev_rpt_ind_evt_t));
    memcpy(rpt_ind, p_rpt, sizeof(dm_key_ev_rpt_ind_evt_t));
    FsmEventCx(DM_KEY_EV_EVENT_REPORT_IND, (fsm_func *)key_event_fsm, rpt_ind);

}

static uint8_t _dm_key_ev_report_evt_at_idle(uint8_t unused, void* p_param)
{
    dm_key_ev_rpt_ind_evt_t* rpt = (dm_key_ev_rpt_ind_evt_t*)p_param;
    bool found;
    uint16_t event;

    //dbg_printf("rp_e_i\r\n");
    if (rpt->action == DM_BTN_ACT_PRESSED)
    {
        found = _dm_key_ev_find_event(&rpt->btn_id, 1, DM_KEY_EV_ACT_PRESSED, &event);
        if (found == TRUE)
        {
            dm_key_ev_env.cbk(event);
        }

        dm_key_ev_env.btn_bak[0] = dm_key_ev_env.btn[0] = rpt->btn_id;
        _dm_key_ev_set_slot_timer();

        return DM_KEY_EV_STATE_PRESSED;
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_IDLE;
}

static uint8_t _dm_key_ev_timer_evt_at_pressed(uint8_t group, void* p_param)
{
    bool found;
    uint16_t event;
    //dbg_printf("t_e_p\r\n");

    if (_dm_key_ev_check_slot_timer(group) == FALSE)
    {
        /* lapsed invalid timer, ignore */
        return DM_KEY_EV_STATE_PRESSED;
    }
    
    dm_key_ev_env.run_time += DM_KEY_EV_SLOT_UNIT;

    if (dm_key_ev_env.run_time > DM_KEY_EV_REPEAT_BEGIN)
    {
        found = _dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                        DM_KEY_EV_ACT_REPEAT, &event);
        if (found == TRUE)
        {
            dm_key_ev_env.cbk(event);
        }
        //dm_key_ev_env.run_time = 0;
        _dm_key_ev_set_slot_timer();
        return DM_KEY_EV_STATE_REPEAT;
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_PRESSED;
}


static uint8_t _dm_key_ev_report_evt_at_pressed(uint8_t unused, void* p_param)
{
    dm_key_ev_rpt_ind_evt_t* rpt = (dm_key_ev_rpt_ind_evt_t*)p_param;
    int16_t item;
    uint16_t event;
    //dbg_printf("r_e_p\r\n");
    if (rpt->action == DM_BTN_ACT_PRESSED)
    {
        item = _dm_key_ev_alloc_btn_item();
        if (dm_key_ev_env.run_time > DM_KEY_EV_COMBO_BTN_MARGIN || item < 0)
        {
            /* failed combo key, treat it as a new key, abandon old buttons */
            _dm_key_ev_reset_runtime_env();
            return _dm_key_ev_report_evt_at_idle(unused, p_param);
        }
        else
        {
            /* combo buttons, reset running timer, treat them as a new (combo-)key */
            _dm_key_ev_clear_slot_timer();
            dm_key_ev_env.btn[(uint8_t)item] = rpt->btn_id;
            dm_key_ev_env.btn_bak[(uint8_t)item] = rpt->btn_id;
            dm_key_ev_env.run_time = 0;
            _dm_key_ev_set_slot_timer();
            if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, DM_KEY_EV_ACT_PRESSED, &event))
            {
                dm_key_ev_env.cbk(event);
            }

            return DM_KEY_EV_STATE_PRESSED;
        }
    }
    else if (rpt->action == DM_BTN_ACT_RELEASED)
    {
        item = _dm_key_ev_find_btn_item(rpt->btn_id);
        if (item >= 0)
        {
            /* check if it is combo-key */
            if (_dm_key_ev_get_valid_btn_num() > 1)
            {
                /* belongs to combo-key, swtich to STATE_COMBO_RELEASED_WATCHING */
                _dm_key_ev_clear_slot_timer();
                dm_key_ev_env.run_time = 0;
                dm_key_ev_env.btn[(uint8_t)item] = DM_KEY_EV_INVALID_BTN_ID;
                _dm_key_ev_set_slot_timer();

                return DM_KEY_EV_STATE_COMBO_RELEASE;
            }
            else
            {
                /* single-button-key */
                _dm_key_ev_clear_slot_timer();
                dm_key_ev_env.btn[(uint8_t)item] = DM_KEY_EV_INVALID_BTN_ID;
                dm_key_ev_env.run_time = 0;
                _dm_key_ev_set_slot_timer();
                if (_dm_key_ev_find_event(&dm_key_ev_env.btn_bak[(uint8_t)item], 1, DM_KEY_EV_ACT_RELEASED, &event))
                {
                    dm_key_ev_env.cbk(event);
                }
                return DM_KEY_EV_STATE_DBCLICK_WAITING;
            }
        }
        else
        {

        	 _dm_key_ev_reset_runtime_env();
        	 return DM_KEY_EV_STATE_IDLE;
        }
    }
}

static uint8_t _dm_key_ev_timer_evt_at_combo_release(uint8_t group, void* p_param)
{
    if (_dm_key_ev_check_slot_timer(group) == FALSE)
    {
        /* lapsed invalid timer, ignore */
        return DM_KEY_EV_STATE_COMBO_RELEASE;
    }
    //dbg_printf("t_e_cr\r\n");
    dm_key_ev_env.run_time += DM_KEY_EV_SLOT_UNIT;

    if (dm_key_ev_env.run_time > DM_KEY_EV_COMBO_BTN_MARGIN)
    {
        /* failed combo key release: margin expired */
        _dm_key_ev_reset_runtime_env();
        return DM_KEY_EV_STATE_IDLE;
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_COMBO_RELEASE;
}

static uint8_t _dm_key_ev_report_evt_at_combo_release(uint8_t unused, void* p_param)
{
    dm_key_ev_rpt_ind_evt_t* rpt = (dm_key_ev_rpt_ind_evt_t*)p_param;
    int16_t item;
    uint16_t event;
    //dbg_printf("r_e_cr\r\n");
    if (rpt->action == DM_BTN_ACT_PRESSED)
    {
        /* failed combo key release: button pressed while combo key releasing */
        _dm_key_ev_reset_runtime_env();
        return DM_KEY_EV_STATE_IDLE;
    }
    else if (rpt->action == DM_BTN_ACT_RELEASED)
    {
        item = _dm_key_ev_find_btn_item(rpt->btn_id);
        if (item < 0)
        {
            /* unkwown button, ignore */
            return DM_KEY_EV_STATE_COMBO_RELEASE;
        }
        else
        {
            dm_key_ev_env.btn[(uint8_t)item] = DM_KEY_EV_INVALID_BTN_ID;
            if (_dm_key_ev_get_valid_btn_num() == 0)
            {
                /* all buttons released */
                _dm_key_ev_clear_slot_timer();
                if (_dm_key_ev_find_event(dm_key_ev_env.btn_bak, DM_KEY_EV_COMBO_BTN_NUM, 
                                            DM_KEY_EV_ACT_RELEASED, &event))
                {
                    dm_key_ev_env.cbk(event);
                }
                _dm_key_ev_reset_runtime_env();
                return DM_KEY_EV_STATE_IDLE;
            }
            else
            {
                dm_key_ev_env.run_time = 0;
                return DM_KEY_EV_STATE_COMBO_RELEASE;
            }
        }
    }
}

static uint8_t _dm_key_ev_timer_evt_at_dbclick_wait(uint8_t group, void* p_param)
{
    uint16_t event;
    //dbg_printf("t_e_dbc_w\r\n");
    if (_dm_key_ev_check_slot_timer(group) == FALSE)
    {
        /* lapsed invalid timer, ignore */
        return DM_KEY_EV_STATE_DBCLICK_WAITING;
    }

    dm_key_ev_env.run_time += DM_KEY_EV_SLOT_UNIT;

    if (dm_key_ev_env.run_time > DM_KEY_EV_DOUBLE_CLICK_INTVL)
    {
        /* expired, now it is confirmed that the previous is a click */
        if (_dm_key_ev_find_event(dm_key_ev_env.btn_bak, DM_KEY_EV_COMBO_BTN_NUM, 
                                            DM_KEY_EV_ACT_CLICK, &event))
        {
            dm_key_ev_env.cbk(event);
        }
        _dm_key_ev_reset_runtime_env();

        return DM_KEY_EV_STATE_IDLE;
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_DBCLICK_WAITING;
}

static uint8_t _dm_key_ev_report_evt_at_dbclick_wait(uint8_t group, void* p_param)
{
    dm_key_ev_rpt_ind_evt_t* rpt = (dm_key_ev_rpt_ind_evt_t*)p_param;
    int16_t item;
    uint8_t i;
    uint16_t event;

    //dbg_printf("r_e_db_w\r\n");
    if (rpt->action == DM_BTN_ACT_PRESSED)
    {
        /* check if valid press */
        item = _dm_key_ev_find_btn_bak_item(rpt->btn_id);
        if (item < 0)
        {
            /* a new key coming */
            _dm_key_ev_reset_runtime_env();
            return _dm_key_ev_report_evt_at_idle(group, p_param);
        }
        else
        {
            dm_key_ev_env.btn[(uint8_t)item] = rpt->btn_id;

            for (i = 0;i < DM_KEY_EV_COMBO_BTN_NUM;i++)
            {
                if (dm_key_ev_env.btn[i] != dm_key_ev_env.btn_bak[i])
                {
                    _dm_key_ev_set_slot_timer();
                    return DM_KEY_EV_STATE_DBCLICK_WAITING;
                }
            }

            /* all button double clicked */
            _dm_key_ev_clear_slot_timer();
            if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                            DM_KEY_EV_ACT_DCLICK, &event))
            {
                dm_key_ev_env.cbk(event);
            }
            dm_key_ev_env.run_time = 0;
            _dm_key_ev_set_slot_timer();
            
            return DM_KEY_EV_STATE_DBCLICK_PRESSED;
        }
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_DBCLICK_WAITING;
}

static uint8_t _dm_key_ev_timer_evt_at_dbclick_pressed(uint8_t group, void* p_param)
{
    uint16_t event;

    //dbg_printf("t_e_cp\r\n");
    if (_dm_key_ev_check_slot_timer(group) == FALSE)
    {
        /* lapsed invalid timer, ignore */
        return DM_KEY_EV_STATE_DBCLICK_PRESSED;
    }

    dm_key_ev_env.run_time += DM_KEY_EV_SLOT_UNIT;

    if (dm_key_ev_env.run_time >= DM_KEY_EV_REPEAT_BEGIN)
    {
        if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                            DM_KEY_EV_ACT_REPEAT, &event))
        {
            dm_key_ev_env.cbk(event);
        }
        dm_key_ev_env.run_time = 0;
        _dm_key_ev_set_slot_timer();
        return DM_KEY_EV_STATE_REPEAT;
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_DBCLICK_PRESSED;
}

static uint8_t _dm_key_ev_report_evt_at_dbclick_pressed(uint8_t unused, void* p_param)
{
    dm_key_ev_rpt_ind_evt_t* rpt = (dm_key_ev_rpt_ind_evt_t*)p_param;
    uint16_t event;
    int16_t item;

   // dbg_printf("r_e_cb_p\r\n");
    if (rpt->action == DM_BTN_ACT_PRESSED)
    {
        /* a new key incoming, abandon old key */
        _dm_key_ev_reset_runtime_env();
        return _dm_key_ev_report_evt_at_idle(unused, p_param);
    }
    else if (rpt->action == DM_BTN_ACT_RELEASED)
    {
        item = _dm_key_ev_find_btn_item(rpt->btn_id);
        if (item >= 0)
        {
            /* one button released means the whole double click key finished */
            if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                                DM_KEY_EV_ACT_RELEASED, &event))
            {
                dm_key_ev_env.cbk(event);
            }
            _dm_key_ev_reset_runtime_env();
            return DM_KEY_EV_STATE_IDLE;
        }
        else
        {
            _dm_key_ev_set_slot_timer();
            return DM_KEY_EV_STATE_DBCLICK_PRESSED;
        }
    }
}

static uint8_t _dm_key_ev_timer_evt_at_repeat(uint8_t group, void* p_param)
{
    uint16_t event;
    dm_key_ev_action_t action;
    uint8_t step;
   // dbg_printf("t_e_re\r\n");
    if (_dm_key_ev_check_slot_timer(group) == FALSE)
    {
        /* lapsed invalid timer, ignore */
        return DM_KEY_EV_STATE_REPEAT;
    }

    dm_key_ev_env.run_time += DM_KEY_EV_SLOT_UNIT;
    
    if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                            DM_KEY_EV_ACT_REPEAT, &event))
    {
        dm_key_ev_env.cbk(event);
    }

    if ((dm_key_ev_env.run_time % DM_KEY_EV_LONG_PRESS_STEP) == 0)
    {
        step = dm_key_ev_env.run_time / DM_KEY_EV_LONG_PRESS_STEP;
        action = (dm_key_ev_action_t)((uint8_t)DM_KEY_EV_ACT_LONG_PRESS * step);

        /* report the (very...)long press event */
        if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                      action, &event))
        {
            dm_key_ev_env.cbk(event);
        }
    }
    _dm_key_ev_set_slot_timer();
    return DM_KEY_EV_STATE_REPEAT;
}

static uint8_t _dm_key_ev_report_evt_at_repeat(uint8_t unused, void* p_param)
{
   // dbg_printf("r_e_re\r\n");
    dm_key_ev_rpt_ind_evt_t* rpt = (dm_key_ev_rpt_ind_evt_t*)p_param;
    uint16_t event;
    int16_t item;

    if (rpt->action == DM_BTN_ACT_PRESSED)
    {
        /* a new key incoming, abandon old key */
        _dm_key_ev_reset_runtime_env();
        return _dm_key_ev_report_evt_at_idle(unused, p_param);
    }
    else if (rpt->action == DM_BTN_ACT_RELEASED)
    {
        item = _dm_key_ev_find_btn_item(rpt->btn_id);
        if (item >= 0)
        {
            /* one button released means the whole double click key finished */
            if (_dm_key_ev_find_event(dm_key_ev_env.btn, DM_KEY_EV_COMBO_BTN_NUM, 
                                                DM_KEY_EV_ACT_RELEASED, &event))
            {
                dm_key_ev_env.cbk(event);
            }
            _dm_key_ev_reset_runtime_env();
            return DM_KEY_EV_STATE_IDLE;
        }
        else
        {
            _dm_key_ev_set_slot_timer();
            return DM_KEY_EV_STATE_REPEAT;
        }
    }
}

static const dm_fsm_t dm_key_ev_fsm[] =
{
    {DM_KEY_EV_STATE_IDLE,            DM_KEY_EV_EVENT_REPORT_IND, _dm_key_ev_report_evt_at_idle           },
    {DM_KEY_EV_STATE_PRESSED,         DM_KEY_EV_EVENT_TIMER,      _dm_key_ev_timer_evt_at_pressed         },
    {DM_KEY_EV_STATE_PRESSED,         DM_KEY_EV_EVENT_REPORT_IND, _dm_key_ev_report_evt_at_pressed        },
    {DM_KEY_EV_STATE_COMBO_RELEASE,   DM_KEY_EV_EVENT_TIMER,      _dm_key_ev_timer_evt_at_combo_release   },
    {DM_KEY_EV_STATE_COMBO_RELEASE,   DM_KEY_EV_EVENT_REPORT_IND, _dm_key_ev_report_evt_at_combo_release  },
    {DM_KEY_EV_STATE_DBCLICK_WAITING, DM_KEY_EV_EVENT_TIMER,      _dm_key_ev_timer_evt_at_dbclick_wait    },
    {DM_KEY_EV_STATE_DBCLICK_WAITING, DM_KEY_EV_EVENT_REPORT_IND, _dm_key_ev_report_evt_at_dbclick_wait   },
    {DM_KEY_EV_STATE_DBCLICK_PRESSED, DM_KEY_EV_EVENT_TIMER,      _dm_key_ev_timer_evt_at_dbclick_pressed },
    {DM_KEY_EV_STATE_DBCLICK_PRESSED, DM_KEY_EV_EVENT_REPORT_IND, _dm_key_ev_report_evt_at_dbclick_pressed},
    {DM_KEY_EV_STATE_REPEAT,          DM_KEY_EV_EVENT_TIMER,      _dm_key_ev_timer_evt_at_repeat          },
    {DM_KEY_EV_STATE_REPEAT,          DM_KEY_EV_EVENT_REPORT_IND, _dm_key_ev_report_evt_at_repeat         }
};

void key_event_fsm(uint8_t group, void* p_param)
{
    uint8_t i=0;
    uint32_t state = 0;
    uint16_t fsm_num = sizeof(dm_key_ev_fsm)/sizeof(dm_fsm_t);
    for(i=0; i< fsm_num; i++)
    {
        if((dm_key_ev_fsm[i].state == dm_key_ev_env.state) && (dm_key_ev_fsm[i].event == group))
        {
            state = dm_key_ev_fsm[i].action(group,p_param);
        }
    }
    dm_key_ev_env.state = state;
    if(p_param != NULL)
        FREE(p_param);
}
void dm_key_ev_init(void)
{
     memset(&dm_key_ev_env,0,sizeof(dm_key_ev_env_t));
}
void dm_key_ev_config(dm_key_ev_conf_t* p_conf)
{
   
    dm_key_ev_env.cbk = p_conf->cbk;
    dm_key_ev_env.ev_map = p_conf->evt_map;
    dm_key_ev_env.map_item_num = p_conf->evt_map_elt_num;

    _dm_key_ev_reset_runtime_env();

    dm_btn_conf_t dm_button_param;
    dm_button_param.scan_interval    = 10* 16000;
    dm_button_param.scan_times       = 5;
    dm_button_param.scan_valid_times = 4;
    dm_button_param.col_io_map       = 0x00001c00;
    dm_button_param.row_io_map       = 0x00000300;
    dm_button_param.cbk              = _dm_key_ev_button_report_callback;
 
    dm_button_config(&dm_button_param);
   
}

#endif //DM_KEY_EVENT_PRESENT

