/*
 * Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
 * All rights reserved
 * https://github.com/0x1abin/MultiButton
 */

#pragma once

#include <stdint.h>
#include <string.h>

// According to your need to modify the constants.
#define TICKS_INTERVAL 5 // ms
#define DEBOUNCE_TICKS 3 // MAX 7 (0 ~ 7)
#define SHORT_TICKS (300 / TICKS_INTERVAL)
#define LONG_TICKS (1000 / TICKS_INTERVAL)

typedef struct Button button_hdl_t;

typedef enum // 触发事件源
{
    NONE_PRESS = 0,
    PRESS_DOWN,       // 按键按下，每次按下都触发
    PRESS_UP,         // 按键弹起，每次松开都触发
    PRESS_REPEAT,     // 重复按下触发，变量repeat计数连击次数
    SINGLE_CLICK,     // 单击按键事件
    DOUBLE_CLICK,     // 双击按键事件
    LONG_PRESS_START, // 达到长按时间阈值时触发一次
    LONG_PRESS_HOLD,  // 长按期间一直触发
} press_event_t;

/* EVENT_MASK */
#define EVENT_PRESS_DOWN (1U << PRESS_DOWN)             // 按键按下，每次按下都触发
#define EVENT_PRESS_UP (1U << PRESS_UP)                 // 按键弹起，每次松开都触发
#define EVENT_PRESS_REPEAT (1U << PRESS_REPEAT)         // 重复按下触发，变量repeat计数连击次数
#define EVENT_SINGLE_CLICK (1U << SINGLE_CLICK)         // 单击按键事件
#define EVENT_DOUBLE_CLICK (1U << DOUBLE_CLICK)         // 双击按键事件
#define EVENT_LONG_PRESS_START (1U << LONG_PRESS_START) // 达到长按时间阈值时触发一次
#define EVENT_LONG_PRESS_HOLD (1U << LONG_PRESS_HOLD)   // 长按期间一直触发

typedef void (*button_callback_fn)(button_hdl_t *handle, press_event_t event);

struct Button
{
    struct Button *next;
    uint16_t ticks;
    uint8_t repeat : 4;
    uint8_t event : 4;
    uint8_t state : 3;
    uint8_t debounce_cnt : 3;
    uint8_t active_level : 1;
    uint8_t button_level : 1;
    uint8_t button_id;
    uint8_t event_cb;
    uint8_t (*hal_button_Level)(uint8_t button_id);
    button_callback_fn cb;
};

#ifdef __cplusplus
extern "C"
{
#endif

void button_init(button_hdl_t *handle, uint8_t (*pin_level)(uint8_t button_id), uint8_t active_level, uint8_t button_id);
void button_attach(button_hdl_t *handle, uint8_t event_mask, button_callback_fn cb);
press_event_t get_button_event(button_hdl_t *handle);
int button_start(button_hdl_t *handle);
void button_stop(button_hdl_t *handle);
void button_ticks(void);

#ifdef __cplusplus
}
#endif
