/* * Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "sys/defs.h" #include "matrix_buttons.h" #include "kernel/os/os.h" #include "sys/list.h" typedef struct { uint32_t id_mask; uint32_t repeat_timeout_ms; /* only used in repeat matrix button */ uint32_t timeout_ms; /* the timeout to trigger the matrix button object */ uint8_t en; /* enable/disable the matrix button object */ MATRIX_BUTTON_TYPE func; /* the matrix button type */ MATRIX_BUTTON_STATE state; /* the matrix button state */ matrix_button_handle handle; /* the matrix button handle */ struct list_head node; /* all the matrix_buttons object will be added in one matrix button list */ } matrix_button_obj; #define MATRIX_BUTTON_DBG 0 #if MATRIX_BUTTON_DBG #define MATRIX_BUTTON_DEBUG(msg, arg...) printf("[matrix button debug] <%s : %d> " msg "\n", __FUNCTION__, __LINE__, ##arg) #define MATRIX_BUTTON_WARNING(msg, arg...) printf("[matrix button warning] <%s : %d> " msg "\n", __FUNCTION__, __LINE__, ##arg) #else #define MATRIX_BUTTON_DEBUG(msg, arg...) #define MATRIX_BUTTON_WARNING(msg, arg...) #endif #define MATRIX_BUTTON_ERR(msg, arg...) printf("[matrix button err] <%s : %d> " msg "\n", __FUNCTION__, __LINE__, ##arg) static matrix_button_impl_t matrix_button_impl; static struct list_head matrix_buttons_head; static bool matrix_buttons_timer_time_up; static OS_Timer_t matrix_buttons_timer; static OS_Thread_t matrix_buttons_thread; static bool matrix_buttons_thread_run_flag; static uint32_t matrix_buttons_thread_stack_size; static OS_Priority matrix_buttons_thread_priority = OS_PRIORITY_NORMAL; static matrix_button_obj *current_tiggered_obj; #define MATRIX_BUTTONS_THREAD_STACK_SIZE_DEFAULT 512 #define GET_BASE(prt) ((matrix_button_obj *)container_of(prt, matrix_button_obj, handle)) static void short_matrix_button_release(int matrix_buttons_state) { /* a matrix button can be released only when the matrix button state is all 0, * in other cases, it is determined that it is interrupted in midway. Only when the * matrix button has been released, the callback function can be called. */ if (matrix_buttons_state == ALL_MATRIX_BUTTONS_RELEASE) { if (current_tiggered_obj->state == PRESS) { current_tiggered_obj->state = RELEASE; if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); } } /* Whether it is a complete release or a middle interruption, * the matrix button state must set to an invalid state. */ current_tiggered_obj->state = INVALID_STA; /* the pointer can only be reset when the matrix_buttons are fully released. */ if (matrix_buttons_state == ALL_MATRIX_BUTTONS_RELEASE) current_tiggered_obj = NULL; } static void long_matrix_button_release(int matrix_buttons_state) { /* whether the timer is active or not, stop the timer and reset the flag. */ OS_TimerStop(&matrix_buttons_timer); matrix_buttons_timer_time_up = false; if (current_tiggered_obj->state == PRESS || current_tiggered_obj->state == REPEAT_PRESS) { current_tiggered_obj->state = RELEASE; if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); } current_tiggered_obj->state = INVALID_STA; if (matrix_buttons_state == ALL_MATRIX_BUTTONS_RELEASE) current_tiggered_obj = NULL; } static void short_long_matrix_button_release(int matrix_buttons_state) { /* if the timer is active, that mean press_time < timeout_ms. */ if (OS_TimerIsActive(&matrix_buttons_timer)) { /* stop the timer and set the RELEASE state, call the callback function. */ OS_TimerStop(&matrix_buttons_timer); matrix_buttons_timer_time_up = false; current_tiggered_obj->state = RELEASE; if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); } /* else the timer is not active, that mean press_time >= timeout_ms. */ else if (current_tiggered_obj->state == PRESS) { current_tiggered_obj->state = REPEAT_RELEASE; if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); } current_tiggered_obj->state = INVALID_STA; if (matrix_buttons_state == ALL_MATRIX_BUTTONS_RELEASE) current_tiggered_obj = NULL; } static void repeat_long_matrix_button_release(int matrix_buttons_state) { long_matrix_button_release(matrix_buttons_state); } static void combined_long_matrix_button_release(int matrix_buttons_state) { OS_TimerStop(&matrix_buttons_timer); matrix_buttons_timer_time_up = false; if (current_tiggered_obj->state == PRESS) { current_tiggered_obj->state = RELEASE; if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); } current_tiggered_obj->state = INVALID_STA; if (matrix_buttons_state == ALL_MATRIX_BUTTONS_RELEASE) current_tiggered_obj = NULL; } static void short_matrix_button_press(matrix_button_obj *obj) { /* if not NULL, that mean the previous matrix button has not been fully released. */ if (current_tiggered_obj) return; /* set PRESS state of short matrix button */ obj->state = PRESS; /* record the current triggered matrix button object */ current_tiggered_obj = obj; } static void long_matrix_button_press(matrix_button_obj *obj) { OS_Status sta; /* if not NULL, that mean the previous matrix button has not been fully released. */ if (current_tiggered_obj) return; /* set the time */ sta = OS_TimerChangePeriod(&matrix_buttons_timer, obj->timeout_ms); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix button timer change period error"); return; } sta = OS_TimerStart(&matrix_buttons_timer); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix button timer start error"); return; } /* matrix button has not been triggerd, the state should be INVALID_STA. */ obj->state = INVALID_STA; /* record the current triggered matrix button object */ current_tiggered_obj = obj; } static void short_long_matrix_button_press(matrix_button_obj *obj) { long_matrix_button_press(obj); } static void combined_long_matrix_button_press(matrix_button_obj *obj) { OS_Status sta; int matrix_buttons_state = obj->id_mask; /* The combination long matrix button is a subset of long press matrix_buttons. * Because all the matrix_buttons can not be pressed at the same time, * so the combination matrix button can interrupt long press buttton and short press matrix button. */ /* if one matrix button object has been triggered, then release it, interrupt it. */ if (current_tiggered_obj && current_tiggered_obj->func == SHORT_BUTTON) short_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj && current_tiggered_obj->func == LONG_BUTTON) long_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj && current_tiggered_obj->func == SHORT_LONG_BUTTON) short_long_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj && current_tiggered_obj->func == COMBINED_LONG_BUTTON) { combined_long_matrix_button_release(matrix_buttons_state); /* combination matrix button can not interrupt combination matrix button, * and the combination matrix button must wait all the matrix_buttons released. */ return; } /* set the time */ sta = OS_TimerChangePeriod(&matrix_buttons_timer, obj->timeout_ms); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix button timer change period error"); return; } sta = OS_TimerStart(&matrix_buttons_timer); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix button timer start error"); return; } /* matrix button has not been triggerd, the state should be INVALID_STA. */ obj->state = INVALID_STA; /* record the current triggered matrix button object */ current_tiggered_obj = obj; } static void repeat_long_matrix_button_press(matrix_button_obj *obj) { long_matrix_button_press(obj); } static void matrix_button_timer_event(void) { OS_Status sta; if (!current_tiggered_obj) return; /* if current matrix button is LONG_BUTTON/SHORT_LONG_BUTTON/COMBINED_LONG_BUTTON, * matrix button timer time's up mean that the press time long enough than timeout_ms. * so the matrix button state should be set PRESS. */ if (current_tiggered_obj->func == LONG_BUTTON || current_tiggered_obj->func == SHORT_LONG_BUTTON || current_tiggered_obj->func == COMBINED_LONG_BUTTON) { /* set the state */ current_tiggered_obj->state = PRESS; /* call the callback function */ if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); } /* if the matrix button is REPEAT_LONG_BUTTON */ else if (current_tiggered_obj->func == REPEAT_LONG_BUTTON) { /* if the matrix button state is INVALID_STA, that mean it is the first time trigger the matrix button. */ if (current_tiggered_obj->state == INVALID_STA) /* set the PRESS state */ current_tiggered_obj->state = PRESS; /* if the state is PRESS/REPEAT_PRESS, that mean it is not the first time trigger the matrix button. */ else if (current_tiggered_obj->state == PRESS || current_tiggered_obj->state == REPEAT_PRESS) /* set the REPEAT_PRESS state */ current_tiggered_obj->state = REPEAT_PRESS; /* call the callback function */ if (current_tiggered_obj->handle.cb) current_tiggered_obj->handle.cb(current_tiggered_obj->state, current_tiggered_obj->handle.arg); /* whether it is the first time trigger the matrix button or not, the timer should be changed. */ sta = OS_TimerChangePeriod(&matrix_buttons_timer, current_tiggered_obj->repeat_timeout_ms); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix button timer change period error"); return; } sta = OS_TimerStart(&matrix_buttons_timer); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix button timer start error"); return; } } } static void release_current_tiggered_obj(int matrix_buttons_state) { if (!current_tiggered_obj) return; if (current_tiggered_obj->func == SHORT_BUTTON) short_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj->func == LONG_BUTTON) long_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj->func == SHORT_LONG_BUTTON) short_long_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj->func == COMBINED_LONG_BUTTON) combined_long_matrix_button_release(matrix_buttons_state); else if (current_tiggered_obj->func == REPEAT_LONG_BUTTON) repeat_long_matrix_button_release(matrix_buttons_state); } static matrix_button_obj *get_matrix_buttons_obj(uint32_t id_mask) { matrix_button_obj *obj; if (list_empty(&matrix_buttons_head)) return NULL; list_for_each_entry(obj, &matrix_buttons_head, node) if (obj->id_mask == id_mask) return obj; return NULL; } static void matrix_buttons_process_thread(void *arg) { int matrix_buttons_state = 0; int prev_matrix_buttons_state = 0; matrix_button_obj *obj; while (matrix_buttons_thread_run_flag) { /* wait a matrix button trigger */ if (matrix_button_impl.low_level_wait_semaphore) matrix_button_impl.low_level_wait_semaphore(OS_WAIT_FOREVER); /* cycle scan matrix button status */ while (1) { /* if matrix button timer time is up, then process the timer event. */ if (matrix_buttons_timer_time_up) { matrix_button_timer_event(); matrix_buttons_timer_time_up = false; goto contin; } /* get all the matrix_buttons' state form low levle matrix_buttons */ if (matrix_button_impl.low_level_get_state) matrix_buttons_state = matrix_button_impl.low_level_get_state(); else matrix_buttons_state = 0; /* if the matrix_buttons state not change, then continue * sometimes the AD matrix_buttons will trigger by mistake. */ if (prev_matrix_buttons_state == matrix_buttons_state) goto contin; prev_matrix_buttons_state = matrix_buttons_state; #if MATRIX_BUTTON_DBG char s[33] = {0}; int n = matrix_buttons_state; for (int i = 31; i >= 0; i--) s[31-i] = (n&(1<en) goto contin; if (obj->func == SHORT_BUTTON) short_matrix_button_press(obj); else if (obj->func == LONG_BUTTON) long_matrix_button_press(obj); else if (obj->func == SHORT_LONG_BUTTON) short_long_matrix_button_press(obj); else if (obj->func == COMBINED_LONG_BUTTON) combined_long_matrix_button_press(obj); else if (obj->func == REPEAT_LONG_BUTTON) repeat_long_matrix_button_press(obj); } contin: if (matrix_buttons_state != ALL_MATRIX_BUTTONS_RELEASE) OS_MSleep(10); else break; } } OS_ThreadDelete(&matrix_buttons_thread); } static void matrix_buttons_timer_cb(void *arg) { /* release the semaphore, let the matrix_buttons thread running. */ if (matrix_button_impl.low_level_release_semaphore) matrix_button_impl.low_level_release_semaphore(); matrix_buttons_timer_time_up = true; } /** * @brief Set the stack size of the matrix_buttons thread. * @note If the callback function of matrix_buttons need lots of stacks, then need * add the matrix_buttons thread's stack. * @param priority: The stack size of matrix_buttons thread. * @retval void. */ void matrix_buttons_set_thread_stack_size(uint32_t size) { if (size > 0) matrix_buttons_thread_stack_size = size; } /** * @brief Set the priority of the matrix_buttons thread. * @note none. * @param priority: The priority of matrix_buttons thread. * @retval void. */ void matrix_buttons_set_thread_priority(uint32_t priority) { if (priority >= OS_PRIORITY_IDLE && priority <= OS_PRIORITY_REAL_TIME) matrix_buttons_thread_priority = priority; } /** * @brief Buttons initialize. * @note Initialize the matrix button module. * @param impl: The interface that the low level matrix_buttons pass to the matrix_buttons module, * which is used to operate the low level matrix_buttons. * @retval 0: success, -1: fail */ int matrix_buttons_init(matrix_button_impl_t *impl) { int ret; OS_Status sta; if (!impl) { MATRIX_BUTTON_ERR("matrix_buttons impl is NULL"); return -1; } memcpy(&matrix_button_impl, impl, sizeof(matrix_button_impl)); /* initialize the low level matrix_buttons */ if (matrix_button_impl.low_level_init) { ret = matrix_button_impl.low_level_init(); if (ret != 0) { MATRIX_BUTTON_ERR("matrix_buttons low level init err"); return -1; } } matrix_buttons_thread_run_flag = 1; sta = OS_ThreadCreate(&matrix_buttons_thread, "matrix_buttons_thread", matrix_buttons_process_thread, NULL, matrix_buttons_thread_priority != OS_PRIORITY_NORMAL ? matrix_buttons_thread_priority : OS_PRIORITY_NORMAL, matrix_buttons_thread_stack_size > 0 ? matrix_buttons_thread_stack_size : MATRIX_BUTTONS_THREAD_STACK_SIZE_DEFAULT); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix_buttons thread create error"); return -1; } /* create timer for matrix_buttons */ sta = OS_TimerCreate(&matrix_buttons_timer, OS_TIMER_ONCE, matrix_buttons_timer_cb, NULL, OS_WAIT_FOREVER); if (sta != OS_OK) { MATRIX_BUTTON_ERR("matrix_buttons timer create error"); return -1; } INIT_LIST_HEAD(&matrix_buttons_head); return 0; } /** * @brief Buttons deinitialize. * @note Deinitialize the matrix_buttons module. * The interface will delete and free all the matrix_buttons objects. * @param void * @retval 0: success, -1: fail */ int matrix_buttons_deinit(void) { matrix_button_obj *obj_t; if (list_empty(&matrix_buttons_head)) return 0; matrix_buttons_thread_run_flag = 0; /* release the semaphore, * prevent the matrix_buttons thread from waiting for the semaphore all the time. */ if (matrix_button_impl.low_level_release_semaphore) matrix_button_impl.low_level_release_semaphore(); /* waiting for the matrix_buttons thread delete */ while (OS_ThreadIsValid(&matrix_buttons_thread)) OS_MSleep(1); /* delete and free all the matrix button objects */ while (!list_empty(&matrix_buttons_head)) { obj_t = list_first_entry(&matrix_buttons_head, matrix_button_obj, node); list_del(&obj_t->node); free(obj_t); } if (OS_TimerIsValid(&matrix_buttons_timer)) OS_TimerDelete(&matrix_buttons_timer); if (matrix_button_impl.low_level_deinit) matrix_button_impl.low_level_deinit(); memset(&matrix_button_impl, 0, sizeof(matrix_button_impl)); return 0; } static void matrix_button_start(matrix_button_handle *handle) { matrix_button_obj *obj = GET_BASE(handle); obj->en = 1; } static void matrix_button_stop(matrix_button_handle *handle) { matrix_button_obj *obj = GET_BASE(handle); obj->en = 0; } static int matrix_button_get_state(matrix_button_handle *handle) { matrix_button_obj *obj = GET_BASE(handle); return obj->state == PRESS ? PRESS : RELEASE; } static int matrix_button_destroy(matrix_button_handle *handle) { matrix_button_obj *obj = GET_BASE(handle); matrix_button_obj *obj_t; if (obj == current_tiggered_obj) { MATRIX_BUTTON_ERR("the matrix button is working, can not destroy"); return -1; } if (list_empty(&matrix_buttons_head)) return -1; /* delete and free the matrix button object from matrix_buttons list head */ list_for_each_entry(obj_t, &matrix_buttons_head, node) { if (obj_t == obj) { list_del(&obj->node); free(obj); return 0; } } return 0; } /** * @brief Create one short matrix button. * @note The short matrix button has only the RELEASE state. When it pressed, the * callback function of the matrix button object will not be called. * When it released, the callback function will be called and pass the * RELEASE state immediately. * @param id_mask: the matrix button id * @retval The matrix button object handle, NULL if create failed. */ matrix_button_handle *create_short_matrix_button(uint32_t id_mask) { uint32_t num = id_mask; int count = 0; /* record how many '1' in id_mask */ while (num) { if (num & 1) count++; num >>= 1; } /* not support multiple matrix_buttons */ if (count != 2) { MATRIX_BUTTON_ERR("short matrix button must only 1 matrix_buttons"); return NULL; } matrix_button_obj *obj; /* check if the matrix button object exists */ obj = get_matrix_buttons_obj(id_mask); if (obj) { MATRIX_BUTTON_ERR("matrix button %x object has already exist", id_mask); return NULL; } obj = (matrix_button_obj *) malloc(sizeof(matrix_button_obj)); if (obj == NULL) { MATRIX_BUTTON_ERR("matrix button object malloc error"); return NULL; } memset(obj, 0, sizeof(matrix_button_obj)); obj->state = INVALID_STA; obj->id_mask = id_mask; obj->func = SHORT_BUTTON; obj->handle.start = matrix_button_start; obj->handle.stop = matrix_button_stop; obj->handle.get_state = matrix_button_get_state; obj->handle.destroy = matrix_button_destroy; /* add matrix button object to matrix_buttons list head */ list_add_tail(&obj->node, &matrix_buttons_head); return &obj->handle; } /** * @brief Create one long matrix button. * @note The long matrix button has the PRESS/RELEASE state. When it pressed for * more than timeout_ms milliseconds, the callback function of the matrix button * object will be called and pass the PRESS state. When it released, the * callback function will be called and pass the RELEASE state. If release * the matrix button earlier than timeout_ms, nothing will happen, the callback * function will not be called. * @param id_mask: the matrix button id * timeout_ms:the timeout to trigger PRESS state. * @retval The matrix button object handle, NULL if create failed. */ matrix_button_handle *create_long_matrix_button(uint32_t id_mask, uint32_t timeout_ms) { uint32_t num = id_mask; int count = 0; while (num) { if (num & 1) count++; num >>= 1; } if (count != 2) { MATRIX_BUTTON_ERR("long matrix button must only 1 matrix_buttons"); return NULL; } matrix_button_obj *obj; obj = get_matrix_buttons_obj(id_mask); if (obj) { MATRIX_BUTTON_ERR("matrix button %x object has already exist", id_mask); return NULL; } obj = (matrix_button_obj *) malloc(sizeof(matrix_button_obj)); if (obj == NULL) { MATRIX_BUTTON_ERR("matrix button object malloc error"); return NULL; } memset(obj, 0, sizeof(matrix_button_obj)); obj->state = INVALID_STA; obj->id_mask = id_mask; obj->func = LONG_BUTTON; obj->timeout_ms = timeout_ms; obj->handle.start = matrix_button_start; obj->handle.stop = matrix_button_stop; obj->handle.get_state = matrix_button_get_state; obj->handle.destroy = matrix_button_destroy; list_add_tail(&obj->node, &matrix_buttons_head); return &obj->handle; } /** * @brief Create one short_long matrix button. * @note The short_long matrix button has the PRESS/RELEASE/REPEAT_RELEASE state. * PRESS: if the matrix button pressed for more than timeout_ms(press_time >= timeout_ms), * this state will be passed to callback function. * RELEASE: if the matrix button released earlier than timeout_ms(press_time < timeout_ms), * this state will be passed to callback function. * REPEAT_RELEASE: if the matrix button pressed more than timeout_ms and released(press_time >= timeout_ms), * this state will be passed to callback function. * @param id_mask: the matrix button id * timeout_ms:the timeout to trigger PRESS state. * @retval The matrix button object handle, NULL if create failed. */ matrix_button_handle *create_short_long_matrix_button(uint32_t id_mask, uint32_t timeout_ms) { uint32_t num = id_mask; int count = 0; while (num) { if (num & 1) count++; num >>= 1; } if (count != 2) { MATRIX_BUTTON_ERR("short and long matrix button must only 1 matrix_buttons"); return NULL; } matrix_button_obj *obj; obj = get_matrix_buttons_obj(id_mask); if (obj) { MATRIX_BUTTON_ERR("matrix button %x object has already exist", id_mask); return NULL; } obj = (matrix_button_obj *) malloc(sizeof(matrix_button_obj)); if (obj == NULL) { MATRIX_BUTTON_ERR("matrix button object malloc error"); return NULL; } memset(obj, 0, sizeof(matrix_button_obj)); obj->state = INVALID_STA; obj->id_mask = id_mask; obj->func = SHORT_LONG_BUTTON; obj->timeout_ms = timeout_ms; obj->handle.start = matrix_button_start; obj->handle.stop = matrix_button_stop; obj->handle.get_state = matrix_button_get_state; obj->handle.destroy = matrix_button_destroy; list_add_tail(&obj->node, &matrix_buttons_head); return &obj->handle; } /** * @brief Create one combined long matrix button. * @note The combined matrix button has the PRESS/RELEASE state. Combined long * matrix button support multiple matrix_buttons, for example, key1|key2|key3, when all * the three matrix_buttons are pressed and more than timeout_ms(all_press_time >= timeout_ms), * the PRESS state will be passed to callback function. If any matrix button released, * the RELEASE state will be passed to callback function. If any matrix button released * earlier than timeout_ms(all_press_time < timeout_ms), nothing will happen. * @param id_mask: the matrix button id, support multiple matrix_buttons(KEY1|KEY2|KEY3). * timeout_ms:the timeout to trigger PRESS state. * @retval The matrix button object handle, NULL if create failed. */ matrix_button_handle *create_combined_long_matrix_button(uint32_t id_mask, uint32_t timeout_ms) { uint32_t num = id_mask; int count = 0; while (num) { if (num & 1) count++; num >>= 1; } if (count < 3) { MATRIX_BUTTON_ERR("combined matrix button must have more than 2 matrix_buttons"); return NULL; } matrix_button_obj *obj; obj = get_matrix_buttons_obj(id_mask); if (obj) { MATRIX_BUTTON_ERR("matrix button %x object has already exist", id_mask); return NULL; } obj = (matrix_button_obj *) malloc(sizeof(matrix_button_obj)); if (obj == NULL) { MATRIX_BUTTON_ERR("matrix button object malloc error"); return NULL; } memset(obj, 0, sizeof(matrix_button_obj)); obj->state = INVALID_STA; obj->id_mask = id_mask; obj->func = COMBINED_LONG_BUTTON; obj->timeout_ms = timeout_ms; obj->handle.start = matrix_button_start; obj->handle.stop = matrix_button_stop; obj->handle.get_state = matrix_button_get_state; obj->handle.destroy = matrix_button_destroy; list_add_tail(&obj->node, &matrix_buttons_head); return &obj->handle; } /** * @brief Create one repeat long matrix button. * @note The repeat long matrix button has the PRESS/RELEASE/REPEAT_PRESS state. * PRESS: if the matrix button pressed for more than timeout_ms(press_time >= timeout_ms), * this state will be passed to callback function. * RELEASE: if the matrix button pressed for more than timeout_ms and released, * this state will be passed to callback function. * REPEAT_PRESS: if the matrix button pressed all the time, the callback function * will be called in every repeat_timeout_ms, and REPEAT_PRESS * will be passed to callback. * @param id_mask: the matrix button id. * timeout_ms:the timeout to trigger PRESS state. * repeat_timeout_ms: the timeout to trigger REPEAT_PRESS state. * @retval The matrix button object handle, NULL if create failed. */ matrix_button_handle *create_repeat_long_matrix_button(uint32_t id_mask, uint32_t timeout_ms, uint32_t repeat_timeout_ms) { uint32_t num = id_mask; int count = 0; while (num) { if (num & 1) count++; num >>= 1; } if (count != 2) { MATRIX_BUTTON_ERR("repeat long matrix button must only 1 matrix_buttons"); return NULL; } matrix_button_obj *obj; obj = get_matrix_buttons_obj(id_mask); if (obj) { MATRIX_BUTTON_ERR("matrix button %x object has already exist", id_mask); return NULL; } obj = (matrix_button_obj *) malloc(sizeof(matrix_button_obj)); if (obj == NULL) { MATRIX_BUTTON_ERR("matrix button object malloc error"); return NULL; } memset(obj, 0, sizeof(matrix_button_obj)); obj->state = INVALID_STA; obj->id_mask = id_mask; obj->func = REPEAT_LONG_BUTTON; obj->timeout_ms = timeout_ms; obj->repeat_timeout_ms = repeat_timeout_ms; obj->handle.start = matrix_button_start; obj->handle.stop = matrix_button_stop; obj->handle.get_state = matrix_button_get_state; obj->handle.destroy = matrix_button_destroy; list_add_tail(&obj->node, &matrix_buttons_head); return &obj->handle; }