├── .gitattributes ├── LICENSE ├── README.md ├── SConscript ├── _config.yml ├── examples └── mfbd_demo_rtt.c ├── mfbd.c ├── mfbd.h ├── mfbd_cfg.h ├── mfbd_sd.c └── mfbd_sd.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi-Function Button Dectection 2 | 3 | Multi-Function Button Dectection,简称MFBD,是一个基于嵌入式C语言的按键库,自动消抖,支持单击、长按单次触发、长按连续触发、双击、多击(三击、四击等等,最大256击)按键操作,可以运行于裸机和各类RTOS。 4 | 5 | ## MFBD设计理念 6 | 7 | MFBD尽可能的减少了RAM的使用,将能保存在Flash中的参数都保存在Flash中。 8 | 当然还可以继续将变量放置在RAM中,这也会减少编写程序时候的工作量。 9 | MFBD通过类似电脑对按键的处理方式,将每个按键的不同操作分配不同的键值。 10 | 同时mfbd采用了回调函数的机制,通过回调函数将键值上报到上层应用程序,当然用户也可以直接在回调函数中进行操作。 11 | 12 | ## MFBD版本 13 | 14 | MFBD有传统定义方式和利用编译器特性的段定义(Section-Definition)方式。 15 | 使用段定义方式将会极大程度减少代码编写量,但是会受限于编译器,目前仅支持`Keil`,`IAR`,`GCC`。 16 | 通过配置`mfbd_cfg.h`中的`MFBD_USE_SECTION_DEFINITION`为`0`或`非0`,为`非0`时即可启用段定义。即使用`mfbd_sd.c`和`mfbd_sd.h`中的API。 17 | 18 | 普通定义请看[如下章节](#mfbd-button定义) 19 | 20 | 段定义请看[如下章节](#mfbd段定义) 21 | 22 | 两者之间程序不兼容,需要重新写程序。 23 | 24 | ## MFBD移植和配置 25 | 26 | MFBD移植只需将文件添加到工程目录即可,配置项都已经汇总到mfbd_cfg.h中: 27 | 28 | ```c 29 | /* mfbd_btn_code_t is the type of value of every button event. */ 30 | typedef uint16_t mfbd_btn_code_t; 31 | 32 | /* mfbd_btn_count_t is the type of count time for button scanning. */ 33 | typedef uint16_t mfbd_btn_count_t; 34 | 35 | /* mfbd_btn_index_t is the type of params when calling is_btn_down_func in mfbd_group_t. */ 36 | typedef uint32_t mfbd_btn_index_t; 37 | 38 | /* set MFBD_USE_TINY_BUTTON to 1 will enable tiny button functions. */ 39 | #define MFBD_USE_TINY_BUTTON 1 40 | 41 | /* set MFBD_USE_NORMAL_BUTTON to 1 will enable normal button functions. */ 42 | #define MFBD_USE_NORMAL_BUTTON 1 43 | 44 | /* set MFBD_USE_MULTIFUCNTION_BUTTON to 1 will enable multifunction button functions. */ 45 | #define MFBD_USE_MULTIFUCNTION_BUTTON 1 46 | 47 | /* set MFBD_USE_BTN_SCAN_PRE_FUNC to 1 will enable running prepare_function before run button detection function */ 48 | #define MFBD_USE_BTN_SCAN_PRE_FUNC 0 49 | 50 | /* set MFBD_USE_BTN_SCAN_AFTER_FUNC to 1 will enable running after_function after run button detection function */ 51 | #define MFBD_USE_BTN_SCAN_AFTER_FUNC 0 52 | 53 | /* 54 | * @Note: 55 | * set MFBD_PARAMS_SAME_IN_GROUP to 1 means all key's filter_time/repeat_time/long_time/multiclick_time are same, 56 | * it will not save filter_time/repeat_time/long_time/multiclick_time in btn_info struct. 57 | * if MFBD_PARAMS_SAME_IN_GROUP is 1, btns cannot disable repeat count alone. 58 | */ 59 | #define MFBD_PARAMS_SAME_IN_GROUP 1 60 | 61 | /* set MFBD_MULTICLICK_STATE_AUTO_RESET to 1 will auto set multiclick state to 0 when reach to max multicick state. */ 62 | #define MFBD_MULTICLICK_STATE_AUTO_RESET 1 63 | 64 | /* set MFBD_MBTN_CONTINUE_LONG_COUNT to 1 will continue count to change state to long after when multiclick state is not 0. */ 65 | #define MFBD_MBTN_CONTINUE_LONG_COUNT 0 66 | 67 | /* 68 | * @Note: 69 | * MFBD_MBTN_MULTICLICK_LONG_EVT only valid when MFBD_MBTN_CONTINUE_LONG_COUNT is not 0. 70 | * When MFBD_MBTN_MULTICLICK_LONG_EVT is 1, it will still report long code and repeat downcodes after multiclick. 71 | */ 72 | #define MFBD_MBTN_MULTICLICK_LONG_EVT 0 73 | 74 | ``` 75 | 76 | `mfbd_btn_code_t`:按键键值的类型。 77 | 可以根据按键事件的多少进行设置。例如有127个按键,每个按键只有按下和松开两个事件,那么就可以设置为`uint8_t`。 78 | 一般情况下推荐使用`uint16_t`。 79 | 80 | `mfbd_btn_count_t`:按键检测时时间计数参数的类型。 81 | 如果为`uint8_t`,那么时间计数无法超过255,此时如果检测周期为10ms,那么将无法进行255*10ms以上的检测操作。 82 | 一般情况下推荐使用`uint16_t`。 83 | 84 | `mfbd_btn_index_t`:调用按键检测函数时传入的参数类型。 85 | 按键检测函数为每个按键组都有自己单独的一个按键检测函数,在检测按键时,函数需要传入一个参数,该参数类型可根据芯片需求自定。 86 | 87 | `MFBD_USE_TINY_BUTTON`:是否使用`tiny button`相关函数和定义。 88 | 因在`mfbd_group_t`结构体中会存放`tiny button`,`normal button`,`multi-function button`三个地址数组的指针,所以会占用3个4字节,通过开关不同的宏定义,可以精简程序空间。 89 | 90 | `MFBD_USE_NORMAL_BUTTON`:是否使用`normal button`相关函数和定义。 91 | 92 | `MFBD_USE_MULTIFUCNTION_BUTTON`:是否使用`multi-function button`相关函数和定义。 93 | 94 | `MFBD_USE_BTN_SCAN_PRE_FUNC`:是否使能在检测每组按键之前调用准备函数。 95 | 该选项非常适合矩阵键盘,矩阵键盘每次扫描后都可以获得所有按键的状态,而无需每次检测一个按键。 96 | 通过使能该函数,可以将矩阵按键的键值存入一个缓冲区,然后该按键组的按键读取函数只需要从缓冲区中读取相应的数值即可。 97 | 98 | `MFBD_USE_BTN_SCAN_AFTER_FUNC`:是否使能在检测每组按键之后调用结束函数。 99 | 该选项可以用来进行低功耗管理,通过在检测后关闭相应外设的电源等操作。 100 | 101 | `MFBD_PARAMS_SAME_IN_GROUP`:当所有按键的扫描滤波时间、长按时间、重复上报时间、连击释放时间一致的时候,可以将该宏置为`1`。此时,每个按键的info结构体中将不再存放上述事件参数,而把时间参数存放在group结构体中。当该选项使能的时候,无法在启用长按事件(long count)的时候单独禁用某个按键的重复上报事件(repeat count),但可以通过设置`repeat_time = 0`禁用全部按键的重复上报事件。 102 | 103 | `MFBD_MULTICLICK_STATE_AUTO_RESET`:当mbtn达到最大连击次数时,连击次数是否自动返回未连击状态。为`1`,则自动返回0状态,下次连击则返回按键连击0按键码,为`0`,则必须等带连击释放时间达到后,才会自动返回0状态,下次连击则返回按键连击最高状态按键码。 104 | 105 | `MFBD_MBTN_CONTINUE_LONG_COUNT`:当mbtn触发连击后,是否继续进行长按检测,为`1`,则会继续检测长按状态,为`0`,则不会继续检测。 106 | 107 | `MFBD_MBTN_MULTICLICK_LONG_EVT`:本宏只在`MFBD_MBTN_CONTINUE_LONG_COUNT`为`1`时生效。为`1`,则会继续上报多击长按后继续上报按键值,长按上报长按键值后,继续计数在重复事件发生后,会上报本次连击的按键值;为`0`,则不会上报按键值,只会改变按键状态,而且mbtn的重复事件被禁用。 108 | 109 | ## MFBD按键事件 110 | 111 | ### 单击事件 112 | 113 | 单击事件分为按下事件和松开事件。 114 | 按下事件发生后,如果按下的按键值不为0,就会上报按下按键值。 115 | 松开事件发生后,如果松开的按键值不为0,就会上报松开按键值。 116 | 117 | ### 长按事件 118 | 119 | 单击事件分为长按连续触发事件和长按单次触发事件。 120 | **长按连续触发事件**效果为当按键持续按下时,持续按下达到一个特定的时间后,上报一次长按按键值,然后开始每隔特定的时间后,继续上报按键值。 121 | **长按单次触发事件**效果为当按键持续按下时,只检测一个特定的长时间后,上报一次长按按键值。如果不想上报单独的长按按键值,长按只重复上报按键值的话,将长按按键值设置和按下按键值一样即可。 122 | 123 | ### 连击事件 124 | 125 | 连击事件指的是在按键松开后的指定时间后,再一次检测到按键按下。 126 | 连击事件中,每次按键按下后,都会上报指定次数的连击按键值。 127 | 其实连击事件是不应该由按键驱动层进行检测的,但是嵌入式环境资源紧张,不可以像电脑那样交给应用层处理。 128 | **注意:多次连击事件和长按事件是冲突的,当长按事件发生,不会进行多次连击的检测。当触发多次连击检测后,也不会进行长按事件的检测** 129 | 在1.0.5版本后,可以通过配置宏`MFBD_MBTN_CONTINUE_LONG_COUNT`为1,和`MFBD_MBTN_MULTICLICK_LONG_EVT`为1,可以实现连击和长按的共存。 130 | 131 | ## MFBD按键组结构体 132 | 133 | MFBD的函数调用的参数都是MFBD按键组结构体指针,用户需要独立编写给其赋值。 134 | 135 | ```c 136 | /* mfbd group struct */ 137 | typedef struct _mfbd_group_struct 138 | { 139 | /* used to read whether button is down. */ 140 | unsigned char (*is_btn_down_func)(mfbd_btn_index_t btn_index); 141 | 142 | /* used to report btn_value, must have a legal value, must not be NULL. */ 143 | void (*btn_value_report)(mfbd_btn_code_t btn_value); 144 | 145 | #if MFBD_USE_TINY_BUTTON 146 | /* pointer to the head of tiny buttons array */ 147 | mfbd_tbtn_t **tbtns; 148 | #endif 149 | 150 | #if MFBD_USE_NORMAL_BUTTON 151 | /* pointer to the head of normal buttons array */ 152 | mfbd_nbtn_t **nbtns; 153 | #endif 154 | 155 | #if MFBD_USE_MULTIFUCNTION_BUTTON 156 | /* pointer to the head of multifunction buttons array */ 157 | mfbd_mbtn_t **mbtns; 158 | #endif 159 | 160 | /* if set MFBD_PARAMS_SAME_IN_GROUP to 1, all btns in group has same params. */ 161 | #if MFBD_PARAMS_SAME_IN_GROUP 162 | 163 | #if MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 164 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 165 | #endif /* MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 166 | 167 | #if MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 168 | 169 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 170 | 171 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 172 | 173 | #endif /* MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 174 | 175 | #if MFBD_USE_MULTIFUCNTION_BUTTON 176 | 177 | mfbd_btn_count_t multiclick_time; /* multi-click time when button still up, set 0 will disable multi-click time count. */ 178 | 179 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 180 | 181 | #endif 182 | 183 | #if MFBD_USE_BTN_SCAN_PRE_FUNC 184 | /* prepare function when start to scan buttons for each group. */ 185 | void (*btn_scan_prepare)(void); 186 | #endif 187 | 188 | #if MFBD_USE_BTN_SCAN_AFTER_FUNC 189 | /* function after scanning buttons for each group. */ 190 | void (*btn_scan_after)(void); 191 | #endif 192 | 193 | } mfbd_group_t; 194 | ``` 195 | 196 | **按键组结构体成员介绍:** 197 | 198 | | 数据成员 | 说明 | 199 | | :---- | :---- | 200 | | `is_btn_down_func` | 按键组中按键的获取按键状态的函数。 | 201 | | `btn_value_report` | 按键组中按键事件触发后上报按键值的函数。 | 202 | | `tbtns` | tbtn按键地址数组的首地址,扫描程序通过该指针为入口,扫描tbtn组的按键,通过宏定义`MFBD_USE_TINY_BUTTON`开启。 | 203 | | `nbtns` | nbtn按键地址数组的首地址,扫描程序通过该指针为入口,扫描nbtn组的按键,通过宏定义`MFBD_USE_TINY_BUTTON`开启。 | 204 | | `mbtns` | mbtn按键地址数组的首地址,扫描程序通过该指针为入口,扫描mbtn组的按键,通过宏定义`MFBD_USE_TINY_BUTTON`开启。 | 205 | | `filter_time` | 按键按下和松开的滤波时间,当MFBD_PARAMS_SAME_IN_GROUP为1时,该时间参数存放到GROUP结构体中。 | 206 | | `repeat_time` | 按键长按事件发生后,重复上报btn_down_code的时间周期,如果设置为0,不会检测长按后的重复事件。当MFBD_PARAMS_SAME_IN_GROUP为1时,该时间参数存放到GROUP结构体中。 | 207 | | `long_time` | 按键长按事件触发时间,如果设置为0,不会检测长按事件(包括长按后的重复事件)。当MFBD_PARAMS_SAME_IN_GROUP为1时,该时间参数存放到GROUP结构体中。 | 208 | | `multiclick_time` | 按键连按事件的终止时间。当MFBD_PARAMS_SAME_IN_GROUP为1时,该时间参数存放到GROUP结构体中。 | 209 | | `btn_scan_prepare` | 按键组开始扫描前的准备函数,通过宏定义`MFBD_USE_BTN_SCAN_PRE_FUNC`开启,设置为NULL时不会调用。 | 210 | | `btn_scan_after` | 按键组完成扫描后的函数,通过宏定义`MFBD_USE_BTN_SCAN_AFTER_FUNC`开启,设置为NULL时不会调用。 | 211 | 212 | ## MFBD按键结构体 213 | 214 | MFBD提供了三种按键处理,之所以提供三种按键处理,是为了开发中可以根据不同项目中不同按键的不同情况,自由的减少RAM的占用。 215 | 216 | 1. **tiny button**:只支持Button单击的操作,不支持按键其他操作,在普通的场景中应用广泛。 217 | 2. **normal button**:normal button支持Button单击、长按的操作,不支持多次连击操作。normal button是很类似于电脑按键处理的,只是多了一个长按单次触发事件(可以通过将btn_long_code设置为0,来禁用长按单次触发事件)。 218 | 3. **multi-function button**:multi-function button支持单击、长按、多次连击的操作。 219 | 三种按键的结构体中同名的成员功能是基本相同的。 220 | 221 | **按键信息结构体成员介绍:** 222 | 223 | | 数据成员 | 说明 | 224 | | :---- | :---- | 225 | | `filter_time` | 按键按下和松开的滤波时间,当MFBD_PARAMS_SAME_IN_GROUP为0时,该时间参数存放到每个按键信息结构体中。 | 226 | | `repeat_time` | 按键长按事件发生后,重复上报btn_down_code的时间周期,如果设置为0,不会检测长按后的重复事件。当MFBD_PARAMS_SAME_IN_GROUP为0时,该时间参数存放到每个按键信息结构体中。 | 227 | | `long_time` | 按键长按事件触发时间,如果设置为0,不会检测长按事件(包括长按后的重复事件)。当MFBD_PARAMS_SAME_IN_GROUP为0时,该时间参数存放到每个按键信息结构体中。 | 228 | | `multiclick_time` | 按键连按事件的终止时间。当MFBD_PARAMS_SAME_IN_GROUP为0时,该时间参数存放到每个按键信息结构体中。 | 229 | | `btn_down_code` | tbtn和nbtn按键按下后,需要上报的键值。如果设置为0,就不会上报。 | 230 | | `*btn_down_code` | mbtn中,按键多次按下后,需要上报的键值数组指针,不可以为NULL。数组中按键值为0的,不会上报。 | 231 | | `btn_up_code` | 按键按下后再松开后,需要上报的键值。如果设置为0,就不会上报。 | 232 | | `btn_long_code` | 按键长按后,需要上报的键值。如果设置为0,就会禁用长按检测和重复上报检测。 | 233 | | `btn_index` | 按键组扫描时,调用按键组结构体中`is_btn_down_func`所传入的参数。 | 234 | | `max_multiclick_state`| mbtn按键最大支持的连击次数。 | 235 | 236 | **按键控制结构体成员介绍:** 237 | 238 | | 数据成员 | 说明 | 239 | | :---- | :---- | 240 | | `*btn_info` | 指向每一个按键的键值和扫描参数信息。 | 241 | | `filter_count` | 用于记录按键滤波时间和内部判断按键状态。 | 242 | | `long_count` | 用于记录按键长按事件触发时间。 | 243 | | `repeat_count` | 用于记录按键长按事件发生后的重复上报时间。 | 244 | | `multiclick_count` | 用于记录按键松开事件发生后,重置多次连击状态multiclick_state的时间。 | 245 | | `multiclick_state` | 用于记录按键连击状态。 | 246 | | `state` | 用于记录当前按键的状态和内部判断。 | 247 | 248 | ## MFBD button定义 249 | 250 | MFBD使用略微复杂,但是给开发者提供了更大的自由度。 251 | 但是在按键程序编写完成后,其他应用程序获取按键值将变得十分容易,无需关注按键硬件层,只需要根据不同的按键值做出相应的操作即可。 252 | ringbuf环形缓冲区是MFBD的好搭档,推荐移植使用时和ringbuf配合,来上报和获取按键值。 253 | 各类RTOS中的MailBox邮箱机制也是一个搭配使用不错的选择。 254 | 为了方便定义按键结构体,`mfbd.h`中提供了宏定义供用户定义按键使用。用户也可以自行通过结构体定义。 255 | 宏定义`MFBD_PARAMS_SAME_IN_GROUP`是否为0,定义方式的参数是不一样的。 256 | 257 | ### tiny button定义示例 258 | 259 | ```c 260 | #if MFBD_BTN_PARAMS_SAME 261 | /* MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) */ 262 | MFBD_TBTN_DEFINE(test_tbtn, 1, 0x1201, 0x1200); 263 | #else 264 | /* MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) */ 265 | MFBD_TBTN_DEFINE(test_tbtn, 1, 3, 0x1201, 0x1200); 266 | #endif /*MFBD_BTN_PARAMS_SAME*/ 267 | ``` 268 | 269 | ### normal button定义示例 270 | 271 | ```c 272 | #if MFBD_BTN_PARAMS_SAME 273 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 274 | MFBD_NBTN_DEFINE(test_nbtn1, 3, 0x1401, 0x1400, 0x1402); 275 | #else 276 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 277 | MFBD_NBTN_DEFINE(test_nbtn1, 3, 3, 0, 150, 0x1401, 0x1400, 0x1402); 278 | #endif /*MFBD_BTN_PARAMS_SAME*/ 279 | ``` 280 | 281 | ### multi-function button定义示例 282 | 283 | multi-function button和其他按键不同,它的宏定义中使用了可变参数,由于可变参数只可以在末尾,所以一并将BTN_DOWN_CODE参数放到了后边 284 | 可变参数可以方便的定义出不同数量的按键值数组,方便连击事件的按键值赋值 285 | 286 | ```c 287 | #if MFBD_BTN_PARAMS_SAME 288 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 289 | MFBD_MBTN_DEFINE(test_mbtn, 4, 3, 0x1501, 0x1500, 0, 0x1511, 0x1521, 0x1531); 290 | #else 291 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 292 | MFBD_MBTN_DEFINE(test_mbtn, 4, 3, 30, 150, 75, 3, 0x1501, 0x1500, 0, 0x1511, 0x1521, 0x1531); 293 | #endif /*MFBD_BTN_PARAMS_SAME*/ 294 | ``` 295 | 296 | ### 默认定义 297 | 298 | 为了方便定义,还引入了默认定义宏 299 | 300 | ```c 301 | MFBD_TBTN_DEFAULT_DEFINE(NAME, ...); 302 | MFBD_NBTN_DEFAULT_DEFINE(NAME, ...); 303 | MFBD_MBTN_DEFAULT_DEFINE(NAME, ...); 304 | ``` 305 | 306 | 在使用DEFAULT_DEFINE时,会自动使用按键名称为扩展的枚举或宏变量值。 307 | 308 | ```MFBD_TBTN_DEFAULT_DEFINE(HI, ...)```,将会默认使用```HI_DOWN_CODE```和```HI_UP_CODE```作为按键值。所以程序中需要准备好该两个名称的按键值枚举变量或宏定义。 309 | 310 | ```MFBD_NBTN_DEFAULT_DEFINE(HI, ...)```,将会默认使用```HI_DOWN_CODE```、```HI_UP_CODE```和```HI_LONG_CODE```作为按键值。所以程序中需要准备好该三个名称的按键值枚举变量或宏定义。 311 | 312 | ```MFBD_MBTN_DEFAULT_DEFINE(HI, ...)```,将会默认使用```HI_UP_CODE```和```HI_LONG_CODE```作为按键值。所以程序中需要准备好该两个名称的按键值枚举变量或宏定义。另外MBTN需要提供一个变量名为```HI_DOWN_CODES```的按键值数组,作为多次连击的按键值。 313 | 314 | 可以通过在枚举变量时,使用如下宏定义,来快速生成名称: 315 | 316 | ```c 317 | #define MFBD_DOWN_CODE_NAME(NAME) NAME##_DOWN_CODE /* when using tbtn/nbtn default define api, this is down-code name. */ 318 | #define MFBD_UP_CODE_NAME(NAME) NAME##_UP_CODE /* when using tbtn/nbtn/mbtn default define api, this is up-code name. */ 319 | #define MFBD_LONG_CODE_NAME(NAME) NAME##_LONG_CODE /* when using nbtn/mbtn default define api, this is long-code name. */ 320 | ``` 321 | 322 | mbtn需要提供数组来代表各种连击时发送的按键值,数组名参考下面的宏定义: 323 | 324 | ```c 325 | #define MFBD_DOWN_CODES_NAME(NAME) NAME##_DOWN_CODES /* when using mbtn default define api, this is long-codes name. */ 326 | 327 | mfbd_btn_code_t MFBD_DOWN_CODES_DEF(mbtn)[4] = {0x1501, 0x1511, 0x1521, 0x1531}; /* example */ 328 | ``` 329 | 330 | ## MFBD 使用示例 331 | 332 | 这里使用上方MFBD定义示例中宏定义的方式定义按键进行操作 333 | 示例中:按键按下低电平,按键弹起高电平 334 | 按键上报函数和读取函数统一如下 335 | 336 | ### 按键组GROUP中读取按键的接口函数 337 | 338 | 在读取按键状态的函数中,如果按键按下了,应当返回`MFBD_BTN_STATE_DOWN`,否则返回`MFBD_BTN_STATE_UP`。 339 | 340 | 针对在矩阵键盘中鬼键,还有另一个状态`MFBD_BTN_STATE_SKIP`,当函数返回`MFBD_BTN_STATE_SKIP`后,MFBD会直接跳过对该按键的检测。 341 | 342 | ```c 343 | unsigned char bsp_btn_check(mfbd_btn_index_t btn_index) 344 | { 345 | switch (btn_index) 346 | { 347 | case 1: 348 | if (rt_pin_read(BTN_KEY0) == 0) 349 | { 350 | return MFBD_BTN_STATE_DOWN; 351 | } 352 | break; 353 | case 2: 354 | if (rt_pin_read(BTN_KEY1) == 0) 355 | { 356 | return MFBD_BTN_STATE_DOWN; 357 | } 358 | break; 359 | case 3: 360 | if (rt_pin_read(BTN_KEY2) == 0) 361 | { 362 | return MFBD_BTN_STATE_DOWN; 363 | } 364 | break; 365 | case 4: 366 | if (rt_pin_read(BTN_WK_UP) == 1) 367 | { 368 | return MFBD_BTN_STATE_DOWN; 369 | } 370 | break; 371 | default: 372 | break; 373 | } 374 | return MFBD_BTN_STATE_UP; 375 | } 376 | ``` 377 | 378 | ### 按键组GROUP中上报按键的接口函数 379 | 380 | ```c 381 | void bsp_btn_value_report(mfbd_btn_code_t btn_value) 382 | { 383 | rt_kprintf("%04x\n", btn_value); 384 | } 385 | ``` 386 | 387 | ### 按键组GROUP定义示例 388 | 389 | 按键组GROUP需要将组内的tbtn、nbtn、mbtn分别组成数组,然后将数组头指针赋值到结构体中 390 | 391 | ```c 392 | MFBD_TBTN_ARRAYLIST(test_tbtn_list, &test_tbtn); 393 | 394 | MFBD_NBTN_ARRAYLIST(test_nbtn_list, &test_nbtn1, &test_nbtn); 395 | 396 | MFBD_MBTN_ARRAYLIST(test_mbtn_list, &test_mbtn); 397 | 398 | const mfbd_group_t test_btn_group = 399 | { 400 | bsp_btn_check, 401 | bsp_btn_value_report, 402 | test_tbtn_list, 403 | test_nbtn_list, 404 | test_mbtn_list, 405 | 406 | #if MFBD_PARAMS_SAME_IN_GROUP 407 | 408 | #if MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 409 | 3, 410 | #endif /* MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 411 | 412 | #if MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 413 | 30, 414 | 150, 415 | #endif /* MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 416 | 417 | #if MFBD_USE_MULTIFUCNTION_BUTTON 418 | 75, 419 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 420 | 421 | #endif /*MFBD_PARAMS_SAME_IN_GROUP*/ 422 | 423 | }; 424 | ``` 425 | 426 | ### 按键检测函数调用 427 | 428 | 在其他配置都已完成后,只需定时调用检测函数即可完成对按键组的检测并上报兼职。 429 | 430 | ```c 431 | extern void mfbd_group_scan(const mfbd_group_t *_pbtn_group); 432 | ``` 433 | 434 | ### 停止按键检测 435 | 436 | 在某些场景下可能需要临时停止按键检测,可以调用下面的函数复位按键组内所有的信息。 437 | 438 | ```c 439 | extern void mfbd_group_reset(const mfbd_group_t *_pbtn_group); 440 | ``` 441 | ### 如果一段时间没有调用按键检测,可以使用SKIP的API来跳过一段时间 442 | 443 | 可以在睡眠时调用此函数,此函数不会上报键值,只是更新计数时间,使用按键当前的状态直接进行计数`times`次时间。`tbtn`由于状态只有按下弹起,所以不支持此功能。 444 | 445 | ```c 446 | extern void mfbd_group_skip(const mfbd_group_t *_pbtn_group, mfbd_btn_count_t times); 447 | ``` 448 | 449 | ## MFBD段定义 450 | 451 | 段定义(Section-Definition)是程序编译期间会将不同的程序内容放到不同的程序段中,再通过链接器链接为固件。段定义同样也支持默认定义方式。 452 | 453 | ### GROUP命名和其他对应名称关系 454 | 455 | 按键依靠组名分类,同样的组必须在一块,所以,使用段定义时,必须使用宏定义的方式来定义按键。 456 | 首先需要给组起一个名字,例如:`test_btns`。 457 | 458 | 那么通过以下定义: 459 | 460 | ```c 461 | #define MFBD_GROUP_NAME(GROUP) mfbd_group_##GROUP 462 | #define MFBD_GROUP_EXTERN(GROUP) extern const mfbd_group_t MFBD_GROUP_NAME(GROUP) 463 | ``` 464 | 465 | 程序中真实的变量组名为`mfbd_group_test_btns` 466 | 467 | 使用`MFBD_GROUP_DEFINE`宏不需要考虑名称,宏定义里面会自动生成名字: 468 | 469 | ```c 470 | #define MFBD_GROUP_DEFINE(GROUP, IS_BTN_DOWN_FUNC, BTN_VALUE_REPORT_FUNC, ...) \ 471 | const mfbd_group_t MFBD_GROUP_NAME(GROUP) = { \ 472 | IS_BTN_DOWN_FUNC, \ 473 | BTN_VALUE_REPORT_FUNC, \ 474 | __VA_ARGS__ \ 475 | } 476 | ``` 477 | 478 | 同样的,通过以下宏定义,将给每组按键中不同的按键类型定义不同的段名(section name): 479 | 480 | ```c 481 | #define _MFBD_SECTION(X) __MFBD_SECTION(#X) 482 | #define MFBD_SECTION(GROUP, BTN_KIND) _MFBD_SECTION(GROUP##_##BTN_KIND) 483 | 484 | #define MFBD_SECTION_START(GROUP, BTN_KIND) _MFBD_SECTION_START(GROUP##_##BTN_KIND) 485 | #define MFBD_SECTION_END(GROUP, BTN_KIND) _MFBD_SECTION_END(GROUP##_##BTN_KIND) 486 | ``` 487 | 488 | 例如,按键组为`test_btns`,则默认: 489 | 490 | 组内的`tbtn`对应的段名为`test_btns_tbtn`。 491 | 492 | 组内的`nbtn`对应的段名为`test_btns_nbtn`。 493 | 494 | 组内的`mbtn`对应的段名为`test_btns_mbtn`。 495 | 496 | ### MDK和IAR编译器使用方法 497 | 498 | MDK和IAR中都在软件内部进行更改了代码编译后的链接操作,可以很方便的使用,无需修改工程文件,直接使用宏定义即可。 499 | 500 | ### GCC使用方法 501 | 502 | GUN gcc工程需要在工程的ld文件中找到`rodata`的初始化链接代码。并添加ld文件指定的函数。 503 | 504 | 例如,按键组为`test_btns`,则默认: 505 | 506 | 组内的`tbtn`对应的段名开始地址为`test_btns_tbtn_start`,结束地址为`test_btns_tbtn_end` 507 | 组内的`nbtn`对应的段名为`test_btns_nbtn_start`,结束地址为`test_btns_nbtn_end` 508 | 组内的`mbtn`对应的段名为`test_btns_mbtn_start`,结束地址为`test_btns_mbtn_end` 509 | 510 | ```ld 511 | .text : 512 | { 513 | . = ALIGN(4); 514 | KEEP(*(SORT_NONE(.handle_reset))) 515 | *(.text) 516 | *(.text.*) 517 | 518 | /* this is for tbtn in test_btns. */ 519 | . = ALIGN(4); 520 | PROVIDE(test_btns_tbtn_start = .); 521 | KEEP (*(SORT(test_btns_tbtn*))) 522 | PROVIDE(test_btns_tbtn_end = .); 523 | 524 | /* this is for nbtn in test_btns. */ 525 | . = ALIGN(4); 526 | PROVIDE(test_btns_nbtn_start = .); 527 | KEEP (*(SORT(test_btns_nbtn*))) 528 | PROVIDE(test_btns_nbtn_end = .); 529 | 530 | /* this is for mbtn in test_btns. */ 531 | . = ALIGN(4); 532 | PROVIDE(test_btns_mbtn_start = .); 533 | KEEP (*(SORT(test_btns_mbtn*))) 534 | PROVIDE(test_btns_mbtn_end = .); 535 | 536 | *(.rodata) 537 | *(.rodata*) 538 | *(.glue_7) 539 | *(.glue_7t) 540 | *(.gnu.linkonce.t.*) 541 | . = ALIGN(4); 542 | } >FLASH AT>FLASH 543 | ``` 544 | 545 | ### 段定义调用按键检测 546 | 547 | 由于使用了段定义,所以程序无法判断一个组是否有所有的使能的按键种类。所以可能会出错,此时需要通过自行调整检测的宏来进行按键检测。 548 | 549 | 默认的按键扫描宏如下: 550 | 551 | ```c 552 | #define MFBD_GROUP_SCAN(GROUP) \ 553 | do \ 554 | { \ 555 | MFBD_GROUP_SCAN_PREPARE(GROUP); \ 556 | MFBD_GROUP_SCAN_TBTN(GROUP); \ 557 | MFBD_GROUP_SCAN_NBTN(GROUP); \ 558 | MFBD_GROUP_SCAN_MBTN(GROUP); \ 559 | MFBD_GROUP_SCAN_AFTER(GROUP); \ 560 | } while (0) 561 | ``` 562 | 563 | 如果在`mfbd_cfg.h`中使能了`mbtn`,但是这个组又没有用到`mbtn`,那么就会出错,因为程序中没有`mbtn`对应的这个段。这时,自行将上述宏复制到程序中,删除没有用到的`MFBD_GROUP_SCAN_NBTN(GROUP);`即可: 564 | 565 | ```c 566 | do 567 | { 568 | MFBD_GROUP_SCAN_PREPARE(GROUP); 569 | MFBD_GROUP_SCAN_TBTN(GROUP); 570 | MFBD_GROUP_SCAN_NBTN(GROUP); 571 | MFBD_GROUP_SCAN_AFTER(GROUP); 572 | } while (0) 573 | ``` 574 | 575 | ### 段定义调用按键复位 576 | 577 | 和段定义调用按键检测一样,需要自行调整程序,删除组内没有用到的按键复位函数宏。 578 | 579 | 默认的按键复位宏如下: 580 | 581 | ```c 582 | #define MFBD_GROUP_RESET(GROUP) \ 583 | do \ 584 | { \ 585 | MFBD_GROUP_RESET_TBTN(GROUP); \ 586 | MFBD_GROUP_RESET_NBTN(GROUP); \ 587 | MFBD_GROUP_RESET_MBTN(GROUP); \ 588 | } while (0) 589 | ``` 590 | 591 | 如果在`mfbd_cfg.h`中使能了`mbtn`,但是这个组又没有用到`mbtn`,那么就会出错,因为程序中没有`mbtn`对应的这个段。这时,自行将上述宏复制到程序中,删除没有用到的`MFBD_GROUP_RESET_MBTN(GROUP);`即可: 592 | 593 | ```c 594 | do 595 | { 596 | MFBD_GROUP_RESET_TBTN(GROUP); 597 | MFBD_GROUP_RESET_NBTN(GROUP); 598 | } while (0) 599 | ``` 600 | 601 | ## 移植使用示例工程 602 | 603 | MFBD提供了下面的测试例程,如果你使用其他开发板和其他RTOS,可以参考例程移植即可。 604 | 605 | ### stm32f429-atk-apollo(rt-thread) 606 | 607 | [examples/mfbd_demo_rtt.c](https://github.com/smartmx/mfbd/tree/main/examples/mfbd_demo_rtt.c),该例程是基于rt-thread os,开发板为正点原子的[stm32f429-atk-apollo](https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32f429-atk-apollo)。 608 | 609 | ### [stm32f429-atk-apollo](https://github.com/smartmx/mfbd-examples/tree/main/STM32F429IGT6_MFBD) 610 | 611 | 该例程为**stm32f429-atk-apollo**的裸机移植使用例程。 612 | 613 | ### [CH573-EVT](https://github.com/smartmx/mfbd-examples/tree/main/CH573_MFBD) 614 | 615 | 该例程为基于沁恒微电子蓝牙芯片CH573的基于tmos的移植使用例程。 616 | 617 | ## 其他功能 618 | 619 | ### 矩阵键盘 620 | 621 | 矩阵键盘可以通过使能`MFBD_USE_BTN_SCAN_PRE_FUNC`,将矩阵键盘上的所有按键通过链表链接到同一个按键组。 622 | 即可在每次轮询检测时,通过准备函数将所有的按键值扫描出来存放到缓存中。然后在获取函数中根据缓存获取按键值即可。 623 | 624 | ### 组合按键 625 | 626 | 组合按键其实不应该由驱动层进行处理,应该由应用层处理。 627 | 不同的应用需求不一样,有的需要组合按键,有的不需要组合按键。 628 | 组合按键生效的应用中,普通按键按下是有应用处理延迟的。 629 | 可以在上报函数中,将时间参数和按键值一起上报至应用层,交由应用层判断。 630 | 应用层在接收到一个按键的键值后,在没有接收到该按键松开的按键值时,收到了组合按键的键值,则判定组合按键按下。 631 | 632 | ### 低功耗 633 | 634 | 低功耗可以通过使能`MFBD_USE_BTN_SCAN_AFTER_FUNC`和`MFBD_USE_BTN_SCAN_PRE_FUNC`,在每次检测完每一组的按键后,在结束函数中,将每组的外设关闭,在准备函数中,将每组的外设打开,以达到低功耗的目的。 635 | 需要根据不同的芯片的情况分好组,不然可能导致无法正常运行。 636 | 637 | ## [博客主页](https://blog.maxiang.vip/) 638 | 639 | QQ交流群:562090553 640 | -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | import rtconfig 3 | 4 | cwd = GetCurrentDir() 5 | 6 | # init src 7 | src = [] 8 | src += Glob('*.c') 9 | 10 | if GetDepend(['PKG_USING_MFBD_DEMO_RTT']): 11 | src += Glob("examples/mfbd_demo_rtt.c") 12 | 13 | CPPPATH = [cwd] 14 | 15 | group = DefineGroup('mfbd', src, depend = ['PKG_USING_MFBD'], CPPPATH = CPPPATH) 16 | 17 | Return('group') 18 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: MFBD 2 | description: Multi-Function Button Dectection. 3 | show_downloads: true 4 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /examples/mfbd_demo_rtt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, smartmx 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2022-02-22 smartmx the first version 9 | * 2022-03-15 smartmx each mbtn has it's own max multi-click times 10 | * 2022-04-16 smartmx drop list definitions, use arraylist, each group has all btn types. 11 | * 2022-08-05 smartmx add reset params function. 12 | * 2022-08-15 smartmx fix bugs. 13 | * 2023-07-03 smartmx add Section Definition option. 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | #include "mfbd.h" 20 | #include "mfbd_sd.h" 21 | 22 | #define MFBD_DEMO_USE_DEFAULT_DEFINE 1 /* set to 1, you can study how to use default define APIs. */ 23 | 24 | void bsp_btn_value_report(mfbd_btn_code_t btn_value); 25 | unsigned char bsp_btn_check(mfbd_btn_index_t btn_index); 26 | 27 | #ifndef BTN_KEY0 28 | #define BTN_KEY0 GET_PIN(H, 3) 29 | #endif 30 | 31 | #ifndef BTN_KEY1 32 | #define BTN_KEY1 GET_PIN(H, 2) 33 | #endif 34 | 35 | #ifndef BTN_KEY2 36 | #define BTN_KEY2 GET_PIN(C, 13) 37 | #endif 38 | 39 | #ifndef BTN_WK_UP 40 | #define BTN_WK_UP GET_PIN(A, 0) 41 | #endif 42 | 43 | /* default definition example */ 44 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 45 | 46 | enum 47 | { 48 | MFBD_DOWN_CODE_NAME(test_tbtn) = 0x1201, 49 | MFBD_UP_CODE_NAME(test_tbtn) = 0x1200, 50 | MFBD_LONG_CODE_NAME(test_tbtn) = 0x1202, 51 | 52 | MFBD_DOWN_CODE_NAME(test_nbtn) = 0x1301, 53 | MFBD_UP_CODE_NAME(test_nbtn) = 0x1300, 54 | MFBD_LONG_CODE_NAME(test_nbtn) = 0x1301, 55 | 56 | MFBD_DOWN_CODE_NAME(test_nbtn1) = 0x1401, 57 | MFBD_UP_CODE_NAME(test_nbtn1) = 0x1400, 58 | MFBD_LONG_CODE_NAME(test_nbtn1) = 0x1402, 59 | 60 | MFBD_UP_CODE_NAME(test_mbtn) = 0x1500, 61 | MFBD_LONG_CODE_NAME(test_mbtn) = 0x1502, 62 | }; 63 | 64 | mfbd_btn_code_t MFBD_DOWN_CODES_NAME(test_mbtn)[4] = {0x1501, 0x1511, 0x1521, 0x1531}; 65 | 66 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 67 | 68 | #if MFBD_USE_SECTION_DEFINITION 69 | /* use section definition. */ 70 | 71 | #if MFBD_PARAMS_SAME_IN_GROUP 72 | 73 | /* tbtn test */ 74 | #if MFBD_USE_TINY_BUTTON 75 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 76 | /* MFBD_TBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX) */ 77 | MFBD_TBTN_DEFAULT_DEFINE(test_btns, test_tbtn, 1); 78 | #else 79 | /* MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) */ 80 | MFBD_TBTN_DEFINE(test_btns, test_tbtn, 1, 0x1201, 0x1200); 81 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 82 | #endif /* MFBD_USE_TINY_BUTTON */ 83 | 84 | /* nbtn test */ 85 | #if MFBD_USE_NORMAL_BUTTON 86 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 87 | /* MFBD_NBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME) */ 88 | MFBD_NBTN_DEFAULT_DEFINE(test_btns, test_nbtn1, 3); 89 | MFBD_NBTN_DEFAULT_DEFINE(test_btns, test_nbtn, 2); 90 | #else 91 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 92 | MFBD_NBTN_DEFINE(test_btns, test_nbtn1, 3, 0x1401, 0x1400, 0x1402); 93 | MFBD_NBTN_DEFINE(test_btns, test_nbtn, 2, 0x1301, 0x1300, 0x1301); 94 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 95 | #endif /* MFBD_USE_NORMAL_BUTTON */ 96 | 97 | /* mbtn test */ 98 | #if MFBD_USE_MULTIFUCNTION_BUTTON 99 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 100 | /* MFBD_MBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, MAX_MULTICLICK_STATE) */ 101 | MFBD_MBTN_DEFAULT_DEFINE(test_btns, test_mbtn, 4, 3); 102 | #else 103 | /* MFBD_MBTN_DEFINE(NAME, BTN_INDEX, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) */ 104 | MFBD_MBTN_DEFINE(test_btns, test_mbtn, 4, 3, 0x1501, 0x1500, 0x1501, 0x1511, 0x1521, 0x1531); 105 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 106 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 107 | 108 | #else 109 | 110 | /* tbtn test */ 111 | #if MFBD_USE_TINY_BUTTON 112 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 113 | /* MFBD_TBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME) */ 114 | MFBD_TBTN_DEFAULT_DEFINE(test_btns, test_tbtn, 1, 3); 115 | #else 116 | /* MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) */ 117 | MFBD_TBTN_DEFINE(test_btns, test_tbtn, 1, 3, 0x1201, 0x1200); 118 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 119 | #endif /* MFBD_USE_TINY_BUTTON */ 120 | 121 | /* nbtn test */ 122 | #if MFBD_USE_NORMAL_BUTTON 123 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 124 | /* MFBD_NBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME) */ 125 | MFBD_NBTN_DEFAULT_DEFINE(test_btns, test_nbtn1, 3, 3, 0, 150); 126 | MFBD_NBTN_DEFAULT_DEFINE(test_btns, test_nbtn, 2, 3, 30, 150); 127 | #else 128 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 129 | MFBD_NBTN_DEFINE(test_btns, test_nbtn1, 3, 3, 0, 150, 0x1401, 0x1400, 0x1402); 130 | MFBD_NBTN_DEFINE(test_btns, test_nbtn, 2, 3, 30, 150, 0x1301, 0x1300, 0x1301); 131 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 132 | #endif /* MFBD_USE_NORMAL_BUTTON */ 133 | 134 | /* mbtn test */ 135 | #if MFBD_USE_MULTIFUCNTION_BUTTON 136 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 137 | /* MFBD_MBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE) */ 138 | MFBD_MBTN_DEFAULT_DEFINE(test_btns, test_mbtn, 4, 3, 30, 150, 75, 3); 139 | #else 140 | /* MFBD_MBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) */ 141 | MFBD_MBTN_DEFINE(test_btns, test_mbtn, 4, 3, 30, 150, 75, 3, 0x1501, 0x1500, 0x1501, 0x1511, 0x1521, 0x1531); 142 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 143 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 144 | 145 | #endif /*MFBD_PARAMS_SAME_IN_GROUP*/ 146 | 147 | //MFBD_GROUP_DEFINE(test_btns, bsp_btn_check, bsp_btn_value_report, 3, 30, 150, 75); 148 | //MFBD_GROUP_DEFINE(test_btns, bsp_btn_check, bsp_btn_value_report); 149 | 150 | const mfbd_group_t MFBD_GROUP_NAME(test_btns) = { 151 | bsp_btn_check, 152 | bsp_btn_value_report, 153 | #if MFBD_PARAMS_SAME_IN_GROUP 154 | 155 | #if MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 156 | 3, 157 | #endif /* MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 158 | 159 | #if MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 160 | 30, 161 | 150, 162 | #endif /* MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 163 | 164 | #if MFBD_USE_MULTIFUCNTION_BUTTON 165 | 75, 166 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 167 | 168 | #endif /*MFBD_PARAMS_SAME_IN_GROUP*/ 169 | }; 170 | 171 | #else 172 | 173 | #if MFBD_PARAMS_SAME_IN_GROUP 174 | 175 | /* tbtn test */ 176 | #if MFBD_USE_TINY_BUTTON 177 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 178 | /* MFBD_TBTN_DEFAULT_DEFINE(NAME, BTN_INDEX) */ 179 | MFBD_TBTN_DEFAULT_DEFINE(test_tbtn, 1); 180 | #else 181 | /* MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) */ 182 | MFBD_TBTN_DEFINE(test_tbtn, 1, 0x1201, 0x1200); 183 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 184 | #endif /* MFBD_USE_TINY_BUTTON */ 185 | 186 | /* nbtn test */ 187 | #if MFBD_USE_NORMAL_BUTTON 188 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 189 | /* MFBD_NBTN_DEFAULT_DEFINE(NAME, BTN_INDEX) */ 190 | MFBD_NBTN_DEFAULT_DEFINE(test_nbtn1, 3); 191 | MFBD_NBTN_DEFAULT_DEFINE(test_nbtn, 2); 192 | #else 193 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 194 | MFBD_NBTN_DEFINE(test_nbtn1, 3, 0x1401, 0x1400, 0x1402); 195 | MFBD_NBTN_DEFINE(test_nbtn, 2, 0x1301, 0x1300, 0x1301); 196 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 197 | #endif /* MFBD_USE_NORMAL_BUTTON */ 198 | 199 | /* mbtn test */ 200 | #if MFBD_USE_MULTIFUCNTION_BUTTON 201 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 202 | /* MFBD_MBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, MAX_MULTICLICK_STATE) */ 203 | MFBD_MBTN_DEFAULT_DEFINE(test_mbtn, 4, 3); 204 | #else 205 | /* FBD_MBTN_DEFINE(NAME, BTN_INDEX, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) */ 206 | MFBD_MBTN_DEFINE(test_mbtn, 4, 3, 0x1501, 0x1500, 0x1501, 0x1511, 0x1521, 0x1531); 207 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 208 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 209 | 210 | #else 211 | 212 | /* tbtn test */ 213 | #if MFBD_USE_TINY_BUTTON 214 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 215 | /* MFBD_TBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, FILTER_TIME) */ 216 | MFBD_TBTN_DEFAULT_DEFINE(test_tbtn, 1, 3); 217 | #else 218 | /* MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) */ 219 | MFBD_TBTN_DEFINE(test_tbtn, 1, 3, 0x1201, 0x1200); 220 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 221 | #endif /* MFBD_USE_TINY_BUTTON */ 222 | 223 | /* nbtn test */ 224 | #if MFBD_USE_NORMAL_BUTTON 225 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 226 | /* MFBD_NBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME) */ 227 | MFBD_NBTN_DEFAULT_DEFINE(test_nbtn1, 3, 3, 0, 150); 228 | MFBD_NBTN_DEFAULT_DEFINE(test_nbtn, 2, 3, 30, 150); 229 | #else 230 | /* MFBD_NBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) */ 231 | MFBD_NBTN_DEFINE(test_nbtn1, 3, 3, 0, 150, 0x1401, 0x1400, 0x1402); 232 | MFBD_NBTN_DEFINE(test_nbtn, 2, 3, 30, 150, 0x1301, 0x1300, 0x1301); 233 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 234 | #endif /* MFBD_USE_NORMAL_BUTTON */ 235 | 236 | /* mbtn test */ 237 | #if MFBD_USE_MULTIFUCNTION_BUTTON 238 | #if MFBD_DEMO_USE_DEFAULT_DEFINE 239 | /* MFBD_MBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE) */ 240 | MFBD_MBTN_DEFAULT_DEFINE(test_mbtn, 4, 3, 30, 150, 75, 3); 241 | #else 242 | /* MFBD_MBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) */ 243 | MFBD_MBTN_DEFINE(test_mbtn, 4, 3, 30, 150, 75, 3, 0x1501, 0x1500, 0x1501, 0x1511, 0x1521, 0x1531); 244 | #endif /* MFBD_DEMO_USE_DEFAULT_DEFINE */ 245 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 246 | 247 | #endif /*MFBD_PARAMS_SAME_IN_GROUP*/ 248 | 249 | #if MFBD_USE_TINY_BUTTON 250 | MFBD_TBTN_ARRAYLIST(test_tbtn_list, &test_tbtn); 251 | #endif /* MFBD_USE_TINY_BUTTON */ 252 | 253 | #if MFBD_USE_NORMAL_BUTTON 254 | MFBD_NBTN_ARRAYLIST(test_nbtn_list, &test_nbtn1, &test_nbtn); 255 | #endif /* MFBD_USE_NORMAL_BUTTON */ 256 | 257 | #if MFBD_USE_MULTIFUCNTION_BUTTON 258 | MFBD_MBTN_ARRAYLIST(test_mbtn_list, &test_mbtn); 259 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 260 | 261 | const mfbd_group_t test_btn_group = 262 | { 263 | bsp_btn_check, 264 | bsp_btn_value_report, 265 | 266 | #if MFBD_USE_TINY_BUTTON 267 | test_tbtn_list, 268 | #endif /* MFBD_USE_TINY_BUTTON */ 269 | 270 | #if MFBD_USE_NORMAL_BUTTON 271 | test_nbtn_list, 272 | #endif /* MFBD_USE_NORMAL_BUTTON */ 273 | 274 | #if MFBD_USE_MULTIFUCNTION_BUTTON 275 | test_mbtn_list, 276 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 277 | 278 | #if MFBD_PARAMS_SAME_IN_GROUP 279 | 280 | #if MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 281 | 3, 282 | #endif /* MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 283 | 284 | #if MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 285 | 30, 286 | 150, 287 | #endif /* MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 288 | 289 | #if MFBD_USE_MULTIFUCNTION_BUTTON 290 | 75, 291 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 292 | 293 | #endif /*MFBD_PARAMS_SAME_IN_GROUP*/ 294 | 295 | }; 296 | 297 | #endif /*MFBD_USE_SECTION_DEFINITION*/ 298 | 299 | unsigned char bsp_btn_check(mfbd_btn_index_t btn_index) 300 | { 301 | switch (btn_index) 302 | { 303 | case 1: 304 | if (rt_pin_read(BTN_KEY0) == 0) 305 | { 306 | return MFBD_BTN_STATE_DOWN; 307 | } 308 | break; 309 | case 2: 310 | if (rt_pin_read(BTN_KEY1) == 0) 311 | { 312 | return MFBD_BTN_STATE_DOWN; 313 | } 314 | break; 315 | case 3: 316 | if (rt_pin_read(BTN_KEY2) == 0) 317 | { 318 | return MFBD_BTN_STATE_DOWN; 319 | } 320 | break; 321 | case 4: 322 | if (rt_pin_read(BTN_WK_UP) == 1) 323 | { 324 | return MFBD_BTN_STATE_DOWN; 325 | } 326 | break; 327 | default: 328 | break; 329 | } 330 | return MFBD_BTN_STATE_UP; 331 | } 332 | 333 | void bsp_btn_value_report(mfbd_btn_code_t btn_value) 334 | { 335 | rt_kprintf("%04x\n", btn_value); 336 | } 337 | 338 | static void mfbd_scan(void *arg) 339 | { 340 | while (1) 341 | { 342 | #if MFBD_USE_SECTION_DEFINITION 343 | /* use section definition. */ 344 | 345 | MFBD_GROUP_SCAN(test_btns); 346 | 347 | #else 348 | 349 | mfbd_group_scan(&test_btn_group); /* scan button group */ 350 | 351 | #endif /*MFBD_USE_SECTION_DEFINITION*/ 352 | 353 | rt_thread_mdelay(10); /* scan period: 10ms */ 354 | } 355 | } 356 | 357 | static void user_button_init(void) 358 | { 359 | 360 | rt_pin_mode(BTN_KEY0, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */ 361 | rt_pin_mode(BTN_KEY1, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */ 362 | rt_pin_mode(BTN_KEY2, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */ 363 | rt_pin_mode(BTN_WK_UP, PIN_MODE_INPUT_PULLDOWN); /* set KEY pin mode to input */ 364 | 365 | } 366 | 367 | int mfbd_main(void) 368 | { 369 | rt_thread_t tid = RT_NULL; 370 | 371 | user_button_init(); 372 | 373 | /* Create background ticks thread */ 374 | tid = rt_thread_create("mfbd", mfbd_scan, RT_NULL, 1024, 10, 10); 375 | if (tid != RT_NULL) 376 | { 377 | rt_thread_startup(tid); 378 | } 379 | 380 | return 0; 381 | } 382 | 383 | INIT_APP_EXPORT(mfbd_main); 384 | 385 | -------------------------------------------------------------------------------- /mfbd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, smartmx 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2022-02-22 smartmx the first version. 9 | * 2022-03-15 smartmx each mbtn has it's own max multi-click times. 10 | * 2022-04-16 smartmx drop list definitions, use arraylist, each group has all btn types. 11 | * 2022-08-05 smartmx add reset params function. 12 | * 2023-03-15 smartmx add state declaration. 13 | * 2023-07-03 smartmx add Section Definition option. 14 | * 2023-07-15 smartmx add skip function, to reduce calling of scan functions. 15 | * 2023-07-22 smartmx add MFBD_MBTN_MULTICLICK_LONG_EVT and MFBD_MBTN_CONTINUE_LONG_COUNT option. 16 | * 2023-09-19 smartmx improve performance, add MFBD_BTN_STATE_SKIP. 17 | * 18 | */ 19 | 20 | #include "mfbd.h" 21 | 22 | #if (MFBD_USE_SECTION_DEFINITION == 0) 23 | 24 | #define MFBD_BTN_IN_FUC (_pbtn) 25 | #define MFBD_BTN_INFO_IN_FUC (_pbtn->btn_info) 26 | 27 | #if MFBD_PARAMS_SAME_IN_GROUP 28 | 29 | /* filter_time */ 30 | #define MFBD_FILTER_TIME_IN_FUC (_pbtn_group->filter_time) 31 | /* long_time */ 32 | #define MFBD_LONG_TIME_IN_FUC (_pbtn_group->long_time) 33 | /* repeat_time */ 34 | #define MFBD_REPEAT_TIME_IN_FUC (_pbtn_group->repeat_time) 35 | /* multiclick_time */ 36 | #define MFBD_MULTICLICK_TIME_IN_FUC (_pbtn_group->multiclick_time) 37 | 38 | #else 39 | 40 | /* filter_time */ 41 | #define MFBD_FILTER_TIME_IN_FUC (MFBD_BTN_INFO_IN_FUC->filter_time) 42 | /* long_time */ 43 | #define MFBD_LONG_TIME_IN_FUC (MFBD_BTN_INFO_IN_FUC->long_time) 44 | /* repeat_time */ 45 | #define MFBD_REPEAT_TIME_IN_FUC (MFBD_BTN_INFO_IN_FUC->repeat_time) 46 | /* multiclick_time */ 47 | #define MFBD_MULTICLICK_TIME_IN_FUC (MFBD_BTN_INFO_IN_FUC->multiclick_time) 48 | 49 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 50 | 51 | 52 | #if MFBD_USE_TINY_BUTTON 53 | /** 54 | * @brief scan all tiny buttons, and report button event value if event happened. 55 | * 56 | * @param _pbtn_group is a pointer of mfbd_group_t. 57 | * 58 | * @return None. 59 | */ 60 | void mfbd_tbtn_scan(const mfbd_group_t *_pbtn_group) 61 | { 62 | mfbd_tbtn_t **_ppbtn = _pbtn_group->tbtns; 63 | mfbd_tbtn_t *_pbtn = *_ppbtn; 64 | MFBD_BTN_STATE_t btn_state; 65 | 66 | while (MFBD_BTN_IN_FUC != NULL) 67 | { 68 | btn_state = _pbtn_group->is_btn_down_func(MFBD_BTN_INFO_IN_FUC->btn_index); 69 | if (btn_state == MFBD_BTN_STATE_DOWN) 70 | { 71 | if(MFBD_BTN_IN_FUC->filter_count >= ((MFBD_FILTER_TIME_IN_FUC) * 2)) 72 | { 73 | /* it means the button is down for over filter_time. */ 74 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_UP) 75 | { 76 | if (MFBD_BTN_INFO_IN_FUC->btn_down_code > 0) 77 | { 78 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code); 79 | } 80 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_DOWN; 81 | } 82 | } 83 | else if(MFBD_BTN_IN_FUC->filter_count >= (MFBD_FILTER_TIME_IN_FUC)) 84 | { 85 | MFBD_BTN_IN_FUC->filter_count++; 86 | } 87 | else 88 | { 89 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 90 | } 91 | } 92 | else if (btn_state == MFBD_BTN_STATE_UP) 93 | { 94 | if (MFBD_BTN_IN_FUC->filter_count == 0) 95 | { 96 | if (MFBD_BTN_IN_FUC->state != MFBD_BTN_STATE_UP) 97 | { 98 | if (MFBD_BTN_INFO_IN_FUC->btn_up_code > 0) 99 | { 100 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_up_code); 101 | } 102 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 103 | } 104 | } 105 | else 106 | { 107 | if (MFBD_BTN_IN_FUC->filter_count > (MFBD_FILTER_TIME_IN_FUC)) 108 | { 109 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 110 | } 111 | else if (MFBD_BTN_IN_FUC->filter_count != 0) 112 | { 113 | MFBD_BTN_IN_FUC->filter_count--; 114 | } 115 | } 116 | } 117 | _ppbtn++; 118 | _pbtn = *_ppbtn; 119 | } 120 | } 121 | 122 | /** 123 | * @brief reset all tiny buttons' params. 124 | * 125 | * @param _pbtn_group is a pointer of mfbd_group_t. 126 | * 127 | * @return None. 128 | */ 129 | void mfbd_tbtn_reset(const mfbd_group_t *_pbtn_group) 130 | { 131 | mfbd_tbtn_t **_ppbtn = _pbtn_group->tbtns; 132 | mfbd_tbtn_t *_pbtn = *_ppbtn; 133 | while (MFBD_BTN_IN_FUC != NULL) 134 | { 135 | MFBD_BTN_IN_FUC->filter_count = 0; 136 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 137 | _ppbtn++; 138 | _pbtn = *_ppbtn; 139 | } 140 | } 141 | 142 | #endif /* MFBD_USE_TINY_BUTTON */ 143 | 144 | 145 | #if MFBD_USE_NORMAL_BUTTON 146 | 147 | /** 148 | * @brief scan all normal buttons, and report button event value if event happened. 149 | * 150 | * @param _pbtn_group is a pointer of mfbd_group_t. 151 | * 152 | * @return None 153 | */ 154 | void mfbd_nbtn_scan(const mfbd_group_t *_pbtn_group) 155 | { 156 | mfbd_nbtn_t **_ppbtn = _pbtn_group->nbtns; 157 | mfbd_nbtn_t *_pbtn = *_ppbtn; 158 | MFBD_BTN_STATE_t btn_state; 159 | 160 | while (MFBD_BTN_IN_FUC != NULL) 161 | { 162 | btn_state = _pbtn_group->is_btn_down_func(MFBD_BTN_INFO_IN_FUC->btn_index); 163 | if (btn_state == MFBD_BTN_STATE_DOWN) 164 | { 165 | if(MFBD_BTN_IN_FUC->filter_count >= ((MFBD_FILTER_TIME_IN_FUC) * 2)) 166 | { 167 | /* it means the button is down for over filter_time. */ 168 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 169 | { 170 | /* MFBD_BTN_STATE_LONG */ 171 | if (MFBD_BTN_IN_FUC->repeat_count > 0) 172 | { 173 | MFBD_BTN_IN_FUC->repeat_count++; 174 | if (MFBD_BTN_IN_FUC->repeat_count > (MFBD_REPEAT_TIME_IN_FUC)) 175 | { 176 | /* repeat event has happened, reset repeat_count to 1. */ 177 | MFBD_BTN_IN_FUC->repeat_count = 1; 178 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code); 179 | } 180 | } 181 | } 182 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 183 | { 184 | if (MFBD_BTN_IN_FUC->long_count > 0) 185 | { 186 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 187 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 188 | { 189 | MFBD_BTN_IN_FUC->long_count++; 190 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 191 | { 192 | /* it means the button is down for over long_time. */ 193 | if (((MFBD_REPEAT_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_down_code != 0)) 194 | { 195 | /* repeat event is enabled in this btn. */ 196 | MFBD_BTN_IN_FUC->repeat_count = 1; 197 | } 198 | else 199 | { 200 | /* repeat event is disabled in this btn. */ 201 | MFBD_BTN_IN_FUC->repeat_count = 0; 202 | } 203 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 204 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 205 | } 206 | } 207 | } 208 | } 209 | else 210 | { 211 | /* MFBD_BTN_STATE_UP */ 212 | /* clear long_count. */ 213 | if (((MFBD_LONG_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_long_code != 0)) 214 | { 215 | /* long event is enabled in this btn. */ 216 | MFBD_BTN_IN_FUC->long_count = 1; 217 | } 218 | else 219 | { 220 | /* long event is disabled in this btn. */ 221 | MFBD_BTN_IN_FUC->long_count = 0; 222 | } 223 | if (MFBD_BTN_INFO_IN_FUC->btn_down_code > 0) 224 | { 225 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code); 226 | } 227 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_DOWN; 228 | } 229 | } 230 | else if(MFBD_BTN_IN_FUC->filter_count >= (MFBD_FILTER_TIME_IN_FUC)) 231 | { 232 | MFBD_BTN_IN_FUC->filter_count++; 233 | } 234 | else 235 | { 236 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 237 | } 238 | } 239 | else if (btn_state == MFBD_BTN_STATE_UP) 240 | { 241 | if (MFBD_BTN_IN_FUC->filter_count == 0) 242 | { 243 | if (MFBD_BTN_IN_FUC->state != MFBD_BTN_STATE_UP) 244 | { 245 | if (MFBD_BTN_INFO_IN_FUC->btn_up_code > 0) 246 | { 247 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_up_code); 248 | } 249 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 250 | } 251 | } 252 | else 253 | { 254 | if (MFBD_BTN_IN_FUC->filter_count > (MFBD_FILTER_TIME_IN_FUC)) 255 | { 256 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 257 | } 258 | else if (MFBD_BTN_IN_FUC->filter_count != 0) 259 | { 260 | MFBD_BTN_IN_FUC->filter_count--; 261 | } 262 | } 263 | } 264 | _ppbtn++; 265 | _pbtn = *_ppbtn; 266 | } 267 | } 268 | 269 | /** 270 | * @brief skip some times of mfbd_btn_count_t with last state. 271 | * 272 | * @param _pbtn_group is a pointer of mfbd_group_t. 273 | * @param times is times need to skip. 274 | * 275 | * @return None. 276 | */ 277 | void mfbd_nbtn_skip(const mfbd_group_t *_pbtn_group, mfbd_btn_count_t times) 278 | { 279 | mfbd_nbtn_t **_ppbtn = _pbtn_group->nbtns; 280 | mfbd_nbtn_t *_pbtn = *_ppbtn; 281 | 282 | while (MFBD_BTN_IN_FUC != NULL) 283 | { 284 | if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 285 | { 286 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 287 | { 288 | if(((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 289 | { 290 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 291 | } 292 | else 293 | { 294 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 295 | } 296 | } 297 | } 298 | else if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 299 | { 300 | if ((MFBD_BTN_IN_FUC->repeat_count > 0) && (MFBD_BTN_IN_FUC->repeat_count < (MFBD_REPEAT_TIME_IN_FUC))) 301 | { 302 | if(((MFBD_REPEAT_TIME_IN_FUC) - MFBD_BTN_IN_FUC->repeat_count) > times) 303 | { 304 | MFBD_BTN_IN_FUC->repeat_count = MFBD_BTN_IN_FUC->repeat_count + times; 305 | } 306 | else 307 | { 308 | MFBD_BTN_IN_FUC->repeat_count = MFBD_REPEAT_TIME_IN_FUC; 309 | } 310 | } 311 | } 312 | 313 | _ppbtn++; 314 | _pbtn = *_ppbtn; 315 | } 316 | } 317 | 318 | /** 319 | * @brief reset all normal buttons' params. 320 | * 321 | * @param _pbtn_group is a pointer of mfbd_group_t. 322 | * 323 | * @return None. 324 | */ 325 | void mfbd_nbtn_reset(const mfbd_group_t *_pbtn_group) 326 | { 327 | mfbd_nbtn_t **_ppbtn = _pbtn_group->nbtns; 328 | mfbd_nbtn_t *_pbtn = *_ppbtn; 329 | while (MFBD_BTN_IN_FUC != NULL) 330 | { 331 | MFBD_BTN_IN_FUC->filter_count = 0; 332 | MFBD_BTN_IN_FUC->long_count = 0; 333 | MFBD_BTN_IN_FUC->repeat_count = 0; 334 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 335 | _ppbtn++; 336 | _pbtn = *_ppbtn; 337 | } 338 | } 339 | 340 | #endif /* MFBD_USE_NORMAL_BUTTON */ 341 | 342 | 343 | #if MFBD_USE_MULTIFUCNTION_BUTTON 344 | 345 | /** 346 | * @brief scan all multi-function buttons, and report button event value if event happened. 347 | * 348 | * @param _pbtn_group is a pointer of mfbd_group_t. 349 | * 350 | * @return None. 351 | */ 352 | void mfbd_mbtn_scan(const mfbd_group_t *_pbtn_group) 353 | { 354 | mfbd_mbtn_t **_ppbtn = _pbtn_group->mbtns; 355 | mfbd_mbtn_t *_pbtn = *_ppbtn; 356 | MFBD_BTN_STATE_t btn_state; 357 | 358 | while (MFBD_BTN_IN_FUC != NULL) 359 | { 360 | btn_state = _pbtn_group->is_btn_down_func(MFBD_BTN_INFO_IN_FUC->btn_index); 361 | if (btn_state == MFBD_BTN_STATE_DOWN) 362 | { 363 | if(MFBD_BTN_IN_FUC->filter_count >= ((MFBD_FILTER_TIME_IN_FUC) * 2)) 364 | { 365 | /* it means the button is down for over filter_time. */ 366 | #if MFBD_MBTN_CONTINUE_LONG_COUNT 367 | #if MFBD_MBTN_MULTICLICK_LONG_EVT 368 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 369 | { 370 | /* MFBD_BTN_STATE_LONG */ 371 | if (MFBD_BTN_IN_FUC->repeat_count > 0) 372 | { 373 | MFBD_BTN_IN_FUC->repeat_count++; 374 | if (MFBD_BTN_IN_FUC->repeat_count > (MFBD_REPEAT_TIME_IN_FUC)) 375 | { 376 | /* repeat event has happened, clear repeat_count. */ 377 | MFBD_BTN_IN_FUC->repeat_count = 1; 378 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state]); 379 | } 380 | } 381 | } 382 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 383 | { 384 | if (MFBD_BTN_IN_FUC->long_count > 0) 385 | { 386 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 387 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 388 | { 389 | MFBD_BTN_IN_FUC->long_count++; 390 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 391 | { 392 | /* it means the button is down for over long_time. */ 393 | if (((MFBD_REPEAT_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state] != 0)) 394 | { 395 | /* repeat event is enabled in this btn. */ 396 | MFBD_BTN_IN_FUC->repeat_count = 1; 397 | } 398 | else 399 | { 400 | /* repeat event is disabled in this btn. */ 401 | MFBD_BTN_IN_FUC->repeat_count = 0; 402 | } 403 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 404 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 405 | } 406 | } 407 | } 408 | } 409 | #else 410 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 411 | { 412 | /* we don't support repeat event here.*/ 413 | } 414 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 415 | { 416 | if (MFBD_BTN_IN_FUC->long_count > 0) 417 | { 418 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 419 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 420 | { 421 | MFBD_BTN_IN_FUC->long_count++; 422 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 423 | { 424 | /* it means the button is down for over long_time. */ 425 | if (MFBD_BTN_IN_FUC->multiclick_state == 0) 426 | { 427 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 428 | } 429 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 430 | } 431 | } 432 | } 433 | } 434 | #endif /* MFBD_MBTN_MULTICLICK_LONG_EVT */ 435 | #else 436 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 437 | { 438 | /* MFBD_BTN_STATE_LONG */ 439 | if (MFBD_BTN_IN_FUC->repeat_count > 0) 440 | { 441 | MFBD_BTN_IN_FUC->repeat_count++; 442 | if (MFBD_BTN_IN_FUC->repeat_count > (MFBD_REPEAT_TIME_IN_FUC)) 443 | { 444 | /* repeat event has happened, clear repeat_count. */ 445 | MFBD_BTN_IN_FUC->repeat_count = 1; 446 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code[0]); 447 | } 448 | } 449 | } 450 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 451 | { 452 | if (MFBD_BTN_IN_FUC->multiclick_state == 0) 453 | { 454 | if (MFBD_BTN_IN_FUC->long_count > 0) 455 | { 456 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 457 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 458 | { 459 | MFBD_BTN_IN_FUC->long_count++; 460 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 461 | { 462 | /* it means the button is down for over long_time. */ 463 | if (((MFBD_REPEAT_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_down_code[0] != 0)) 464 | { 465 | /* repeat event is enabled in this btn. */ 466 | MFBD_BTN_IN_FUC->repeat_count = 1; 467 | } 468 | else 469 | { 470 | /* repeat event is disabled in this btn. */ 471 | MFBD_BTN_IN_FUC->repeat_count = 0; 472 | } 473 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 474 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 475 | } 476 | } 477 | } 478 | } 479 | } 480 | #endif /* MFBD_MBTN_CONTINUE_LONG_COUNT */ 481 | else 482 | { 483 | /* MFBD_BTN_STATE_UP */ 484 | /* clear long_count. */ 485 | if (((MFBD_LONG_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_long_code != 0)) 486 | { 487 | /* long event is enabled in this btn. */ 488 | MFBD_BTN_IN_FUC->long_count = 1; 489 | } 490 | else 491 | { 492 | /* long event is disabled in this btn. */ 493 | MFBD_BTN_IN_FUC->long_count = 0; 494 | } 495 | if (MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state] > 0) 496 | { 497 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state]); 498 | } 499 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_DOWN; 500 | } 501 | } 502 | else if(MFBD_BTN_IN_FUC->filter_count >= (MFBD_FILTER_TIME_IN_FUC)) 503 | { 504 | MFBD_BTN_IN_FUC->filter_count++; 505 | } 506 | else 507 | { 508 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 509 | } 510 | } 511 | else if (btn_state == MFBD_BTN_STATE_UP) 512 | { 513 | if (MFBD_BTN_IN_FUC->filter_count == 0) 514 | { 515 | if (MFBD_BTN_IN_FUC->state != MFBD_BTN_STATE_UP) 516 | { 517 | #if MFBD_MULTICLICK_STATE_AUTO_RESET 518 | /* if multiclick_state is not 0 and less than max_multiclick_state, inc multiclick_state */ 519 | if (((MFBD_MULTICLICK_TIME_IN_FUC) != 0) 520 | && (MFBD_BTN_IN_FUC->multiclick_state < MFBD_BTN_INFO_IN_FUC->max_multiclick_state) 521 | #if (MFBD_MBTN_CONTINUE_LONG_COUNT==0) 522 | && (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 523 | #endif /* (MFBD_MBTN_CONTINUE_LONG_COUNT==0) */ 524 | ) 525 | { 526 | MFBD_BTN_IN_FUC->multiclick_state++; 527 | MFBD_BTN_IN_FUC->multiclick_count = 0; 528 | } 529 | #else 530 | /* if multiclick_state is not 0 and less than max_multiclick_state, inc multiclick_state */ 531 | if (((MFBD_MULTICLICK_TIME_IN_FUC) != 0) 532 | #if (MFBD_MBTN_CONTINUE_LONG_COUNT==0) 533 | && (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 534 | #endif /* (MFBD_MBTN_CONTINUE_LONG_COUNT==0) */ 535 | ) 536 | { 537 | if(MFBD_BTN_IN_FUC->multiclick_state < MFBD_BTN_INFO_IN_FUC->max_multiclick_state) 538 | { 539 | MFBD_BTN_IN_FUC->multiclick_state++; 540 | } 541 | MFBD_BTN_IN_FUC->multiclick_count = 0; 542 | } 543 | #endif /* MFBD_MULTICLICK_STATE_AUTO_RESET */ 544 | else 545 | { 546 | /* over max multi-click times or (long event and repeat event) happened, reset to 0. */ 547 | MFBD_BTN_IN_FUC->multiclick_state = 0; 548 | } 549 | if (MFBD_BTN_INFO_IN_FUC->btn_up_code > 0) 550 | { 551 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_up_code); 552 | } 553 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 554 | } 555 | else 556 | { 557 | if (MFBD_BTN_IN_FUC->multiclick_state != 0) 558 | { 559 | MFBD_BTN_IN_FUC->multiclick_count++; 560 | if (MFBD_BTN_IN_FUC->multiclick_count >= (MFBD_MULTICLICK_TIME_IN_FUC)) 561 | { 562 | MFBD_BTN_IN_FUC->multiclick_state = 0; 563 | } 564 | } 565 | } 566 | } 567 | else 568 | { 569 | if (MFBD_BTN_IN_FUC->filter_count > (MFBD_FILTER_TIME_IN_FUC)) 570 | { 571 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 572 | } 573 | else if (MFBD_BTN_IN_FUC->filter_count != 0) 574 | { 575 | MFBD_BTN_IN_FUC->filter_count--; 576 | } 577 | } 578 | } 579 | _ppbtn++; 580 | _pbtn = *_ppbtn; 581 | } 582 | } 583 | 584 | /** 585 | * @brief skip some times of mfbd_btn_count_t with last state. 586 | * 587 | * @param _pbtn_group is a pointer of mfbd_group_t. 588 | * @param times is times need to skip. 589 | * 590 | * @return None. 591 | */ 592 | void mfbd_mbtn_skip(const mfbd_group_t *_pbtn_group, mfbd_btn_count_t times) 593 | { 594 | mfbd_mbtn_t **_ppbtn = _pbtn_group->mbtns; 595 | mfbd_mbtn_t *_pbtn = *_ppbtn; 596 | 597 | while (MFBD_BTN_IN_FUC != NULL) 598 | { 599 | if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_UP) 600 | { 601 | if (MFBD_BTN_IN_FUC->multiclick_state != 0) 602 | { 603 | if (MFBD_BTN_IN_FUC->multiclick_count < (MFBD_MULTICLICK_TIME_IN_FUC)) 604 | { 605 | if(((MFBD_MULTICLICK_TIME_IN_FUC) - MFBD_BTN_IN_FUC->multiclick_count) > times) 606 | { 607 | MFBD_BTN_IN_FUC->multiclick_count = MFBD_BTN_IN_FUC->multiclick_count + times; 608 | } 609 | else 610 | { 611 | MFBD_BTN_IN_FUC->multiclick_state = 0; 612 | } 613 | } 614 | } 615 | } 616 | #if MFBD_MBTN_CONTINUE_LONG_COUNT 617 | #if MFBD_MBTN_MULTICLICK_LONG_EVT 618 | else if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 619 | { 620 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 621 | { 622 | if(((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 623 | { 624 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 625 | } 626 | else 627 | { 628 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 629 | } 630 | } 631 | } 632 | else 633 | { 634 | /* MFBD_BTN_STATE_LONG, if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) */ 635 | if ((MFBD_BTN_IN_FUC->repeat_count > 0) && (MFBD_BTN_IN_FUC->repeat_count < (MFBD_REPEAT_TIME_IN_FUC))) 636 | { 637 | if(((MFBD_REPEAT_TIME_IN_FUC) - MFBD_BTN_IN_FUC->repeat_count) > times) 638 | { 639 | MFBD_BTN_IN_FUC->repeat_count = MFBD_BTN_IN_FUC->repeat_count + times; 640 | } 641 | else 642 | { 643 | MFBD_BTN_IN_FUC->repeat_count = MFBD_REPEAT_TIME_IN_FUC; 644 | } 645 | } 646 | } 647 | #else 648 | else if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 649 | { 650 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 651 | { 652 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 653 | if(((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 654 | { 655 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 656 | } 657 | else 658 | { 659 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 660 | } 661 | } 662 | } 663 | else 664 | { 665 | /* MFBD_BTN_STATE_LONG, if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) */ 666 | /* we don't support repeat event here.*/ 667 | } 668 | #endif /* MFBD_MBTN_MULTICLICK_LONG_EVT */ 669 | #else 670 | else if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 671 | { 672 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 673 | { 674 | if(((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 675 | { 676 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 677 | } 678 | else 679 | { 680 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 681 | } 682 | } 683 | } 684 | else 685 | { 686 | /* MFBD_BTN_STATE_LONG, if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) */ 687 | if ((MFBD_BTN_IN_FUC->repeat_count > 0) && (MFBD_BTN_IN_FUC->repeat_count < (MFBD_REPEAT_TIME_IN_FUC))) 688 | { 689 | if(((MFBD_REPEAT_TIME_IN_FUC) - MFBD_BTN_IN_FUC->repeat_count) > times) 690 | { 691 | MFBD_BTN_IN_FUC->repeat_count = MFBD_BTN_IN_FUC->repeat_count + times; 692 | } 693 | else 694 | { 695 | MFBD_BTN_IN_FUC->repeat_count = MFBD_REPEAT_TIME_IN_FUC; 696 | } 697 | } 698 | } 699 | #endif /* MFBD_MBTN_CONTINUE_LONG_COUNT */ 700 | _ppbtn++; 701 | _pbtn = *_ppbtn; 702 | } 703 | } 704 | 705 | /** 706 | * @brief reset all multi-function buttons' params. 707 | * 708 | * @param _pbtn_group is a pointer of mfbd_group_t. 709 | * 710 | * @return None. 711 | */ 712 | void mfbd_mbtn_reset(const mfbd_group_t *_pbtn_group) 713 | { 714 | mfbd_mbtn_t **_ppbtn = _pbtn_group->mbtns; 715 | mfbd_mbtn_t *_pbtn = *_ppbtn; 716 | while (MFBD_BTN_IN_FUC != NULL) 717 | { 718 | MFBD_BTN_IN_FUC->filter_count = 0; 719 | MFBD_BTN_IN_FUC->long_count = 0; 720 | MFBD_BTN_IN_FUC->multiclick_count = 0; 721 | MFBD_BTN_IN_FUC->multiclick_state = 0; 722 | MFBD_BTN_IN_FUC->repeat_count = 0; 723 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 724 | _ppbtn++; 725 | _pbtn = *_ppbtn; 726 | } 727 | } 728 | 729 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 730 | 731 | 732 | /** 733 | * @brief scan all buttons in the group, and report button event value if event happened. 734 | * 735 | * @param _pbtn_group is a pointer of mfbd_group_t. 736 | * 737 | * @return None. 738 | */ 739 | void mfbd_group_scan(const mfbd_group_t *_pbtn_group) 740 | { 741 | 742 | #if MFBD_USE_BTN_SCAN_PRE_FUNC 743 | if (_pbtn_group->btn_scan_prepare != NULL) 744 | { 745 | /* call prepare scan function */ 746 | _pbtn_group->btn_scan_prepare(); 747 | } 748 | #endif /* MFBD_USE_BTN_SCAN_PRE_FUNC */ 749 | 750 | #if MFBD_USE_TINY_BUTTON 751 | if (_pbtn_group->tbtns != NULL) 752 | { 753 | /*scan tiny buttons in group.*/ 754 | mfbd_tbtn_scan(_pbtn_group); 755 | } 756 | #endif /* MFBD_USE_TINY_BUTTON */ 757 | 758 | #if MFBD_USE_NORMAL_BUTTON 759 | if (_pbtn_group->nbtns != NULL) 760 | { 761 | /*scan normal buttons in group.*/ 762 | mfbd_nbtn_scan(_pbtn_group); 763 | } 764 | #endif /* MFBD_USE_NORMAL_BUTTON */ 765 | 766 | #if MFBD_USE_MULTIFUCNTION_BUTTON 767 | if (_pbtn_group->mbtns != NULL) 768 | { 769 | /*scan multifunction buttons in group.*/ 770 | mfbd_mbtn_scan(_pbtn_group); 771 | } 772 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 773 | 774 | #if MFBD_USE_BTN_SCAN_AFTER_FUNC 775 | if (_pbtn_group->btn_scan_after != NULL) 776 | { 777 | /* call after scan function */ 778 | _pbtn_group->btn_scan_after(); 779 | } 780 | #endif /* MFBD_USE_BTN_SCAN_AFTER_FUNC */ 781 | 782 | } 783 | 784 | 785 | /** 786 | * @brief skip some times with last state. 787 | * 788 | * @param _pbtn_group is a pointer of mfbd_group_t. 789 | * @param times is times need to skip. 790 | * 791 | * @return None. 792 | */ 793 | void mfbd_group_skip(const mfbd_group_t *_pbtn_group, mfbd_btn_count_t times) 794 | { 795 | /* tbtn doesn't need to skip times. */ 796 | 797 | #if MFBD_USE_NORMAL_BUTTON 798 | if (_pbtn_group->nbtns != NULL) 799 | { 800 | /* skip times of normal buttons in group.*/ 801 | mfbd_nbtn_skip(_pbtn_group, times); 802 | } 803 | #endif /* MFBD_USE_NORMAL_BUTTON */ 804 | 805 | #if MFBD_USE_MULTIFUCNTION_BUTTON 806 | if (_pbtn_group->mbtns != NULL) 807 | { 808 | /* skip times of multifunction buttons in group.*/ 809 | mfbd_mbtn_skip(_pbtn_group, times); 810 | } 811 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 812 | 813 | } 814 | 815 | 816 | /** 817 | * @brief reset all buttons params in the group. 818 | * 819 | * @param _pbtn_group is a pointer of mfbd_group_t. 820 | * 821 | * @return None. 822 | */ 823 | void mfbd_group_reset(const mfbd_group_t *_pbtn_group) 824 | { 825 | 826 | #if MFBD_USE_TINY_BUTTON 827 | if (_pbtn_group->tbtns != NULL) 828 | { 829 | /*reset tiny buttons in group.*/ 830 | mfbd_tbtn_reset(_pbtn_group); 831 | } 832 | #endif /* MFBD_USE_TINY_BUTTON */ 833 | 834 | #if MFBD_USE_NORMAL_BUTTON 835 | if (_pbtn_group->nbtns != NULL) 836 | { 837 | /*reset normal buttons in group.*/ 838 | mfbd_nbtn_reset(_pbtn_group); 839 | } 840 | #endif /* MFBD_USE_NORMAL_BUTTON */ 841 | 842 | #if MFBD_USE_MULTIFUCNTION_BUTTON 843 | if (_pbtn_group->mbtns != NULL) 844 | { 845 | /*reset multifunction buttons in group.*/ 846 | mfbd_mbtn_reset(_pbtn_group); 847 | } 848 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 849 | 850 | } 851 | 852 | #endif /* (MFBD_USE_SECTION_DEFINITION == 0) */ 853 | -------------------------------------------------------------------------------- /mfbd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, smartmx 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2022-02-22 smartmx the first version. 9 | * 2022-03-15 smartmx each mbtn has it's own max multi-click times. 10 | * 2022-04-16 smartmx drop list definitions, use array, each group has all btn types. 11 | * 2022-08-05 smartmx add reset params function. 12 | * 2022-08-15 smartmx fix bugs. 13 | * 2022-09-07 smartmx add default define apis. 14 | * 2023-03-15 smartmx add state declaration. 15 | * 2023-07-03 smartmx add Section Definition option. 16 | * 2023-07-15 smartmx add skip function, to reduce calling of scan functions. 17 | * 2023-09-19 smartmx improve performance, add MFBD_BTN_STATE_SKIP. 18 | * 19 | */ 20 | 21 | #ifndef _MFBD_H_ 22 | #define _MFBD_H_ 23 | 24 | #include "mfbd_cfg.h" 25 | 26 | #if (MFBD_USE_SECTION_DEFINITION == 0) 27 | 28 | typedef enum 29 | { 30 | MFBD_BTN_STATE_UP = 0, 31 | MFBD_BTN_STATE_DOWN, 32 | MFBD_BTN_STATE_LONG, 33 | MFBD_BTN_STATE_SKIP = 0xff, 34 | } MFBD_BTN_STATE_t; 35 | 36 | #define MFBD_DOWN_CODE_NAME(NAME) NAME##_DOWN_CODE /* when using tbtn/nbtn default define api, this is down-code name. */ 37 | #define MFBD_UP_CODE_NAME(NAME) NAME##_UP_CODE /* when using tbtn/nbtn/mbtn default define api, this is up-code name. */ 38 | #define MFBD_LONG_CODE_NAME(NAME) NAME##_LONG_CODE /* when using nbtn/mbtn default define api, this is long-code name. */ 39 | #define MFBD_DOWN_CODES_NAME(NAME) NAME##_DOWN_CODES /* when using mbtn default define api, this is down-codes name. */ 40 | 41 | /* tiny button definitions, tiny button functions only support down and up event. */ 42 | #if MFBD_PARAMS_SAME_IN_GROUP 43 | 44 | typedef struct _mfbd_tbtn_info_struct 45 | { 46 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 47 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 48 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 49 | } mfbd_tbtn_info_t; 50 | 51 | #else 52 | 53 | typedef struct _mfbd_tbtn_info_struct 54 | { 55 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 56 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 57 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 58 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 59 | } mfbd_tbtn_info_t; 60 | 61 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 62 | 63 | typedef struct _mfbd_tiny_btn_struct 64 | { 65 | const mfbd_tbtn_info_t *btn_info; /* a pointer to mfbd_tbtn_info_t. */ 66 | mfbd_btn_count_t filter_count; /* filter time count when button state changed. */ 67 | unsigned char state; /* the state of button, up or down. */ 68 | } mfbd_tbtn_t; 69 | 70 | #if MFBD_PARAMS_SAME_IN_GROUP 71 | 72 | #define MFBD_TBTN_DEFINE(NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE) \ 73 | static const mfbd_tbtn_info_t NAME##_info = { \ 74 | BTN_DOWN_CODE, \ 75 | BTN_UP_CODE, \ 76 | BTN_INDEX, \ 77 | }; \ 78 | mfbd_tbtn_t NAME = { \ 79 | &NAME##_info, \ 80 | 0, \ 81 | 0, \ 82 | } 83 | 84 | #define MFBD_TBTN_DEFAULT_DEFINE(NAME, BTN_INDEX) \ 85 | static const mfbd_tbtn_info_t NAME##_info = { \ 86 | NAME##_DOWN_CODE, \ 87 | NAME##_UP_CODE, \ 88 | BTN_INDEX, \ 89 | }; \ 90 | mfbd_tbtn_t NAME = { \ 91 | &NAME##_info, \ 92 | 0, \ 93 | 0, \ 94 | } 95 | 96 | #else 97 | 98 | #define MFBD_TBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) \ 99 | static const mfbd_tbtn_info_t NAME##_info = { \ 100 | BTN_DOWN_CODE, \ 101 | BTN_UP_CODE, \ 102 | FILTER_TIME, \ 103 | BTN_INDEX, \ 104 | }; \ 105 | mfbd_tbtn_t NAME = { \ 106 | &NAME##_info, \ 107 | 0, \ 108 | 0, \ 109 | } 110 | 111 | #define MFBD_TBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, FILTER_TIME) \ 112 | static const mfbd_tbtn_info_t NAME##_info = { \ 113 | NAME##_DOWN_CODE, \ 114 | NAME##_UP_CODE, \ 115 | FILTER_TIME, \ 116 | BTN_INDEX, \ 117 | }; \ 118 | mfbd_tbtn_t NAME = { \ 119 | &NAME##_info, \ 120 | 0, \ 121 | 0, \ 122 | } 123 | 124 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 125 | 126 | #define MFBD_TBTN_EXTERN(NAME) extern mfbd_tbtn_t NAME 127 | 128 | #define MFBD_TBTN_ARRAYLIST(NAME, ...) mfbd_tbtn_t* NAME[] = {__VA_ARGS__, NULL} 129 | 130 | 131 | 132 | /* normal button definitions, normal button functions support down, up and long-press event. */ 133 | #if MFBD_PARAMS_SAME_IN_GROUP 134 | 135 | typedef struct _mfbd_nbtn_info_struct 136 | { 137 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 138 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 139 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code instead. */ 140 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 141 | } mfbd_nbtn_info_t; 142 | 143 | #else 144 | 145 | typedef struct _mfbd_nbtn_info_struct 146 | { 147 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 148 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 149 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 150 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 151 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 152 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code instead. */ 153 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 154 | } mfbd_nbtn_info_t; 155 | 156 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 157 | 158 | typedef struct _mfbd_normal_btn_struct 159 | { 160 | const mfbd_nbtn_info_t *btn_info; /* a pointer to mfbd_nbtn_info_t. */ 161 | mfbd_btn_count_t filter_count; /* filter time count when button state changed. */ 162 | mfbd_btn_count_t long_count; /* long time count when button still down. */ 163 | mfbd_btn_count_t repeat_count; /* repeat time count when button still down. */ 164 | unsigned char state; /* the state of button, up or down. */ 165 | } mfbd_nbtn_t; 166 | 167 | 168 | #if MFBD_PARAMS_SAME_IN_GROUP 169 | 170 | #define MFBD_NBTN_DEFINE(NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) \ 171 | static const mfbd_nbtn_info_t NAME##_info = { \ 172 | BTN_DOWN_CODE, \ 173 | BTN_UP_CODE, \ 174 | BTN_LONG_CODE, \ 175 | BTN_INDEX, \ 176 | }; \ 177 | mfbd_nbtn_t NAME = { \ 178 | &NAME##_info, \ 179 | 0, \ 180 | 0, \ 181 | 0, \ 182 | 0, \ 183 | } 184 | 185 | #define MFBD_NBTN_DEFAULT_DEFINE(NAME, BTN_INDEX) \ 186 | static const mfbd_nbtn_info_t NAME##_info = { \ 187 | NAME##_DOWN_CODE, \ 188 | NAME##_UP_CODE, \ 189 | NAME##_LONG_CODE, \ 190 | BTN_INDEX, \ 191 | }; \ 192 | mfbd_nbtn_t NAME = { \ 193 | &NAME##_info, \ 194 | 0, \ 195 | 0, \ 196 | } 197 | 198 | #else 199 | 200 | #define MFBD_NBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) \ 201 | static const mfbd_nbtn_info_t NAME##_info = { \ 202 | FILTER_TIME, \ 203 | REPEAT_TIME, \ 204 | LONG_TIME, \ 205 | BTN_DOWN_CODE, \ 206 | BTN_UP_CODE, \ 207 | BTN_LONG_CODE, \ 208 | BTN_INDEX, \ 209 | }; \ 210 | mfbd_nbtn_t NAME = { \ 211 | &NAME##_info, \ 212 | 0, \ 213 | 0, \ 214 | 0, \ 215 | 0, \ 216 | } 217 | 218 | #define MFBD_NBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME) \ 219 | static const mfbd_nbtn_info_t NAME##_info = { \ 220 | FILTER_TIME, \ 221 | REPEAT_TIME, \ 222 | LONG_TIME, \ 223 | NAME##_DOWN_CODE, \ 224 | NAME##_UP_CODE, \ 225 | NAME##_LONG_CODE, \ 226 | BTN_INDEX, \ 227 | }; \ 228 | mfbd_nbtn_t NAME = { \ 229 | &NAME##_info, \ 230 | 0, \ 231 | 0, \ 232 | } 233 | 234 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 235 | 236 | #define MFBD_NBTN_EXTERN(NAME) extern mfbd_nbtn_t NAME 237 | 238 | #define MFBD_NBTN_ARRAYLIST(NAME, ...) mfbd_nbtn_t* NAME[] = {__VA_ARGS__, NULL} 239 | 240 | 241 | 242 | /* multi-function button definitions, multi-function button functions support down, up, long-press and multi-click event. */ 243 | #if MFBD_PARAMS_SAME_IN_GROUP 244 | 245 | typedef struct _mfbd_mbtn_info_struct 246 | { 247 | const mfbd_btn_code_t *btn_down_code; /* pointer to multi-click keyCodes when button down. */ 248 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 249 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code[0] instead. */ 250 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 251 | unsigned char max_multiclick_state; /* max multiclick states. */ 252 | } mfbd_mbtn_info_t; 253 | 254 | #else 255 | 256 | typedef struct _mfbd_mbtn_info_struct 257 | { 258 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 259 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 260 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 261 | mfbd_btn_count_t multiclick_time; /* multi-click time when button still up, set 0 will disable multi-click time count. */ 262 | const mfbd_btn_code_t *btn_down_code; /* pointer to multi-click keyCodes when button down. */ 263 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 264 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code[0] instead. */ 265 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 266 | unsigned char max_multiclick_state; /* max multiclick states. */ 267 | } mfbd_mbtn_info_t; 268 | 269 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 270 | /* 271 | * @Note: 272 | * repeat_count and long_count are conflict to multi-click. 273 | * repeat_count and long_count only check in the first button down event, and will disable in next multi-click event. 274 | * also, if repeat_count and long_count event has happened in the first down event, it will reset multiclick_state. 275 | */ 276 | typedef struct _mfbd_multi_fuction_btn_struct 277 | { 278 | const mfbd_mbtn_info_t *btn_info; /* a pointer to mfbd_mbtn_info_t. */ 279 | mfbd_btn_count_t filter_count; /* filter time count when button state changed. */ 280 | mfbd_btn_count_t long_count; /* long time count when button still down. */ 281 | mfbd_btn_count_t repeat_count; /* repeat time count when button still down. */ 282 | mfbd_btn_count_t multiclick_count; /* multi-click time count when button is up. */ 283 | unsigned char multiclick_state; /* multi-click count when button is in multi-click state. */ 284 | unsigned char state; /* the state of button, up or down. */ 285 | } mfbd_mbtn_t; 286 | 287 | #if MFBD_PARAMS_SAME_IN_GROUP 288 | 289 | #define MFBD_MBTN_DEFINE(NAME, BTN_INDEX, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) \ 290 | static const mfbd_btn_code_t NAME##_down_codes[MAX_MULTICLICK_STATE + 1] = {BTN_DOWN_CODE, __VA_ARGS__}; \ 291 | static const mfbd_mbtn_info_t NAME##_info = { \ 292 | NAME##_down_codes, \ 293 | BTN_UP_CODE, \ 294 | BTN_LONG_CODE, \ 295 | BTN_INDEX, \ 296 | MAX_MULTICLICK_STATE, \ 297 | }; \ 298 | mfbd_mbtn_t NAME = { \ 299 | &NAME##_info, \ 300 | 0, \ 301 | 0, \ 302 | 0, \ 303 | 0, \ 304 | 0, \ 305 | 0, \ 306 | } 307 | 308 | #define MFBD_MBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, MAX_MULTICLICK_STATE) \ 309 | static const mfbd_mbtn_info_t NAME##_info = { \ 310 | NAME##_DOWN_CODES, \ 311 | NAME##_UP_CODE, \ 312 | NAME##_LONG_CODE, \ 313 | BTN_INDEX, \ 314 | MAX_MULTICLICK_STATE, \ 315 | }; \ 316 | mfbd_mbtn_t NAME = { \ 317 | &NAME##_info, \ 318 | 0, \ 319 | 0, \ 320 | 0, \ 321 | 0, \ 322 | 0, \ 323 | 0, \ 324 | } 325 | 326 | #else 327 | 328 | #define MFBD_MBTN_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) \ 329 | static const mfbd_btn_code_t NAME##_down_codes[MAX_MULTICLICK_STATE + 1] = {BTN_DOWN_CODE, __VA_ARGS__}; \ 330 | static const mfbd_mbtn_info_t NAME##_info = { \ 331 | FILTER_TIME, \ 332 | REPEAT_TIME, \ 333 | LONG_TIME, \ 334 | MULTICLICK_TIME, \ 335 | NAME##_down_codes, \ 336 | BTN_UP_CODE, \ 337 | BTN_LONG_CODE, \ 338 | BTN_INDEX, \ 339 | MAX_MULTICLICK_STATE, \ 340 | }; \ 341 | mfbd_mbtn_t NAME = { \ 342 | &NAME##_info, \ 343 | 0, \ 344 | 0, \ 345 | 0, \ 346 | 0, \ 347 | 0, \ 348 | 0, \ 349 | } 350 | 351 | #define MFBD_MBTN_DEFAULT_DEFINE(NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE) \ 352 | static const mfbd_mbtn_info_t NAME##_info = { \ 353 | FILTER_TIME, \ 354 | REPEAT_TIME, \ 355 | LONG_TIME, \ 356 | MULTICLICK_TIME, \ 357 | NAME##_DOWN_CODES, \ 358 | NAME##_UP_CODE, \ 359 | NAME##_LONG_CODE, \ 360 | BTN_INDEX, \ 361 | MAX_MULTICLICK_STATE, \ 362 | }; \ 363 | mfbd_mbtn_t NAME = { \ 364 | &NAME##_info, \ 365 | 0, \ 366 | 0, \ 367 | 0, \ 368 | 0, \ 369 | 0, \ 370 | 0, \ 371 | } 372 | 373 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 374 | 375 | #define MFBD_MBTN_EXTERN(NAME) extern mfbd_mbtn_t NAME 376 | 377 | #define MFBD_MBTN_ARRAYLIST(NAME, ...) mfbd_mbtn_t* NAME[] = {__VA_ARGS__, NULL} 378 | 379 | 380 | 381 | /* mfbd group struct */ 382 | typedef struct _mfbd_group_struct 383 | { 384 | /* used to read whether button is down. */ 385 | unsigned char (*is_btn_down_func)(mfbd_btn_index_t btn_index); 386 | 387 | /* used to report btn_value, must have a legal value, must not be NULL. */ 388 | void (*btn_value_report)(mfbd_btn_code_t btn_value); 389 | 390 | #if MFBD_USE_TINY_BUTTON 391 | /* pointer to the head of tiny buttons pointer array */ 392 | mfbd_tbtn_t **tbtns; 393 | #endif /* MFBD_USE_TINY_BUTTON */ 394 | 395 | #if MFBD_USE_NORMAL_BUTTON 396 | /* pointer to the head of normal buttons pointer array */ 397 | mfbd_nbtn_t **nbtns; 398 | #endif /* MFBD_USE_NORMAL_BUTTON */ 399 | 400 | #if MFBD_USE_MULTIFUCNTION_BUTTON 401 | /* pointer to the head of multifunction buttons pointer array */ 402 | mfbd_mbtn_t **mbtns; 403 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 404 | 405 | /* if set MFBD_PARAMS_SAME_IN_GROUP to 1, all btns in group has same params. */ 406 | #if MFBD_PARAMS_SAME_IN_GROUP 407 | 408 | #if MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 409 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 410 | #endif /* MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 411 | 412 | #if MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 413 | 414 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 415 | 416 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 417 | 418 | #endif /* MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 419 | 420 | #if MFBD_USE_MULTIFUCNTION_BUTTON 421 | 422 | mfbd_btn_count_t multiclick_time; /* multi-click time when button still up, set 0 will disable multi-click time count. */ 423 | 424 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 425 | 426 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 427 | 428 | #if MFBD_USE_BTN_SCAN_PRE_FUNC 429 | /* prepare function when start to scan buttons for each group. */ 430 | void (*btn_scan_prepare)(void); 431 | #endif /* MFBD_USE_BTN_SCAN_PRE_FUNC */ 432 | 433 | #if MFBD_USE_BTN_SCAN_AFTER_FUNC 434 | /* function after scanning buttons for each group. */ 435 | void (*btn_scan_after)(void); 436 | #endif /* MFBD_USE_BTN_SCAN_AFTER_FUNC */ 437 | 438 | } mfbd_group_t; 439 | 440 | extern void mfbd_group_scan(const mfbd_group_t *_pbtn_group); 441 | 442 | extern void mfbd_group_skip(const mfbd_group_t *_pbtn_group, mfbd_btn_count_t times); 443 | 444 | extern void mfbd_group_reset(const mfbd_group_t *_pbtn_group); 445 | 446 | #endif /* (MFBD_USE_SECTION_DEFINITION == 0) */ 447 | 448 | #endif /* _MFBD_H_ */ 449 | -------------------------------------------------------------------------------- /mfbd_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, smartmx 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2022-02-22 smartmx the first version. 9 | * 2022-03-15 smartmx each mbtn has it's own max multi-click times. 10 | * 2022-04-16 smartmx drop list definitions, use arraylist, each group has all btn types. 11 | * 2022-08-05 smartmx add reset params function. 12 | * 2022-12-04 smartmx change some definitions, add rtconfig.h. 13 | * 2023-03-25 smartmx add some comment. 14 | * 2023-07-03 smartmx add Section Definition option. 15 | * 2023-07-22 smartmx add MFBD_MBTN_MULTICLICK_LONG_EVT and MFBD_MBTN_CONTINUE_LONG_COUNT option. 16 | * 17 | */ 18 | 19 | #ifndef _MFBD_CFG_H_ 20 | #define _MFBD_CFG_H_ 21 | 22 | /* add type definitions of your chips in your compiler environment. */ 23 | #include "stdint.h" 24 | /* if you are not use mfbd in rt-thread, delete #include "rtconfig.h" below */ 25 | #include "rtconfig.h" 26 | 27 | #ifndef NULL 28 | #define NULL 0 29 | #endif 30 | 31 | /* use section definitions can simplify the code, but limited with the complier. */ 32 | #ifdef PKG_MFBD_USE_SECTION_DEFINITION 33 | #define MFBD_USE_SECTION_DEFINITION 1 34 | #else 35 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 36 | #define MFBD_USE_SECTION_DEFINITION 0 37 | #endif 38 | 39 | /* mfbd_btn_code_t is the type of value for every button event. */ 40 | #ifdef PKG_MFBD_BTN_CODE_SIZE 41 | #if PKG_MFBD_BTN_CODE_SIZE==1 42 | typedef uint8_t mfbd_btn_code_t; 43 | #elif PKG_MFBD_BTN_CODE_SIZE==2 44 | typedef uint16_t mfbd_btn_code_t; 45 | #elif PKG_MFBD_BTN_CODE_SIZE==4 46 | typedef uint32_t mfbd_btn_code_t; 47 | #elif PKG_MFBD_BTN_CODE_SIZE==8 48 | typedef uint64_t mfbd_btn_code_t; 49 | #else 50 | typedef uint16_t mfbd_btn_code_t; 51 | #endif 52 | #else 53 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 54 | typedef uint16_t mfbd_btn_code_t; 55 | #endif 56 | 57 | /* mfbd_btn_count_t is the type of count time for button scanning. */ 58 | #ifdef PKG_MFBD_BTN_COUNT_SIZE 59 | #if PKG_MFBD_BTN_COUNT_SIZE==1 60 | typedef uint8_t mfbd_btn_count_t; 61 | #elif PKG_MFBD_BTN_COUNT_SIZE==2 62 | typedef uint16_t mfbd_btn_count_t; 63 | #elif PKG_MFBD_BTN_COUNT_SIZE==4 64 | typedef uint32_t mfbd_btn_count_t; 65 | #elif PKG_MFBD_BTN_COUNT_SIZE==8 66 | typedef uint64_t mfbd_btn_count_t; 67 | #else 68 | typedef uint16_t mfbd_btn_count_t; 69 | #endif 70 | #else 71 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 72 | typedef uint16_t mfbd_btn_count_t; 73 | #endif 74 | 75 | /* mfbd_btn_index_t is the type of params when calling is_btn_down_func in mfbd_group_t. */ 76 | #ifdef PKG_MFBD_BTN_INDEX_SIZE 77 | #if PKG_MFBD_BTN_INDEX_SIZE==1 78 | typedef uint8_t mfbd_btn_index_t; 79 | #elif PKG_MFBD_BTN_INDEX_SIZE==2 80 | typedef uint16_t mfbd_btn_index_t; 81 | #elif PKG_MFBD_BTN_INDEX_SIZE==4 82 | typedef uint32_t mfbd_btn_index_t; 83 | #elif PKG_MFBD_BTN_INDEX_SIZE==8 84 | typedef uint64_t mfbd_btn_index_t; 85 | #elif PKG_MFBD_BTN_INDEX_SIZE==0 86 | typedef void *mfbd_btn_index_t; 87 | #else 88 | typedef uint32_t mfbd_btn_index_t; 89 | #endif 90 | #else 91 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 92 | typedef uint32_t mfbd_btn_index_t; 93 | #endif 94 | 95 | /* set MFBD_USE_TINY_BUTTON to 1 will enable tiny button functions. */ 96 | #ifdef PKG_MFBD_USE_TINY_BUTTON 97 | #define MFBD_USE_TINY_BUTTON 1 98 | #else 99 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 100 | #define MFBD_USE_TINY_BUTTON 0 101 | #endif 102 | 103 | /* set MFBD_USE_NORMAL_BUTTON to 1 will enable normal button functions. */ 104 | #ifdef PKG_MFBD_USE_NORMAL_BUTTON 105 | #define MFBD_USE_NORMAL_BUTTON 1 106 | #else 107 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 108 | #define MFBD_USE_NORMAL_BUTTON 0 109 | #endif 110 | 111 | /* set MFBD_USE_MULTIFUCNTION_BUTTON to 1 will enable multifunction button functions. */ 112 | #ifdef PKG_MFBD_USE_MULTIFUCNTION_BUTTON 113 | #define MFBD_USE_MULTIFUCNTION_BUTTON 1 114 | #else 115 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 116 | #define MFBD_USE_MULTIFUCNTION_BUTTON 0 117 | #endif 118 | 119 | /* set MFBD_USE_BTN_SCAN_PRE_FUNC to 1 will enable running prepare_function before run button detection function */ 120 | #ifdef PKG_MFBD_USE_BTN_SCAN_PRE_FUNC 121 | #define MFBD_USE_BTN_SCAN_PRE_FUNC 1 122 | #else 123 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 124 | #define MFBD_USE_BTN_SCAN_PRE_FUNC 0 125 | #endif 126 | 127 | /* set MFBD_USE_BTN_SCAN_AFTER_FUNC to 1 will enable running after_function after run button detection function */ 128 | #ifdef PKG_MFBD_USE_BTN_SCAN_AFTER_FUNC 129 | #define MFBD_USE_BTN_SCAN_AFTER_FUNC 1 130 | #else 131 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 132 | #define MFBD_USE_BTN_SCAN_AFTER_FUNC 0 133 | #endif 134 | 135 | /* 136 | * @Note: 137 | * set MFBD_PARAMS_SAME_IN_GROUP to 1 means all key's filter_time/repeat_time/long_time/multiclick_time are same, 138 | * it will not save filter_time/repeat_time/long_time/multiclick_time in btn_info struct. 139 | * if MFBD_PARAMS_SAME_IN_GROUP is 1, btns cannot disable repeat count alone. 140 | */ 141 | #ifdef PKG_MFBD_PARAMS_SAME_IN_GROUP 142 | #define MFBD_PARAMS_SAME_IN_GROUP 1 143 | #else 144 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 145 | #define MFBD_PARAMS_SAME_IN_GROUP 0 146 | #endif 147 | 148 | /* set MFBD_MULTICLICK_STATE_AUTO_RESET to 1 will auto reset multiclick state to 0 when reach to max multicick state. */ 149 | #ifdef PKG_MFBD_MULTICLICK_STATE_AUTO_RESET 150 | #define MFBD_MULTICLICK_STATE_AUTO_RESET 1 151 | #else 152 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 153 | #define MFBD_MULTICLICK_STATE_AUTO_RESET 0 154 | #endif 155 | 156 | /* set MFBD_MBTN_CONTINUE_LONG_COUNT to 1 will continue count to change state to long after when multiclick state is not 0. */ 157 | #ifdef PKG_MFBD_MBTN_CONTINUE_LONG_COUNT 158 | #define MFBD_MBTN_CONTINUE_LONG_COUNT 1 159 | #else 160 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 161 | #define MFBD_MBTN_CONTINUE_LONG_COUNT 0 162 | #endif 163 | 164 | #if MFBD_MBTN_CONTINUE_LONG_COUNT 165 | /* 166 | * @Note: 167 | * MFBD_MBTN_MULTICLICK_LONG_EVT only valid when MFBD_MBTN_CONTINUE_LONG_COUNT is not 0. 168 | * When MFBD_MBTN_MULTICLICK_LONG_EVT is 1, it will still report long code and repeat downcodes after multiclick. 169 | */ 170 | #ifdef PKG_MFBD_MBTN_MULTICLICK_LONG_EVT 171 | #define MFBD_MBTN_MULTICLICK_LONG_EVT 1 172 | #else 173 | /* if you are not use mfbd in rt-thread, you can change this instead. */ 174 | #define MFBD_MBTN_MULTICLICK_LONG_EVT 0 175 | #endif 176 | #else 177 | #define MFBD_MBTN_MULTICLICK_LONG_EVT 0 178 | #endif 179 | 180 | #endif /* _MFBD_CFG_H_ */ 181 | -------------------------------------------------------------------------------- /mfbd_sd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, smartmx 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2023-07-03 smartmx the first version, Multi-Function Button Dectection with Section Definition. 9 | * 2023-07-15 smartmx add skip function, to reduce calling of scan functions. 10 | * 2023-07-22 smartmx add MFBD_MBTN_MULTICLICK_LONG_EVT and MFBD_MBTN_CONTINUE_LONG_COUNT option. 11 | * 2023-09-19 smartmx improve performance, add MFBD_BTN_STATE_SKIP. 12 | * 13 | */ 14 | 15 | #include "mfbd_sd.h" 16 | 17 | #if MFBD_USE_SECTION_DEFINITION 18 | 19 | #define MFBD_BTN_IN_FUC (_pbtn_info->btn) 20 | #define MFBD_BTN_INFO_IN_FUC (_pbtn_info) 21 | 22 | #if MFBD_PARAMS_SAME_IN_GROUP 23 | 24 | /* filter_time */ 25 | #define MFBD_FILTER_TIME_IN_FUC (_pbtn_group->filter_time) 26 | /* long_time */ 27 | #define MFBD_LONG_TIME_IN_FUC (_pbtn_group->long_time) 28 | /* repeat_time */ 29 | #define MFBD_REPEAT_TIME_IN_FUC (_pbtn_group->repeat_time) 30 | /* multiclick_time */ 31 | #define MFBD_MULTICLICK_TIME_IN_FUC (_pbtn_group->multiclick_time) 32 | 33 | #else 34 | 35 | /* filter_time */ 36 | #define MFBD_FILTER_TIME_IN_FUC (_pbtn_info->filter_time) 37 | /* long_time */ 38 | #define MFBD_LONG_TIME_IN_FUC (_pbtn_info->long_time) 39 | /* repeat_time */ 40 | #define MFBD_REPEAT_TIME_IN_FUC (_pbtn_info->repeat_time) 41 | /* multiclick_time */ 42 | #define MFBD_MULTICLICK_TIME_IN_FUC (_pbtn_info->multiclick_time) 43 | 44 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 45 | 46 | 47 | #if MFBD_USE_TINY_BUTTON 48 | /** 49 | * @brief scan all tiny buttons, and report button event value if event happened. 50 | * 51 | * @param _pbtn_group is a pointer of mfbd_group_t. 52 | * @param _pbtn_info_start is a pointer to the start address in flash with type mfbd_tbtn_info_t. 53 | * @param _pbtn_info_end is a pointer to the end address in flash with type mfbd_tbtn_info_t. 54 | * 55 | * @return None. 56 | */ 57 | void mfbd_tbtn_scan(const mfbd_group_t *_pbtn_group, const mfbd_tbtn_info_t *_pbtn_info_start, const mfbd_tbtn_info_t *_pbtn_info_end) 58 | { 59 | const mfbd_tbtn_info_t *_pbtn_info = _pbtn_info_start; 60 | MFBD_BTN_STATE_t btn_state; 61 | 62 | while (1) 63 | { 64 | if (_pbtn_info_end <= _pbtn_info) 65 | { 66 | break; 67 | } 68 | 69 | btn_state = _pbtn_group->is_btn_down_func(MFBD_BTN_INFO_IN_FUC->btn_index); 70 | if (btn_state == MFBD_BTN_STATE_DOWN) 71 | { 72 | if (MFBD_BTN_IN_FUC->filter_count >= ((MFBD_FILTER_TIME_IN_FUC) * 2)) 73 | { 74 | /* it means the button is down for over filter_time. */ 75 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_UP) 76 | { 77 | if (MFBD_BTN_INFO_IN_FUC->btn_down_code > 0) 78 | { 79 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code); 80 | } 81 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_DOWN; 82 | } 83 | } 84 | else if (MFBD_BTN_IN_FUC->filter_count >= (MFBD_FILTER_TIME_IN_FUC)) 85 | { 86 | MFBD_BTN_IN_FUC->filter_count++; 87 | } 88 | else 89 | { 90 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 91 | } 92 | } 93 | else if (btn_state == MFBD_BTN_STATE_UP) 94 | { 95 | if (MFBD_BTN_IN_FUC->filter_count == 0) 96 | { 97 | if (MFBD_BTN_IN_FUC->state != MFBD_BTN_STATE_UP) 98 | { 99 | if (MFBD_BTN_INFO_IN_FUC->btn_up_code > 0) 100 | { 101 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_up_code); 102 | } 103 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 104 | } 105 | } 106 | else 107 | { 108 | if (MFBD_BTN_IN_FUC->filter_count > (MFBD_FILTER_TIME_IN_FUC)) 109 | { 110 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 111 | } 112 | else if (MFBD_BTN_IN_FUC->filter_count != 0) 113 | { 114 | MFBD_BTN_IN_FUC->filter_count--; 115 | } 116 | } 117 | } 118 | _pbtn_info++; 119 | } 120 | } 121 | 122 | /** 123 | * @brief reset all tiny buttons' params. 124 | * 125 | * @param _pbtn_info_start is a pointer to the start address in flash with type mfbd_tbtn_info_t. 126 | * @param _pbtn_info_end is a pointer to the end address in flash with type mfbd_tbtn_info_t. 127 | * 128 | * @return None. 129 | */ 130 | void mfbd_tbtn_reset(const mfbd_tbtn_info_t *_pbtn_info_start, const mfbd_tbtn_info_t *_pbtn_info_end) 131 | { 132 | const mfbd_tbtn_info_t *_pbtn_info = _pbtn_info_start; 133 | while (1) 134 | { 135 | if (_pbtn_info_end <= _pbtn_info) 136 | { 137 | break; 138 | } 139 | MFBD_BTN_IN_FUC->filter_count = 0; 140 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 141 | 142 | _pbtn_info++; 143 | } 144 | } 145 | 146 | #endif /* MFBD_USE_TINY_BUTTON */ 147 | 148 | 149 | #if MFBD_USE_NORMAL_BUTTON 150 | 151 | /** 152 | * @brief scan all normal buttons, and report button event value if event happened. 153 | * 154 | * @param _pbtn_group is a pointer of mfbd_group_t. 155 | * @param _pbtn_info_start is a pointer to the start address in flash with type mfbd_nbtn_info_t. 156 | * @param _pbtn_info_end is a pointer to the end address in flash with type mfbd_nbtn_info_t. 157 | * 158 | * @return None 159 | */ 160 | void mfbd_nbtn_scan(const mfbd_group_t *_pbtn_group, const mfbd_nbtn_info_t *_pbtn_info_start, const mfbd_nbtn_info_t *_pbtn_info_end) 161 | { 162 | const mfbd_nbtn_info_t *_pbtn_info = _pbtn_info_start; 163 | MFBD_BTN_STATE_t btn_state; 164 | 165 | while (1) 166 | { 167 | if (_pbtn_info_end <= _pbtn_info) 168 | { 169 | break; 170 | } 171 | 172 | btn_state = _pbtn_group->is_btn_down_func(MFBD_BTN_INFO_IN_FUC->btn_index); 173 | if (btn_state == MFBD_BTN_STATE_DOWN) 174 | { 175 | if (MFBD_BTN_IN_FUC->filter_count >= ((MFBD_FILTER_TIME_IN_FUC) * 2)) 176 | { 177 | /* it means the button is down for over filter_time. */ 178 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 179 | { 180 | /* MFBD_BTN_STATE_LONG */ 181 | if (MFBD_BTN_IN_FUC->repeat_count > 0) 182 | { 183 | MFBD_BTN_IN_FUC->repeat_count++; 184 | if (MFBD_BTN_IN_FUC->repeat_count > (MFBD_REPEAT_TIME_IN_FUC)) 185 | { 186 | /* repeat event has happened, reset repeat_count to 1. */ 187 | MFBD_BTN_IN_FUC->repeat_count = 1; 188 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code); 189 | } 190 | } 191 | } 192 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 193 | { 194 | if (MFBD_BTN_IN_FUC->long_count > 0) 195 | { 196 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 197 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 198 | { 199 | MFBD_BTN_IN_FUC->long_count++; 200 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 201 | { 202 | /* it means the button is down for over long_time. */ 203 | if (((MFBD_REPEAT_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_down_code != 0)) 204 | { 205 | /* repeat event is enabled in this btn. */ 206 | MFBD_BTN_IN_FUC->repeat_count = 1; 207 | } 208 | else 209 | { 210 | /* repeat event is disabled in this btn. */ 211 | MFBD_BTN_IN_FUC->repeat_count = 0; 212 | } 213 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 214 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 215 | } 216 | } 217 | } 218 | } 219 | else 220 | { 221 | /* MFBD_BTN_STATE_UP */ 222 | /* clear long_count. */ 223 | if (((MFBD_LONG_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_long_code != 0)) 224 | { 225 | /* long event is enabled in this btn. */ 226 | MFBD_BTN_IN_FUC->long_count = 1; 227 | } 228 | else 229 | { 230 | /* long event is disabled in this btn. */ 231 | MFBD_BTN_IN_FUC->long_count = 0; 232 | } 233 | if (MFBD_BTN_INFO_IN_FUC->btn_down_code > 0) 234 | { 235 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code); 236 | } 237 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_DOWN; 238 | } 239 | } 240 | else if (MFBD_BTN_IN_FUC->filter_count >= (MFBD_FILTER_TIME_IN_FUC)) 241 | { 242 | MFBD_BTN_IN_FUC->filter_count++; 243 | } 244 | else 245 | { 246 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 247 | } 248 | } 249 | else if (btn_state == MFBD_BTN_STATE_UP) 250 | { 251 | if (MFBD_BTN_IN_FUC->filter_count == 0) 252 | { 253 | if (MFBD_BTN_IN_FUC->state != MFBD_BTN_STATE_UP) 254 | { 255 | if (MFBD_BTN_INFO_IN_FUC->btn_up_code > 0) 256 | { 257 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_up_code); 258 | } 259 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 260 | } 261 | } 262 | else 263 | { 264 | if (MFBD_BTN_IN_FUC->filter_count > (MFBD_FILTER_TIME_IN_FUC)) 265 | { 266 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 267 | } 268 | else if (MFBD_BTN_IN_FUC->filter_count != 0) 269 | { 270 | MFBD_BTN_IN_FUC->filter_count--; 271 | } 272 | } 273 | } 274 | _pbtn_info++; 275 | } 276 | } 277 | 278 | /** 279 | * @brief skip some times of mfbd_btn_count_t with last state. 280 | * 281 | * @param _pbtn_group is a pointer of mfbd_group_t. 282 | * @param times is times need to skip. 283 | * 284 | * @return None. 285 | */ 286 | void mfbd_nbtn_skip(const mfbd_group_t *_pbtn_group, const mfbd_nbtn_info_t *_pbtn_info_start, const mfbd_nbtn_info_t *_pbtn_info_end, mfbd_btn_count_t times) 287 | { 288 | const mfbd_nbtn_info_t *_pbtn_info = _pbtn_info_start; 289 | 290 | while (1) 291 | { 292 | if (_pbtn_info_end <= _pbtn_info) 293 | { 294 | break; 295 | } 296 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 297 | { 298 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 299 | { 300 | if (((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 301 | { 302 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 303 | } 304 | else 305 | { 306 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 307 | } 308 | } 309 | } 310 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 311 | { 312 | if ((MFBD_BTN_IN_FUC->repeat_count > 0) && (MFBD_BTN_IN_FUC->repeat_count < (MFBD_REPEAT_TIME_IN_FUC))) 313 | { 314 | if (((MFBD_REPEAT_TIME_IN_FUC) - MFBD_BTN_IN_FUC->repeat_count) > times) 315 | { 316 | MFBD_BTN_IN_FUC->repeat_count = MFBD_BTN_IN_FUC->repeat_count + times; 317 | } 318 | else 319 | { 320 | MFBD_BTN_IN_FUC->repeat_count = MFBD_REPEAT_TIME_IN_FUC; 321 | } 322 | } 323 | } 324 | _pbtn_info++; 325 | } 326 | } 327 | 328 | /** 329 | * @brief reset all normal buttons' params. 330 | * 331 | * @param _pbtn_info_start is a pointer to the start address in flash with type mfbd_nbtn_info_t. 332 | * @param _pbtn_info_end is a pointer to the end address in flash with type mfbd_nbtn_info_t. 333 | * 334 | * @return None. 335 | */ 336 | void mfbd_nbtn_reset(const mfbd_nbtn_info_t *_pbtn_info_start, const mfbd_nbtn_info_t *_pbtn_info_end) 337 | { 338 | const mfbd_nbtn_info_t *_pbtn_info = _pbtn_info_start; 339 | while (1) 340 | { 341 | if (_pbtn_info_end <= _pbtn_info) 342 | { 343 | break; 344 | } 345 | MFBD_BTN_IN_FUC->filter_count = 0; 346 | MFBD_BTN_IN_FUC->long_count = 0; 347 | MFBD_BTN_IN_FUC->repeat_count = 0; 348 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 349 | 350 | _pbtn_info++; 351 | } 352 | } 353 | 354 | #endif /* MFBD_USE_NORMAL_BUTTON */ 355 | 356 | 357 | #if MFBD_USE_MULTIFUCNTION_BUTTON 358 | 359 | /** 360 | * @brief scan all multi-function buttons, and report button event value if event happened. 361 | * 362 | * @param _pbtn_group is a pointer of mfbd_group_t. 363 | * @param _pbtn_info_start is a pointer to the start address in flash with type mfbd_mbtn_info_t. 364 | * @param _pbtn_info_end is a pointer to the end address in flash with type mfbd_mbtn_info_t. 365 | * 366 | * @return None. 367 | */ 368 | void mfbd_mbtn_scan(const mfbd_group_t *_pbtn_group, const mfbd_mbtn_info_t *_pbtn_info_start, const mfbd_mbtn_info_t *_pbtn_info_end) 369 | { 370 | const mfbd_mbtn_info_t *_pbtn_info = _pbtn_info_start; 371 | MFBD_BTN_STATE_t btn_state; 372 | 373 | while (1) 374 | { 375 | if (_pbtn_info_end <= _pbtn_info) 376 | { 377 | break; 378 | } 379 | 380 | btn_state = _pbtn_group->is_btn_down_func(MFBD_BTN_INFO_IN_FUC->btn_index); 381 | if (btn_state == MFBD_BTN_STATE_DOWN) 382 | { 383 | if (MFBD_BTN_IN_FUC->filter_count >= ((MFBD_FILTER_TIME_IN_FUC) * 2)) 384 | { 385 | /* it means the button is down for over filter_time. */ 386 | #if MFBD_MBTN_CONTINUE_LONG_COUNT 387 | #if MFBD_MBTN_MULTICLICK_LONG_EVT 388 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 389 | { 390 | /* MFBD_BTN_STATE_LONG */ 391 | if (MFBD_BTN_IN_FUC->repeat_count > 0) 392 | { 393 | MFBD_BTN_IN_FUC->repeat_count++; 394 | if (MFBD_BTN_IN_FUC->repeat_count > (MFBD_REPEAT_TIME_IN_FUC)) 395 | { 396 | /* repeat event has happened, clear repeat_count. */ 397 | MFBD_BTN_IN_FUC->repeat_count = 1; 398 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state]); 399 | } 400 | } 401 | } 402 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 403 | { 404 | if (MFBD_BTN_IN_FUC->long_count > 0) 405 | { 406 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 407 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 408 | { 409 | MFBD_BTN_IN_FUC->long_count++; 410 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 411 | { 412 | /* it means the button is down for over long_time. */ 413 | if (((MFBD_REPEAT_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state] != 0)) 414 | { 415 | /* repeat event is enabled in this btn. */ 416 | MFBD_BTN_IN_FUC->repeat_count = 1; 417 | } 418 | else 419 | { 420 | /* repeat event is disabled in this btn. */ 421 | MFBD_BTN_IN_FUC->repeat_count = 0; 422 | } 423 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 424 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 425 | } 426 | } 427 | } 428 | } 429 | #else 430 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 431 | { 432 | /* we don't support repeat event here.*/ 433 | } 434 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 435 | { 436 | if (MFBD_BTN_IN_FUC->long_count > 0) 437 | { 438 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 439 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 440 | { 441 | MFBD_BTN_IN_FUC->long_count++; 442 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 443 | { 444 | /* it means the button is down for over long_time. */ 445 | if (MFBD_BTN_IN_FUC->multiclick_state == 0) 446 | { 447 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 448 | } 449 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 450 | } 451 | } 452 | } 453 | } 454 | #endif /* MFBD_MBTN_MULTICLICK_LONG_EVT */ 455 | #else 456 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) 457 | { 458 | /* MFBD_BTN_STATE_LONG */ 459 | if (MFBD_BTN_IN_FUC->repeat_count > 0) 460 | { 461 | MFBD_BTN_IN_FUC->repeat_count++; 462 | if (MFBD_BTN_IN_FUC->repeat_count > (MFBD_REPEAT_TIME_IN_FUC)) 463 | { 464 | /* repeat event has happened, clear repeat_count. */ 465 | MFBD_BTN_IN_FUC->repeat_count = 1; 466 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code[0]); 467 | } 468 | } 469 | } 470 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 471 | { 472 | if (MFBD_BTN_IN_FUC->multiclick_state == 0) 473 | { 474 | if (MFBD_BTN_IN_FUC->long_count > 0) 475 | { 476 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 477 | if (MFBD_BTN_IN_FUC->long_count <= (MFBD_LONG_TIME_IN_FUC)) 478 | { 479 | MFBD_BTN_IN_FUC->long_count++; 480 | if (MFBD_BTN_IN_FUC->long_count > (MFBD_LONG_TIME_IN_FUC)) 481 | { 482 | /* it means the button is down for over long_time. */ 483 | if (((MFBD_REPEAT_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_down_code[0] != 0)) 484 | { 485 | /* repeat event is enabled in this btn. */ 486 | MFBD_BTN_IN_FUC->repeat_count = 1; 487 | } 488 | else 489 | { 490 | /* repeat event is disabled in this btn. */ 491 | MFBD_BTN_IN_FUC->repeat_count = 0; 492 | } 493 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_long_code); 494 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_LONG; 495 | } 496 | } 497 | } 498 | } 499 | } 500 | #endif /* MFBD_MBTN_CONTINUE_LONG_COUNT */ 501 | else 502 | { 503 | /* MFBD_BTN_STATE_UP */ 504 | /* clear long_count. */ 505 | if (((MFBD_LONG_TIME_IN_FUC) > 0) && (MFBD_BTN_INFO_IN_FUC->btn_long_code != 0)) 506 | { 507 | /* long event is enabled in this btn. */ 508 | MFBD_BTN_IN_FUC->long_count = 1; 509 | } 510 | else 511 | { 512 | /* long event is disabled in this btn. */ 513 | MFBD_BTN_IN_FUC->long_count = 0; 514 | } 515 | if (MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state] > 0) 516 | { 517 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_down_code[MFBD_BTN_IN_FUC->multiclick_state]); 518 | } 519 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_DOWN; 520 | } 521 | } 522 | else if (MFBD_BTN_IN_FUC->filter_count >= (MFBD_FILTER_TIME_IN_FUC)) 523 | { 524 | MFBD_BTN_IN_FUC->filter_count++; 525 | } 526 | else 527 | { 528 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 529 | } 530 | } 531 | else if (btn_state == MFBD_BTN_STATE_UP) 532 | { 533 | if (MFBD_BTN_IN_FUC->filter_count == 0) 534 | { 535 | if (MFBD_BTN_IN_FUC->state != MFBD_BTN_STATE_UP) 536 | { 537 | #if MFBD_MULTICLICK_STATE_AUTO_RESET 538 | /* if multiclick_state is not 0 and less than max_multiclick_state, inc multiclick_state */ 539 | if (((MFBD_MULTICLICK_TIME_IN_FUC) != 0) 540 | && (MFBD_BTN_IN_FUC->multiclick_state < MFBD_BTN_INFO_IN_FUC->max_multiclick_state) 541 | #if (MFBD_MBTN_CONTINUE_LONG_COUNT==0) 542 | && (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 543 | #endif /* (MFBD_MBTN_CONTINUE_LONG_COUNT==0) */ 544 | ) 545 | { 546 | MFBD_BTN_IN_FUC->multiclick_state++; 547 | MFBD_BTN_IN_FUC->multiclick_count = 0; 548 | } 549 | #else 550 | /* if multiclick_state is not 0 and less than max_multiclick_state, inc multiclick_state */ 551 | if (((MFBD_MULTICLICK_TIME_IN_FUC) != 0) 552 | #if (MFBD_MBTN_CONTINUE_LONG_COUNT==0) 553 | && (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 554 | #endif /* (MFBD_MBTN_CONTINUE_LONG_COUNT==0) */ 555 | ) 556 | { 557 | if (MFBD_BTN_IN_FUC->multiclick_state < MFBD_BTN_INFO_IN_FUC->max_multiclick_state) 558 | { 559 | MFBD_BTN_IN_FUC->multiclick_state++; 560 | } 561 | MFBD_BTN_IN_FUC->multiclick_count = 0; 562 | } 563 | #endif /* MFBD_MULTICLICK_STATE_AUTO_RESET */ 564 | else 565 | { 566 | /* over max multi-click times or (long event and repeat event) happened, reset to 0. */ 567 | MFBD_BTN_IN_FUC->multiclick_state = 0; 568 | } 569 | if (MFBD_BTN_INFO_IN_FUC->btn_up_code > 0) 570 | { 571 | _pbtn_group->btn_value_report(MFBD_BTN_INFO_IN_FUC->btn_up_code); 572 | } 573 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 574 | } 575 | else 576 | { 577 | if (MFBD_BTN_IN_FUC->multiclick_state != 0) 578 | { 579 | MFBD_BTN_IN_FUC->multiclick_count++; 580 | if (MFBD_BTN_IN_FUC->multiclick_count >= (MFBD_MULTICLICK_TIME_IN_FUC)) 581 | { 582 | MFBD_BTN_IN_FUC->multiclick_state = 0; 583 | } 584 | } 585 | } 586 | } 587 | else 588 | { 589 | if (MFBD_BTN_IN_FUC->filter_count > (MFBD_FILTER_TIME_IN_FUC)) 590 | { 591 | MFBD_BTN_IN_FUC->filter_count = (MFBD_FILTER_TIME_IN_FUC); 592 | } 593 | else if (MFBD_BTN_IN_FUC->filter_count != 0) 594 | { 595 | MFBD_BTN_IN_FUC->filter_count--; 596 | } 597 | } 598 | } 599 | 600 | _pbtn_info++; 601 | } 602 | } 603 | 604 | /** 605 | * @brief skip some times of mfbd_btn_count_t with last state. 606 | * 607 | * @param _pbtn_group is a pointer of mfbd_group_t. 608 | * @param times is times need to skip. 609 | * 610 | * @return None. 611 | */ 612 | void mfbd_mbtn_skip(const mfbd_group_t *_pbtn_group, const mfbd_mbtn_info_t *_pbtn_info_start, const mfbd_mbtn_info_t *_pbtn_info_end, mfbd_btn_count_t times) 613 | { 614 | const mfbd_mbtn_info_t *_pbtn_info = _pbtn_info_start; 615 | while (1) 616 | { 617 | if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_UP) 618 | { 619 | if (MFBD_BTN_IN_FUC->multiclick_state != 0) 620 | { 621 | if (MFBD_BTN_IN_FUC->multiclick_count < (MFBD_MULTICLICK_TIME_IN_FUC)) 622 | { 623 | if (((MFBD_MULTICLICK_TIME_IN_FUC) - MFBD_BTN_IN_FUC->multiclick_count) > times) 624 | { 625 | MFBD_BTN_IN_FUC->multiclick_count = MFBD_BTN_IN_FUC->multiclick_count + times; 626 | } 627 | else 628 | { 629 | MFBD_BTN_IN_FUC->multiclick_state = 0; 630 | } 631 | } 632 | } 633 | } 634 | #if MFBD_MBTN_CONTINUE_LONG_COUNT 635 | #if MFBD_MBTN_MULTICLICK_LONG_EVT 636 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 637 | { 638 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 639 | { 640 | if (((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 641 | { 642 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 643 | } 644 | else 645 | { 646 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 647 | } 648 | } 649 | } 650 | else 651 | { 652 | /* MFBD_BTN_STATE_LONG, if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) */ 653 | if ((MFBD_BTN_IN_FUC->repeat_count > 0) && (MFBD_BTN_IN_FUC->repeat_count < (MFBD_REPEAT_TIME_IN_FUC))) 654 | { 655 | if (((MFBD_REPEAT_TIME_IN_FUC) - MFBD_BTN_IN_FUC->repeat_count) > times) 656 | { 657 | MFBD_BTN_IN_FUC->repeat_count = MFBD_BTN_IN_FUC->repeat_count + times; 658 | } 659 | else 660 | { 661 | MFBD_BTN_IN_FUC->repeat_count = MFBD_REPEAT_TIME_IN_FUC; 662 | } 663 | } 664 | } 665 | #else 666 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 667 | { 668 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 669 | { 670 | /* if long_time is 0 or long_code is 0, disable long and repeat check. */ 671 | if (((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 672 | { 673 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 674 | } 675 | else 676 | { 677 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 678 | } 679 | } 680 | } 681 | else 682 | { 683 | /* MFBD_BTN_STATE_LONG, if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) */ 684 | /* we don't support repeat event here.*/ 685 | } 686 | #endif /* MFBD_MBTN_MULTICLICK_LONG_EVT */ 687 | #else 688 | else if (MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_DOWN) 689 | { 690 | if ((MFBD_BTN_IN_FUC->long_count > 0) && (MFBD_BTN_IN_FUC->long_count < (MFBD_LONG_TIME_IN_FUC))) 691 | { 692 | if (((MFBD_LONG_TIME_IN_FUC) - MFBD_BTN_IN_FUC->long_count) > times) 693 | { 694 | MFBD_BTN_IN_FUC->long_count = MFBD_BTN_IN_FUC->long_count + times; 695 | } 696 | else 697 | { 698 | MFBD_BTN_IN_FUC->long_count = MFBD_LONG_TIME_IN_FUC; 699 | } 700 | } 701 | } 702 | else 703 | { 704 | /* MFBD_BTN_STATE_LONG, if(MFBD_BTN_IN_FUC->state == MFBD_BTN_STATE_LONG) */ 705 | if ((MFBD_BTN_IN_FUC->repeat_count > 0) && (MFBD_BTN_IN_FUC->repeat_count < (MFBD_REPEAT_TIME_IN_FUC))) 706 | { 707 | if (((MFBD_REPEAT_TIME_IN_FUC) - MFBD_BTN_IN_FUC->repeat_count) > times) 708 | { 709 | MFBD_BTN_IN_FUC->repeat_count = MFBD_BTN_IN_FUC->repeat_count + times; 710 | } 711 | else 712 | { 713 | MFBD_BTN_IN_FUC->repeat_count = MFBD_REPEAT_TIME_IN_FUC; 714 | } 715 | } 716 | } 717 | #endif /* MFBD_MBTN_CONTINUE_LONG_COUNT */ 718 | 719 | _pbtn_info++; 720 | } 721 | } 722 | 723 | /** 724 | * @brief reset all multi-function buttons' params. 725 | * 726 | * @param _pbtn_info_start is a pointer to the start address in flash with type mfbd_mbtn_info_t. 727 | * @param _pbtn_info_end is a pointer to the end address in flash with type mfbd_mbtn_info_t. 728 | * 729 | * @return None. 730 | */ 731 | void mfbd_mbtn_reset(const mfbd_mbtn_info_t *_pbtn_info_start, const mfbd_mbtn_info_t *_pbtn_info_end) 732 | { 733 | const mfbd_mbtn_info_t *_pbtn_info = _pbtn_info_start; 734 | while (1) 735 | { 736 | if (_pbtn_info_end <= _pbtn_info) 737 | { 738 | break; 739 | } 740 | MFBD_BTN_IN_FUC->filter_count = 0; 741 | MFBD_BTN_IN_FUC->long_count = 0; 742 | MFBD_BTN_IN_FUC->multiclick_count = 0; 743 | MFBD_BTN_IN_FUC->multiclick_state = 0; 744 | MFBD_BTN_IN_FUC->repeat_count = 0; 745 | MFBD_BTN_IN_FUC->state = MFBD_BTN_STATE_UP; 746 | 747 | _pbtn_info++; 748 | } 749 | } 750 | 751 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 752 | 753 | #endif /* MFBD_USE_SECTION_DEFINITION */ 754 | -------------------------------------------------------------------------------- /mfbd_sd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, smartmx 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2023-07-03 smartmx the first version, Multi-Function Button Dectection with Section Definition. 9 | * 2023-07-15 smartmx add skip function, to reduce calling of scan functions. 10 | * 2023-09-19 smartmx improve performance, add MFBD_BTN_STATE_SKIP. 11 | * 12 | */ 13 | 14 | #ifndef _MFBD_SD_H_ 15 | #define _MFBD_SD_H_ 16 | 17 | #include "mfbd_cfg.h" 18 | 19 | #if MFBD_USE_SECTION_DEFINITION 20 | 21 | typedef enum 22 | { 23 | MFBD_BTN_STATE_UP = 0, 24 | MFBD_BTN_STATE_DOWN, 25 | MFBD_BTN_STATE_LONG, 26 | MFBD_BTN_STATE_SKIP = 0xff, 27 | } MFBD_BTN_STATE_t; 28 | 29 | #define MFBD_DOWN_CODE_NAME(NAME) NAME##_DOWN_CODE /* when using tbtn/nbtn default define api, this is down-code name. */ 30 | #define MFBD_UP_CODE_NAME(NAME) NAME##_UP_CODE /* when using tbtn/nbtn/mbtn default define api, this is up-code name. */ 31 | #define MFBD_LONG_CODE_NAME(NAME) NAME##_LONG_CODE /* when using nbtn/mbtn default define api, this is long-code name. */ 32 | #define MFBD_DOWN_CODES_NAME(NAME) NAME##_DOWN_CODES /* when using mbtn default define api, this is down-codes name. */ 33 | 34 | #if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM Compiler */ 35 | #define __MFBD_SECTION(x) __attribute__((section(x))) 36 | #define MFBD_USED __attribute__((used)) 37 | #define _MFBD_SECTION_START(X) X##$$Base 38 | #define _MFBD_SECTION_END(X) X##$$Limit 39 | #elif defined (__IAR_SYSTEMS_ICC__) /* IAR Compiler */ 40 | #define __MFBD_SECTION(x) @ x 41 | #define MFBD_USED __root 42 | #define _MFBD_SECTION_START(X) __section_begin(#X) 43 | #define _MFBD_SECTION_END(X) __section_end(#X) 44 | #elif defined (__GNUC__) /* GNU GCC Compiler */ 45 | #define __MFBD_SECTION(x) __attribute__((section(x))) 46 | #define MFBD_USED __attribute__((used)) 47 | #define _MFBD_SECTION_START(X) X##_start 48 | #define _MFBD_SECTION_END(X) X##_end 49 | #else 50 | #error "not supported tool chain..." 51 | #endif 52 | 53 | #define _MFBD_SECTION(X) __MFBD_SECTION(#X) 54 | #define MFBD_SECTION(GROUP, BTN_KIND) _MFBD_SECTION(GROUP##_##BTN_KIND) 55 | 56 | #define MFBD_SECTION_START(GROUP, BTN_KIND) _MFBD_SECTION_START(GROUP##_##BTN_KIND) 57 | #define MFBD_SECTION_END(GROUP, BTN_KIND) _MFBD_SECTION_END(GROUP##_##BTN_KIND) 58 | 59 | 60 | /* tiny button definitions, tiny button functions only support down and up event. */ 61 | typedef struct _mfbd_tiny_btn_struct 62 | { 63 | mfbd_btn_count_t filter_count; /* filter time count when button state changed. */ 64 | unsigned char state; /* the state of button, up or down. */ 65 | } mfbd_tbtn_t; 66 | 67 | #if MFBD_PARAMS_SAME_IN_GROUP 68 | 69 | typedef struct _mfbd_tbtn_info_struct 70 | { 71 | mfbd_tbtn_t *btn; /* a pointer to mfbd_tbtn_t. */ 72 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 73 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 74 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 75 | } mfbd_tbtn_info_t; 76 | 77 | #else 78 | 79 | typedef struct _mfbd_tbtn_info_struct 80 | { 81 | mfbd_tbtn_t *btn; /* a pointer to mfbd_tbtn_t. */ 82 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 83 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 84 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 85 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 86 | } mfbd_tbtn_info_t; 87 | 88 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 89 | 90 | #if MFBD_PARAMS_SAME_IN_GROUP 91 | 92 | #define MFBD_TBTN_DEFINE(GROUP, NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE) \ 93 | MFBD_USED mfbd_tbtn_t NAME = { \ 94 | 0, \ 95 | 0, \ 96 | }; \ 97 | MFBD_USED static const mfbd_tbtn_info_t NAME##_info MFBD_SECTION(GROUP, tbtn)= { \ 98 | &NAME, \ 99 | BTN_DOWN_CODE, \ 100 | BTN_UP_CODE, \ 101 | BTN_INDEX, \ 102 | } 103 | 104 | #define MFBD_TBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX) \ 105 | MFBD_USED mfbd_tbtn_t NAME = { \ 106 | 0, \ 107 | 0, \ 108 | }; \ 109 | MFBD_USED static const mfbd_tbtn_info_t NAME##_info MFBD_SECTION(GROUP, tbtn)= { \ 110 | &NAME, \ 111 | NAME##_DOWN_CODE, \ 112 | NAME##_UP_CODE, \ 113 | BTN_INDEX, \ 114 | } 115 | 116 | #else 117 | 118 | #define MFBD_TBTN_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, BTN_DOWN_CODE, BTN_UP_CODE) \ 119 | MFBD_USED mfbd_tbtn_t NAME = { \ 120 | 0, \ 121 | 0, \ 122 | }; \ 123 | MFBD_USED static const mfbd_tbtn_info_t NAME##_info MFBD_SECTION(GROUP, tbtn)= { \ 124 | &NAME, \ 125 | BTN_DOWN_CODE, \ 126 | BTN_UP_CODE, \ 127 | FILTER_TIME, \ 128 | BTN_INDEX, \ 129 | } 130 | 131 | #define MFBD_TBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME) \ 132 | MFBD_USED mfbd_tbtn_t NAME = { \ 133 | 0, \ 134 | 0, \ 135 | }; \ 136 | MFBD_USED static const mfbd_tbtn_info_t NAME##_info MFBD_SECTION(GROUP, tbtn)= { \ 137 | &NAME, \ 138 | NAME##_DOWN_CODE, \ 139 | NAME##_UP_CODE, \ 140 | FILTER_TIME, \ 141 | BTN_INDEX, \ 142 | } 143 | 144 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 145 | 146 | #define MFBD_TBTN_EXTERN(NAME) extern mfbd_tbtn_t NAME 147 | 148 | 149 | /* normal button definitions, normal button functions support down, up and long-press event. */ 150 | typedef struct _mfbd_normal_btn_struct 151 | { 152 | mfbd_btn_count_t filter_count; /* filter time count when button state changed. */ 153 | mfbd_btn_count_t long_count; /* long time count when button still down. */ 154 | mfbd_btn_count_t repeat_count; /* repeat time count when button still down. */ 155 | unsigned char state; /* the state of button, up or down. */ 156 | } mfbd_nbtn_t; 157 | 158 | #if MFBD_PARAMS_SAME_IN_GROUP 159 | 160 | typedef struct _mfbd_nbtn_info_struct 161 | { 162 | mfbd_nbtn_t *btn; /* a pointer to mfbd_nbtn_t. */ 163 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 164 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 165 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code instead. */ 166 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 167 | } mfbd_nbtn_info_t; 168 | 169 | #else 170 | 171 | typedef struct _mfbd_nbtn_info_struct 172 | { 173 | mfbd_nbtn_t *btn; /* a pointer to mfbd_nbtn_t. */ 174 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 175 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 176 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 177 | mfbd_btn_code_t btn_down_code; /* keyCode when button down, set to 0 will not report it. */ 178 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 179 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code instead. */ 180 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 181 | } mfbd_nbtn_info_t; 182 | 183 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 184 | 185 | 186 | #if MFBD_PARAMS_SAME_IN_GROUP 187 | 188 | #define MFBD_NBTN_DEFINE(GROUP, NAME, BTN_INDEX, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) \ 189 | MFBD_USED mfbd_nbtn_t NAME = { \ 190 | 0, \ 191 | 0, \ 192 | 0, \ 193 | 0, \ 194 | }; \ 195 | MFBD_USED static const mfbd_nbtn_info_t NAME##_info MFBD_SECTION(GROUP, nbtn)= { \ 196 | &NAME, \ 197 | BTN_DOWN_CODE, \ 198 | BTN_UP_CODE, \ 199 | BTN_LONG_CODE, \ 200 | BTN_INDEX, \ 201 | } 202 | 203 | #define MFBD_NBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX) \ 204 | mfbd_nbtn_t NAME = { \ 205 | 0, \ 206 | 0, \ 207 | 0, \ 208 | 0, \ 209 | }; \ 210 | MFBD_USED static const mfbd_nbtn_info_t NAME##_info MFBD_SECTION(GROUP, nbtn)= { \ 211 | &NAME, \ 212 | NAME##_DOWN_CODE, \ 213 | NAME##_UP_CODE, \ 214 | NAME##_LONG_CODE, \ 215 | BTN_INDEX, \ 216 | } 217 | 218 | #else 219 | 220 | #define MFBD_NBTN_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE) \ 221 | mfbd_nbtn_t NAME = { \ 222 | 0, \ 223 | 0, \ 224 | 0, \ 225 | 0, \ 226 | }; \ 227 | MFBD_USED static const mfbd_nbtn_info_t NAME##_info MFBD_SECTION(GROUP, nbtn)= { \ 228 | &NAME, \ 229 | FILTER_TIME, \ 230 | REPEAT_TIME, \ 231 | LONG_TIME, \ 232 | BTN_DOWN_CODE, \ 233 | BTN_UP_CODE, \ 234 | BTN_LONG_CODE, \ 235 | BTN_INDEX, \ 236 | } 237 | 238 | #define MFBD_NBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME) \ 239 | mfbd_nbtn_t NAME = { \ 240 | 0, \ 241 | 0, \ 242 | 0, \ 243 | 0, \ 244 | }; \ 245 | MFBD_USED static const mfbd_nbtn_info_t NAME##_info MFBD_SECTION(GROUP, nbtn)= { \ 246 | &NAME, \ 247 | FILTER_TIME, \ 248 | REPEAT_TIME, \ 249 | LONG_TIME, \ 250 | NAME##_DOWN_CODE, \ 251 | NAME##_UP_CODE, \ 252 | NAME##_LONG_CODE, \ 253 | BTN_INDEX, \ 254 | } 255 | 256 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 257 | 258 | #define MFBD_NBTN_EXTERN(NAME) extern mfbd_nbtn_t NAME 259 | 260 | 261 | /* multi-function button definitions, multi-function button functions support down, up, long-press and multi-click event. */ 262 | 263 | /* 264 | * @Note: 265 | * repeat_count and long_count are conflict to multi-click. 266 | * repeat_count and long_count only check in the first button down event, and will disable in next multi-click event. 267 | * also, if repeat_count and long_count event has happened in the first down event, it will reset multiclick_state. 268 | */ 269 | typedef struct _mfbd_multifuction_btn_struct 270 | { 271 | mfbd_btn_count_t filter_count; /* filter time count when button state changed. */ 272 | mfbd_btn_count_t long_count; /* long time count when button still down. */ 273 | mfbd_btn_count_t repeat_count; /* repeat time count when button still down. */ 274 | mfbd_btn_count_t multiclick_count; /* multi-click time count when button is up. */ 275 | unsigned char multiclick_state; /* multi-click count when button is in multi-click state. */ 276 | unsigned char state; /* the state of button, up or down. */ 277 | } mfbd_mbtn_t; 278 | 279 | #if MFBD_PARAMS_SAME_IN_GROUP 280 | 281 | typedef struct _mfbd_mbtn_info_struct 282 | { 283 | mfbd_mbtn_t *btn; /* a pointer to mfbd_mbtn_t. */ 284 | const mfbd_btn_code_t *btn_down_code; /* pointer to multi-click keyCodes when button down. */ 285 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 286 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code[0] instead. */ 287 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 288 | unsigned char max_multiclick_state; /* max multiclick states. */ 289 | } mfbd_mbtn_info_t; 290 | 291 | #else 292 | 293 | typedef struct _mfbd_mbtn_info_struct 294 | { 295 | mfbd_mbtn_t *btn; /* a pointer to mfbd_mbtn_t. */ 296 | const mfbd_btn_code_t *btn_down_code; /* pointer to multi-click keyCodes when button down. */ 297 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 298 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 299 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 300 | mfbd_btn_count_t multiclick_time; /* multi-click time when button still up, set 0 will disable multi-click time count. */ 301 | mfbd_btn_code_t btn_up_code; /* keyCode when button up, set to 0 will not report it. */ 302 | mfbd_btn_code_t btn_long_code; /* keyCode when button down for long_time, set 0 will not report it ,but report btn_down_code[0] instead. */ 303 | mfbd_btn_index_t btn_index; /* parameter when calling is_btn_down_func. */ 304 | unsigned char max_multiclick_state; /* max multiclick states. */ 305 | } mfbd_mbtn_info_t; 306 | 307 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 308 | 309 | #if MFBD_PARAMS_SAME_IN_GROUP 310 | 311 | #define MFBD_MBTN_DEFINE(GROUP, NAME, BTN_INDEX, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) \ 312 | static const mfbd_btn_code_t NAME##_down_codes[MAX_MULTICLICK_STATE + 1] = {BTN_DOWN_CODE, __VA_ARGS__}; \ 313 | mfbd_mbtn_t NAME = { \ 314 | 0, \ 315 | 0, \ 316 | 0, \ 317 | 0, \ 318 | 0, \ 319 | 0, \ 320 | }; \ 321 | MFBD_USED static const mfbd_mbtn_info_t NAME##_info MFBD_SECTION(GROUP, mbtn)= { \ 322 | &NAME, \ 323 | NAME##_down_codes, \ 324 | BTN_UP_CODE, \ 325 | BTN_LONG_CODE, \ 326 | BTN_INDEX, \ 327 | MAX_MULTICLICK_STATE, \ 328 | } 329 | 330 | #define MFBD_MBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, MAX_MULTICLICK_STATE) \ 331 | mfbd_mbtn_t NAME = { \ 332 | 0, \ 333 | 0, \ 334 | 0, \ 335 | 0, \ 336 | 0, \ 337 | 0, \ 338 | }; \ 339 | MFBD_USED static const mfbd_mbtn_info_t NAME##_info MFBD_SECTION(GROUP, mbtn)= { \ 340 | &NAME, \ 341 | NAME##_DOWN_CODES, \ 342 | NAME##_UP_CODE, \ 343 | NAME##_LONG_CODE, \ 344 | BTN_INDEX, \ 345 | MAX_MULTICLICK_STATE, \ 346 | } 347 | 348 | #else 349 | 350 | #define MFBD_MBTN_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE, BTN_DOWN_CODE, BTN_UP_CODE, BTN_LONG_CODE, ...) \ 351 | static const mfbd_btn_code_t NAME##_down_codes[MAX_MULTICLICK_STATE + 1] = {BTN_DOWN_CODE, __VA_ARGS__}; \ 352 | mfbd_mbtn_t NAME = { \ 353 | 0, \ 354 | 0, \ 355 | 0, \ 356 | 0, \ 357 | 0, \ 358 | 0, \ 359 | }; \ 360 | MFBD_USED static const mfbd_mbtn_info_t NAME##_info MFBD_SECTION(GROUP, mbtn)= { \ 361 | &NAME, \ 362 | NAME##_down_codes, \ 363 | FILTER_TIME, \ 364 | REPEAT_TIME, \ 365 | LONG_TIME, \ 366 | MULTICLICK_TIME, \ 367 | BTN_UP_CODE, \ 368 | BTN_LONG_CODE, \ 369 | BTN_INDEX, \ 370 | MAX_MULTICLICK_STATE, \ 371 | } 372 | 373 | #define MFBD_MBTN_DEFAULT_DEFINE(GROUP, NAME, BTN_INDEX, FILTER_TIME, REPEAT_TIME, LONG_TIME, MULTICLICK_TIME, MAX_MULTICLICK_STATE) \ 374 | mfbd_mbtn_t NAME = { \ 375 | 0, \ 376 | 0, \ 377 | 0, \ 378 | 0, \ 379 | 0, \ 380 | 0, \ 381 | }; \ 382 | MFBD_USED static const mfbd_mbtn_info_t NAME##_info MFBD_SECTION(GROUP, mbtn)= { \ 383 | &NAME, \ 384 | NAME##_DOWN_CODES, \ 385 | FILTER_TIME, \ 386 | REPEAT_TIME, \ 387 | LONG_TIME, \ 388 | MULTICLICK_TIME, \ 389 | NAME##_UP_CODE, \ 390 | NAME##_LONG_CODE, \ 391 | BTN_INDEX, \ 392 | MAX_MULTICLICK_STATE, \ 393 | } 394 | 395 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 396 | 397 | #define MFBD_MBTN_EXTERN(NAME) extern mfbd_mbtn_t NAME 398 | 399 | 400 | /* mfbd group struct */ 401 | typedef struct _mfbd_group_struct 402 | { 403 | /* used to read whether button is down. */ 404 | unsigned char (*is_btn_down_func)(mfbd_btn_index_t btn_index); 405 | 406 | /* used to report btn_value, must have a legal value, must not be NULL. */ 407 | void (*btn_value_report)(mfbd_btn_code_t btn_value); 408 | 409 | /* if set MFBD_PARAMS_SAME_IN_GROUP to 1, all btns in group has same params. */ 410 | #if MFBD_PARAMS_SAME_IN_GROUP 411 | 412 | #if MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 413 | mfbd_btn_count_t filter_time; /* filter time when button state changed, please do not use 0. */ 414 | #endif /* MFBD_USE_TINY_BUTTON || MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 415 | 416 | #if MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON 417 | 418 | mfbd_btn_count_t repeat_time; /* repeat time when button still down for over long_time, set 0 will disable repeat time count. */ 419 | 420 | mfbd_btn_count_t long_time; /* long time when button still down, set 0 will disable long time and repeat time count. */ 421 | 422 | #endif /* MFBD_USE_NORMAL_BUTTON || MFBD_USE_MULTIFUCNTION_BUTTON */ 423 | 424 | #if MFBD_USE_MULTIFUCNTION_BUTTON 425 | 426 | mfbd_btn_count_t multiclick_time; /* multi-click time when button still up, set 0 will disable multi-click time count. */ 427 | 428 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 429 | 430 | #endif /* MFBD_PARAMS_SAME_IN_GROUP */ 431 | 432 | #if MFBD_USE_BTN_SCAN_PRE_FUNC 433 | /* prepare function when start to scan buttons for each group. */ 434 | void (*btn_scan_prepare)(void); 435 | #endif /* MFBD_USE_BTN_SCAN_PRE_FUNC */ 436 | 437 | #if MFBD_USE_BTN_SCAN_AFTER_FUNC 438 | /* function after scanning buttons for each group. */ 439 | void (*btn_scan_after)(void); 440 | #endif /* MFBD_USE_BTN_SCAN_AFTER_FUNC */ 441 | 442 | } mfbd_group_t; 443 | 444 | #define MFBD_GROUP_NAME(GROUP) mfbd_group_##GROUP 445 | #define MFBD_GROUP_EXTERN(GROUP) extern const mfbd_group_t MFBD_GROUP_NAME(GROUP) 446 | 447 | #define MFBD_GROUP_DEFINE(GROUP, IS_BTN_DOWN_FUNC, BTN_VALUE_REPORT_FUNC, ...) \ 448 | const mfbd_group_t MFBD_GROUP_NAME(GROUP) = { \ 449 | IS_BTN_DOWN_FUNC, \ 450 | BTN_VALUE_REPORT_FUNC, \ 451 | __VA_ARGS__ \ 452 | } 453 | 454 | extern void mfbd_tbtn_scan(const mfbd_group_t *_pbtn_group, const mfbd_tbtn_info_t *_pbtn_info_start, const mfbd_tbtn_info_t *_pbtn_info_end); 455 | extern void mfbd_tbtn_reset(const mfbd_tbtn_info_t *_pbtn_info_start, const mfbd_tbtn_info_t *_pbtn_info_end); 456 | 457 | extern void mfbd_nbtn_scan(const mfbd_group_t *_pbtn_group, const mfbd_nbtn_info_t *_pbtn_info_start, const mfbd_nbtn_info_t *_pbtn_info_end); 458 | extern void mfbd_nbtn_skip(const mfbd_group_t *_pbtn_group, const mfbd_nbtn_info_t *_pbtn_info_start, const mfbd_nbtn_info_t *_pbtn_info_end, mfbd_btn_count_t times); 459 | extern void mfbd_nbtn_reset(const mfbd_nbtn_info_t *_pbtn_info_start, const mfbd_nbtn_info_t *_pbtn_info_end); 460 | 461 | extern void mfbd_mbtn_scan(const mfbd_group_t *_pbtn_group, const mfbd_mbtn_info_t *_pbtn_info_start, const mfbd_mbtn_info_t *_pbtn_info_end); 462 | extern void mfbd_mbtn_skip(const mfbd_group_t *_pbtn_group, const mfbd_mbtn_info_t *_pbtn_info_start, const mfbd_mbtn_info_t *_pbtn_info_end, mfbd_btn_count_t times); 463 | extern void mfbd_mbtn_reset(const mfbd_mbtn_info_t *_pbtn_info_start, const mfbd_mbtn_info_t *_pbtn_info_end); 464 | 465 | #if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM Compiler */ 466 | 467 | #if MFBD_USE_TINY_BUTTON 468 | #define MFBD_GROUP_SCAN_TBTN(GROUP) \ 469 | do \ 470 | { \ 471 | extern const int MFBD_SECTION_START(GROUP, tbtn); \ 472 | extern const int MFBD_SECTION_END(GROUP, tbtn); \ 473 | mfbd_tbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_tbtn_info_t *)&(MFBD_SECTION_START(GROUP, tbtn)), (const mfbd_tbtn_info_t *)&(MFBD_SECTION_END(GROUP, tbtn))); \ 474 | } while (0) 475 | #define MFBD_GROUP_RESET_TBTN(GROUP) \ 476 | do \ 477 | { \ 478 | extern const int MFBD_SECTION_START(GROUP, tbtn); \ 479 | extern const int MFBD_SECTION_END(GROUP, tbtn); \ 480 | mfbd_tbtn_reset((const mfbd_tbtn_info_t *)&(MFBD_SECTION_START(GROUP, tbtn)), (const mfbd_tbtn_info_t *)&(MFBD_SECTION_END(GROUP, tbtn))); \ 481 | } while (0) 482 | #else 483 | #define MFBD_GROUP_SCAN_TBTN(GROUP) do{} while(0) 484 | #define MFBD_GROUP_RESET_TBTN(GROUP) do{} while(0) 485 | #endif /* MFBD_USE_TINY_BUTTON */ 486 | 487 | #if MFBD_USE_NORMAL_BUTTON 488 | #define MFBD_GROUP_SCAN_NBTN(GROUP) \ 489 | do \ 490 | { \ 491 | extern const int MFBD_SECTION_START(GROUP, nbtn); \ 492 | extern const int MFBD_SECTION_END(GROUP, nbtn); \ 493 | mfbd_nbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_START(GROUP, nbtn)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_END(GROUP, nbtn))); \ 494 | } while (0) 495 | #define MFBD_GROUP_SKIP_NBTN(GROUP, TIMES) \ 496 | do \ 497 | { \ 498 | extern const int MFBD_SECTION_START(GROUP, nbtn); \ 499 | extern const int MFBD_SECTION_END(GROUP, nbtn); \ 500 | mfbd_nbtn_skip((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_START(GROUP, nbtn)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_END(GROUP, nbtn)), TIMES); \ 501 | } while (0) 502 | #define MFBD_GROUP_RESET_NBTN(GROUP) \ 503 | do \ 504 | { \ 505 | extern const int MFBD_SECTION_START(GROUP, nbtn); \ 506 | extern const int MFBD_SECTION_END(GROUP, nbtn); \ 507 | mfbd_nbtn_reset((const mfbd_nbtn_info_t *)&(MFBD_SECTION_START(GROUP, nbtn)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_END(GROUP, nbtn))); \ 508 | } while (0) 509 | #else 510 | #define MFBD_GROUP_SCAN_NBTN(GROUP) do{} while(0) 511 | #define MFBD_GROUP_SKIP_NBTN(GROUP, TIMES) do{} while(0) 512 | #define MFBD_GROUP_RESET_NBTN(GROUP) do{} while(0) 513 | #endif /* MFBD_USE_NORMAL_BUTTON */ 514 | 515 | #if MFBD_USE_MULTIFUCNTION_BUTTON 516 | #define MFBD_GROUP_SCAN_MBTN(GROUP) \ 517 | do \ 518 | { \ 519 | extern const int MFBD_SECTION_START(GROUP, mbtn); \ 520 | extern const int MFBD_SECTION_END(GROUP, mbtn); \ 521 | mfbd_mbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_START(GROUP, mbtn)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_END(GROUP, mbtn))); \ 522 | } while (0) 523 | #define MFBD_GROUP_SKIP_MBTN(GROUP, TIMES) \ 524 | do \ 525 | { \ 526 | extern const int MFBD_SECTION_START(GROUP, mbtn); \ 527 | extern const int MFBD_SECTION_END(GROUP, mbtn); \ 528 | mfbd_mbtn_skip((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_START(GROUP, mbtn)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_END(GROUP, mbtn)), TIMES); \ 529 | } while (0) 530 | #define MFBD_GROUP_RESET_MBTN(GROUP) \ 531 | do \ 532 | { \ 533 | extern const int MFBD_SECTION_START(GROUP, mbtn); \ 534 | extern const int MFBD_SECTION_END(GROUP, mbtn); \ 535 | mfbd_mbtn_reset((const mfbd_mbtn_info_t *)&(MFBD_SECTION_START(GROUP, mbtn)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_END(GROUP, mbtn))); \ 536 | } while (0) 537 | #else 538 | #define MFBD_GROUP_SCAN_MBTN(GROUP) do{} while(0) 539 | #define MFBD_GROUP_SKIP_MBTN(GROUP, TIMES) do{} while(0) 540 | #define MFBD_GROUP_RESET_MBTN(GROUP) do{} while(0) 541 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 542 | 543 | #elif defined (__IAR_SYSTEMS_ICC__) /* IAR Compiler */ 544 | 545 | #if MFBD_USE_TINY_BUTTON 546 | #define MFBD_GROUP_SCAN_TBTN(GROUP) \ 547 | do \ 548 | { \ 549 | mfbd_tbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_tbtn_info_t *)MFBD_SECTION_START(GROUP, tbtn), (const mfbd_tbtn_info_t *)MFBD_SECTION_END(GROUP, tbtn)); \ 550 | } while (0) 551 | #define MFBD_GROUP_RESET_TBTN(GROUP) \ 552 | do \ 553 | { \ 554 | mfbd_tbtn_reset((const mfbd_tbtn_info_t *)MFBD_SECTION_START(GROUP, nbtn), (const mfbd_tbtn_info_t *)MFBD_SECTION_END(GROUP, nbtn)); \ 555 | } while (0) 556 | #else 557 | #define MFBD_GROUP_SCAN_TBTN(GROUP) do{} while(0) 558 | #endif /* MFBD_USE_TINY_BUTTON */ 559 | 560 | #if MFBD_USE_NORMAL_BUTTON 561 | #define MFBD_GROUP_SCAN_NBTN(GROUP) \ 562 | do \ 563 | { \ 564 | mfbd_nbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_nbtn_info_t *)MFBD_SECTION_START(GROUP, nbtn), (const mfbd_nbtn_info_t *)MFBD_SECTION_END(GROUP, nbtn)); \ 565 | } while (0) 566 | #define MFBD_GROUP_SKIP_NBTN(GROUP, TIMES) \ 567 | do \ 568 | { \ 569 | mfbd_nbtn_skip((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_nbtn_info_t *)MFBD_SECTION_START(GROUP, nbtn), (const mfbd_nbtn_info_t *)MFBD_SECTION_END(GROUP, nbtn), TIMES); \ 570 | } while (0) 571 | #define MFBD_GROUP_RESET_NBTN(GROUP) \ 572 | do \ 573 | { \ 574 | mfbd_nbtn_reset((const mfbd_nbtn_info_t *)MFBD_SECTION_START(GROUP, nbtn), (const mfbd_nbtn_info_t *)MFBD_SECTION_END(GROUP, nbtn)); \ 575 | } while (0) 576 | #else 577 | #define MFBD_GROUP_SCAN_NBTN(GROUP) do{} while(0) 578 | #define MFBD_GROUP_SKIP_NBTN(GROUP, TIMES) do{} while(0) 579 | #define MFBD_GROUP_RESET_NBTN(GROUP) do{} while(0) 580 | #endif /* MFBD_USE_NORMAL_BUTTON */ 581 | 582 | #if MFBD_USE_MULTIFUCNTION_BUTTON 583 | #define MFBD_GROUP_SCAN_MBTN(GROUP) \ 584 | do \ 585 | { \ 586 | mfbd_mbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_mbtn_info_t *)MFBD_SECTION_START(GROUP, mbtn), (const mfbd_mbtn_info_t *)MFBD_SECTION_END(GROUP, mbtn)); \ 587 | } while (0) 588 | #define MFBD_GROUP_SKIP_MBTN(GROUP, TIMES) \ 589 | do \ 590 | { \ 591 | mfbd_mbtn_skip((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_mbtn_info_t *)MFBD_SECTION_START(GROUP, mbtn), (const mfbd_mbtn_info_t *)MFBD_SECTION_END(GROUP, mbtn), TIMES); \ 592 | } while (0) 593 | #define MFBD_GROUP_RESET_MBTN(GROUP) \ 594 | do \ 595 | { \ 596 | mfbd_mbtn_reset((const mfbd_mbtn_info_t *)MFBD_SECTION_START(GROUP, mbtn), (const mfbd_mbtn_info_t *)MFBD_SECTION_END(GROUP, mbtn)); \ 597 | } while (0) 598 | #else 599 | #define MFBD_GROUP_SCAN_MBTN(GROUP) do{} while(0) 600 | #define MFBD_GROUP_SKIP_MBTN(GROUP, TIMES) do{} while(0) 601 | #define MFBD_GROUP_RESET_MBTN(GROUP) do{} while(0) 602 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 603 | 604 | #elif defined (__GNUC__) /* GNU GCC Compiler */ 605 | 606 | #if MFBD_USE_TINY_BUTTON 607 | #define MFBD_GROUP_SCAN_TBTN(GROUP) \ 608 | do \ 609 | { \ 610 | extern const int MFBD_SECTION_START(GROUP, tbtn); \ 611 | extern const int MFBD_SECTION_END(GROUP, tbtn); \ 612 | mfbd_tbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_tbtn_info_t *)&(MFBD_SECTION_START(GROUP, tbtn)), (const mfbd_tbtn_info_t *)&(MFBD_SECTION_END(GROUP, tbtn))); \ 613 | } while (0) 614 | #define MFBD_GROUP_RESET_TBTN(GROUP) \ 615 | do \ 616 | { \ 617 | extern const int MFBD_SECTION_START(GROUP, tbtn); \ 618 | extern const int MFBD_SECTION_END(GROUP, tbtn); \ 619 | mfbd_tbtn_reset((const mfbd_tbtn_info_t *)&(MFBD_SECTION_START(GROUP, tbtn)), (const mfbd_tbtn_info_t *)&(MFBD_SECTION_END(GROUP, tbtn))); \ 620 | } while (0) 621 | #else 622 | #define MFBD_GROUP_SCAN_TBTN(GROUP) do{} while(0) 623 | #define MFBD_GROUP_RESET_TBTN(GROUP) do{} while(0) 624 | #endif /* MFBD_USE_TINY_BUTTON */ 625 | 626 | #if MFBD_USE_NORMAL_BUTTON 627 | #define MFBD_GROUP_SCAN_NBTN(GROUP) \ 628 | do \ 629 | { \ 630 | extern const int MFBD_SECTION_START(GROUP, nbtn); \ 631 | extern const int MFBD_SECTION_END(GROUP, nbtn); \ 632 | mfbd_nbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_START(GROUP, nbtn)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_END(GROUP, nbtn))); \ 633 | } while (0) 634 | #define MFBD_GROUP_SKIP_NBTN(GROUP, TIMES) \ 635 | do \ 636 | { \ 637 | extern const int MFBD_SECTION_START(GROUP, nbtn); \ 638 | extern const int MFBD_SECTION_END(GROUP, nbtn); \ 639 | mfbd_nbtn_skip((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_START(GROUP, nbtn)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_END(GROUP, nbtn)), TIMES); \ 640 | } while (0) 641 | #define MFBD_GROUP_RESET_NBTN(GROUP) \ 642 | do \ 643 | { \ 644 | extern const int MFBD_SECTION_START(GROUP, nbtn); \ 645 | extern const int MFBD_SECTION_END(GROUP, nbtn); \ 646 | mfbd_nbtn_reset((const mfbd_nbtn_info_t *)&(MFBD_SECTION_START(GROUP, nbtn)), (const mfbd_nbtn_info_t *)&(MFBD_SECTION_END(GROUP, nbtn))); \ 647 | } while (0) 648 | #else 649 | #define MFBD_GROUP_SCAN_NBTN(GROUP) do{} while(0) 650 | #define MFBD_GROUP_SKIP_NBTN(GROUP, TIMES) do{} while(0) 651 | #define MFBD_GROUP_RESET_NBTN(GROUP) do{} while(0) 652 | #endif /* MFBD_USE_NORMAL_BUTTON */ 653 | 654 | #if MFBD_USE_MULTIFUCNTION_BUTTON 655 | #define MFBD_GROUP_SCAN_MBTN(GROUP) \ 656 | do \ 657 | { \ 658 | extern const int MFBD_SECTION_START(GROUP, mbtn); \ 659 | extern const int MFBD_SECTION_END(GROUP, mbtn); \ 660 | mfbd_mbtn_scan((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_START(GROUP, mbtn)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_END(GROUP, mbtn))); \ 661 | } while (0) 662 | #define MFBD_GROUP_SKIP_MBTN(GROUP, TIMES) \ 663 | do \ 664 | { \ 665 | extern const int MFBD_SECTION_START(GROUP, mbtn); \ 666 | extern const int MFBD_SECTION_END(GROUP, mbtn); \ 667 | mfbd_mbtn_skip((const mfbd_group_t *)&(MFBD_GROUP_NAME(GROUP)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_START(GROUP, mbtn)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_END(GROUP, mbtn)), TIMES); \ 668 | } while (0) 669 | #define MFBD_GROUP_RESET_MBTN(GROUP) \ 670 | do \ 671 | { \ 672 | extern const int MFBD_SECTION_START(GROUP, mbtn); \ 673 | extern const int MFBD_SECTION_END(GROUP, mbtn); \ 674 | mfbd_mbtn_reset((const mfbd_mbtn_info_t *)&(MFBD_SECTION_START(GROUP, mbtn)), (const mfbd_mbtn_info_t *)&(MFBD_SECTION_END(GROUP, mbtn))); \ 675 | } while (0) 676 | #else 677 | #define MFBD_GROUP_SCAN_MBTN(GROUP) do{} while(0) 678 | #define MFBD_GROUP_SKIP_MBTN(GROUP, TIMES) do{} while(0) 679 | #define MFBD_GROUP_RESET_MBTN(GROUP) do{} while(0) 680 | #endif /* MFBD_USE_MULTIFUCNTION_BUTTON */ 681 | 682 | #else 683 | #error "not supported tool chain..." 684 | #endif 685 | 686 | #if MFBD_USE_BTN_SCAN_PRE_FUNC 687 | #define MFBD_GROUP_SCAN_PREPARE(GROUP) \ 688 | do \ 689 | { \ 690 | if(MFBD_GROUP_NAME(GROUP).btn_scan_prepare!= NULL) \ 691 | { \ 692 | MFBD_GROUP_NAME(GROUP).btn_scan_prepare(); \ 693 | } \ 694 | } while(0) 695 | #else 696 | #define MFBD_GROUP_SCAN_PREPARE(GROUP) do{} while(0) 697 | #endif /* MFBD_USE_BTN_SCAN_PRE_FUNC */ 698 | 699 | #if MFBD_USE_BTN_SCAN_AFTER_FUNC 700 | #define MFBD_GROUP_SCAN_AFTER(GROUP) \ 701 | do \ 702 | { \ 703 | if(MFBD_GROUP_NAME(GROUP).btn_scan_after!= NULL) \ 704 | { \ 705 | MFBD_GROUP_NAME(GROUP).btn_scan_after(); \ 706 | } \ 707 | } while(0) 708 | #else 709 | #define MFBD_GROUP_SCAN_AFTER(GROUP) do{} while(0) 710 | #endif /* MFBD_USE_BTN_SCAN_AFTER_FUNC */ 711 | 712 | /* 713 | * @Note: 714 | * this in a example for how to scan or reset the mfbd group, 715 | * if some group has not all btn types, you should write code by yourself. 716 | */ 717 | #define MFBD_GROUP_SCAN(GROUP) \ 718 | do \ 719 | { \ 720 | MFBD_GROUP_SCAN_PREPARE(GROUP); \ 721 | MFBD_GROUP_SCAN_TBTN(GROUP); \ 722 | MFBD_GROUP_SCAN_NBTN(GROUP); \ 723 | MFBD_GROUP_SCAN_MBTN(GROUP); \ 724 | MFBD_GROUP_SCAN_AFTER(GROUP); \ 725 | } while (0) 726 | 727 | #define MFBD_GROUP_SKIP(GROUP, TIMES) \ 728 | do \ 729 | { \ 730 | MFBD_GROUP_SKIP_NBTN(GROUP, TIMES); \ 731 | MFBD_GROUP_SKIP_MBTN(GROUP, TIMES); \ 732 | } while (0) 733 | 734 | #define MFBD_GROUP_RESET(GROUP) \ 735 | do \ 736 | { \ 737 | MFBD_GROUP_RESET_TBTN(GROUP); \ 738 | MFBD_GROUP_RESET_NBTN(GROUP); \ 739 | MFBD_GROUP_RESET_MBTN(GROUP); \ 740 | } while (0) 741 | 742 | #endif /* MFBD_USE_SECTION_DEFINITION */ 743 | 744 | #endif /* _MFBD_SD_H_ */ 745 | --------------------------------------------------------------------------------