multi_button.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * @File: multi_button.c
  3. * @Author: Zibin Zheng
  4. * @Date: 2018-01-23 20:36:01
  5. *
  6. * @LICENSE: Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
  7. * All rights reserved.
  8. *
  9. * @NOTE: The original author of MultiButton is Zibin Zheng.
  10. * Please contact the original author for authorization
  11. * before use.I(liu2guang) only adapt the library to
  12. * rt-thread and fix some bugs. I(liu2guang) am not
  13. * responsible for the authorization of the library.
  14. *
  15. * Change Logs:
  16. * Date Author Notes
  17. * 2018-01-23 liu2guang Adapter rtthread and Fix the bug.
  18. */
  19. #include "multi_button.h"
  20. #define EVENT_CB(ev) if(handle->cb[ev]) handle->cb[ev]((void*)handle)
  21. #define PRESS_REPEAT_MAX_NUM 15 /*!< The maximum value of the repeat counter */
  22. static button_t head_handle = NULL;
  23. /**
  24. * @brief Initializes the button struct handle.
  25. * @param handle: the button handle struct.
  26. * @param pin_level: read the pin of the connected button level.
  27. * @param active_level: pin pressed level.
  28. * @retval None
  29. */
  30. void button_init(button_t handle, uint8_t(*pin_level)(void), uint8_t active_level)
  31. {
  32. memset(handle, 0, sizeof(struct button));
  33. handle->event = (uint8_t)NONE_PRESS;
  34. handle->hal_button_Level = pin_level;
  35. handle->button_level = !active_level;
  36. handle->active_level = active_level;
  37. handle->short_ticks = SHORT_TICKS;
  38. handle->long_ticks = LONG_TICKS;
  39. }
  40. /**
  41. * @brief Attach the button event callback function.
  42. * @param handle: the button handle struct.
  43. * @param event: trigger event type.
  44. * @param cb: callback function.
  45. * @retval None
  46. */
  47. void button_attach(button_t handle, PressEvent event, BtnCallback cb)
  48. {
  49. handle->cb[event] = cb;
  50. }
  51. /**
  52. * @brief Attach the button adjust ticks
  53. * @param handle: the button handle strcut.
  54. * @param ticks: judge short ticks(unit:ms)
  55. * @retval None
  56. */
  57. void button_set_short_ticks(button_t handle, uint16_t ticks)
  58. {
  59. handle->short_ticks = ticks / TICKS_INTERVAL;
  60. }
  61. /**
  62. * @brief Attach the button adjust long ticks
  63. * @param handle: the button handle strcut.
  64. * @param ticks: judge long ticks(unit:ms)
  65. * @retval None
  66. */
  67. void button_set_long_ticks(button_t handle, uint16_t ticks)
  68. {
  69. handle->long_ticks = ticks / TICKS_INTERVAL;
  70. }
  71. /**
  72. * @brief Inquire the button event happen.
  73. * @param handle: the button handle struct.
  74. * @retval button event.
  75. */
  76. PressEvent get_button_event(button_t handle)
  77. {
  78. return (PressEvent)(handle->event);
  79. }
  80. /**
  81. * @brief button driver core function, driver state machine.
  82. * @param handle: the button handle struct.
  83. * @retval None
  84. */
  85. static void button_handler(button_t handle)
  86. {
  87. uint8_t read_gpio_level = handle->hal_button_Level();
  88. //ticks counter working..
  89. if((handle->state) > 0)
  90. {
  91. handle->ticks++;
  92. }
  93. /*------------button debounce handle---------------*/
  94. if(read_gpio_level != handle->button_level)
  95. {
  96. //not equal to prev one
  97. //continue read 3 times same new level change
  98. if(++(handle->debounce_cnt) >= DEBOUNCE_TICKS)
  99. {
  100. handle->button_level = read_gpio_level;
  101. handle->debounce_cnt = 0;
  102. }
  103. }
  104. else
  105. {
  106. // level not change ,counter reset.
  107. handle->debounce_cnt = 0;
  108. }
  109. /*-----------------State machine-------------------*/
  110. switch (handle->state)
  111. {
  112. case 0:
  113. if(handle->button_level == handle->active_level)
  114. {
  115. handle->event = (uint8_t)PRESS_DOWN;
  116. EVENT_CB(PRESS_DOWN);
  117. handle->ticks = 0;
  118. handle->repeat = 1;
  119. handle->state = 1;
  120. }
  121. else
  122. {
  123. handle->event = (uint8_t)NONE_PRESS;
  124. }
  125. break;
  126. case 1:
  127. if(handle->button_level != handle->active_level)
  128. {
  129. handle->event = (uint8_t)PRESS_UP;
  130. EVENT_CB(PRESS_UP);
  131. handle->ticks = 0;
  132. handle->state = 2;
  133. }
  134. else if(handle->ticks > handle->long_ticks)
  135. {
  136. handle->event = (uint8_t)LONG_PRESS_START;
  137. EVENT_CB(LONG_PRESS_START);
  138. handle->state = 5;
  139. }
  140. break;
  141. case 2:
  142. if(handle->button_level == handle->active_level)
  143. {
  144. handle->event = (uint8_t)PRESS_DOWN;
  145. EVENT_CB(PRESS_DOWN);
  146. if(handle->repeat != PRESS_REPEAT_MAX_NUM)
  147. {
  148. handle->repeat++;
  149. }
  150. EVENT_CB(PRESS_REPEAT);
  151. handle->ticks = 0;
  152. handle->state = 3;
  153. }
  154. else if(handle->ticks > handle->short_ticks)
  155. {
  156. if(handle->repeat == 1)
  157. {
  158. handle->event = (uint8_t)SINGLE_CLICK;
  159. EVENT_CB(SINGLE_CLICK);
  160. }
  161. else if(handle->repeat == 2)
  162. {
  163. handle->event = (uint8_t)DOUBLE_CLICK;
  164. EVENT_CB(DOUBLE_CLICK);
  165. }
  166. handle->state = 0;
  167. }
  168. break;
  169. case 3:
  170. if(handle->button_level != handle->active_level)
  171. {
  172. handle->event = (uint8_t)PRESS_UP;
  173. EVENT_CB(PRESS_UP);
  174. if(handle->ticks < handle->short_ticks)
  175. {
  176. handle->ticks = 0;
  177. handle->state = 2;
  178. }
  179. else
  180. {
  181. handle->state = 0;
  182. }
  183. }
  184. else if(handle->ticks > handle->short_ticks) // SHORT_TICKS < press down hold time < LONG_TICKS
  185. {
  186. handle->state = 1;
  187. }
  188. break;
  189. case 5:
  190. if(handle->button_level == handle->active_level)
  191. {
  192. handle->event = (uint8_t)LONG_PRESS_HOLD;
  193. if (handle->ticks % LONG_HOLD_CYC == 0)
  194. {
  195. EVENT_CB(LONG_PRESS_HOLD);
  196. }
  197. }
  198. else
  199. {
  200. handle->event = (uint8_t)PRESS_UP;
  201. EVENT_CB(PRESS_UP);
  202. handle->state = 0;
  203. }
  204. break;
  205. default:
  206. handle->state = 0; /* reset */
  207. break;
  208. }
  209. }
  210. /**
  211. * @brief Start the button work, add the handle into work list.
  212. * @param handle: target handle struct.
  213. * @retval 0: succeed. -1: already exist.
  214. */
  215. int button_start(button_t handle)
  216. {
  217. button_t target = head_handle;
  218. while(target)
  219. {
  220. if(target == handle)
  221. {
  222. return -1; //already exist.
  223. }
  224. target = target->next;
  225. }
  226. handle->next = head_handle;
  227. head_handle = handle;
  228. return 0;
  229. }
  230. /**
  231. * @brief Stop the button work, remove the handle off work list.
  232. * @param handle: target handle struct.
  233. * @retval None
  234. */
  235. void button_stop(button_t handle)
  236. {
  237. button_t* curr;
  238. for(curr = &head_handle; *curr;)
  239. {
  240. button_t entry = *curr;
  241. if (entry == handle)
  242. {
  243. *curr = entry->next;
  244. return;
  245. }
  246. else
  247. {
  248. curr = &entry->next;
  249. }
  250. }
  251. }
  252. /**
  253. * @brief background ticks, timer repeat invoking interval 5ms.
  254. * @param None.
  255. * @retval None
  256. */
  257. void button_ticks(void)
  258. {
  259. button_t target;
  260. for(target = head_handle; target != NULL; target = target->next)
  261. {
  262. button_handler(target);
  263. }
  264. }