button.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /************************************************************
  2. * @brief button_drive
  3. * @param RT_NULL
  4. * @return RT_NULL
  5. * @author jiejie
  6. * @github https://github.com/jiejieTop
  7. * @date 2018-xx-xx
  8. * @version v1.0.1
  9. * @note button.c
  10. ***********************************************************/
  11. #include "button.h"
  12. #ifdef HUALI_PKG_USING_BUTTON
  13. /*******************************************************************
  14. * Variable Declaration
  15. *******************************************************************/
  16. static struct button* Head_Button = RT_NULL;
  17. /*******************************************************************
  18. * Function Declaration
  19. *******************************************************************/
  20. static char *StrnCopy(char *dst, const char *src, rt_uint32_t n);
  21. static void Print_Btn_Info(Button_t* btn);
  22. static void Add_Button(Button_t* btn);
  23. /************************************************************
  24. * @brief Create a Button
  25. * @param name:button name
  26. * @param btn:button structure
  27. * @param read_btn_level:Button trigger level reading function,
  28. * Return the level of the rt_uint8_t type by yourself
  29. * @param btn_trigger_level:Button trigger level
  30. * @return RT_NULL
  31. * @author jiejie
  32. * @github https://github.com/jiejieTop
  33. * @date 2018-xx-xx
  34. * @version v1.0
  35. * @note RT_NULL
  36. ***********************************************************/
  37. void Button_Create(const char *name,
  38. Button_t *btn,
  39. rt_uint8_t(*read_btn_level)(void),
  40. rt_uint8_t btn_trigger_level)
  41. {
  42. if( btn == RT_NULL)
  43. {
  44. RT_DEBUG_LOG(RT_DEBUG_THREAD,("struct button is RT_NULL!"));
  45. }
  46. memset(btn, 0, sizeof(struct button)); //Clear structure information
  47. StrnCopy(btn->Name, name, BTN_NAME_MAX); //button name
  48. btn->Button_State = NONE_TRIGGER; //Button status
  49. btn->Button_Last_State = NONE_TRIGGER; //Button last status
  50. btn->Button_Trigger_Event = NONE_TRIGGER; //Button trigger event
  51. btn->Read_Button_Level = read_btn_level; //Button trigger level reading function
  52. btn->Button_Trigger_Level = btn_trigger_level; //Button trigger level
  53. btn->Button_Last_Level = btn->Read_Button_Level(); //Button current level
  54. btn->Debounce_Time = 0;
  55. RT_DEBUG_LOG(RT_DEBUG_THREAD,("button create success!"));
  56. Add_Button(btn); //Added to the singly linked list when button created
  57. Print_Btn_Info(btn); //printf info
  58. }
  59. /************************************************************
  60. * @brief burron trigger events are attach to callback function
  61. * @param btn:button structure
  62. * @param btn_event:button events
  63. * @param btn_callback : Callback handler after the button is triggered.Need user implementation
  64. * @return RT_NULL
  65. * @author jiejie
  66. * @github https://github.com/jiejieTop
  67. * @date 2018-xx-xx
  68. * @version v1.0
  69. ***********************************************************/
  70. void Button_Attach(Button_t *btn,Button_Event btn_event,Button_CallBack btn_callback)
  71. {
  72. if( btn == RT_NULL)
  73. {
  74. RT_DEBUG_LOG(RT_DEBUG_THREAD,("struct button is RT_NULL!"));
  75. }
  76. if(BUTTON_ALL_RIGGER == btn_event)
  77. {
  78. for(rt_uint8_t i = 0 ; i < number_of_event-1 ; i++)
  79. /*A callback function triggered by a button event ,Used to handle button events */
  80. btn->CallBack_Function[i] = btn_callback;
  81. }
  82. else
  83. {
  84. btn->CallBack_Function[btn_event] = btn_callback;
  85. }
  86. }
  87. /************************************************************
  88. * @brief Delete an already created button
  89. * @param RT_NULL
  90. * @return RT_NULL
  91. * @author jiejie
  92. * @github https://github.com/jiejieTop
  93. * @date 2018-xx-xx
  94. * @version v1.0
  95. * @note RT_NULL
  96. ***********************************************************/
  97. void Button_Delete(Button_t *btn)
  98. {
  99. struct button** curr;
  100. for(curr = &Head_Button; *curr;)
  101. {
  102. struct button* entry = *curr;
  103. if (entry == btn)
  104. {
  105. *curr = entry->Next;
  106. }
  107. else
  108. {
  109. curr = &entry->Next;
  110. }
  111. }
  112. }
  113. /************************************************************
  114. * @brief Get Button Event Info
  115. * @param RT_NULL
  116. * @return RT_NULL
  117. * @author jiejie
  118. * @github https://github.com/jiejieTop
  119. * @date 2018-xx-xx
  120. * @version v1.0
  121. ***********************************************************/
  122. void Get_Button_EventInfo(Button_t *btn)
  123. {
  124. for(rt_uint8_t i = 0 ; i < number_of_event-1 ; i++)
  125. {
  126. if(btn->CallBack_Function[i] != 0)
  127. {
  128. /* print */
  129. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Button_Event:%d",i));
  130. }
  131. }
  132. }
  133. /************************************************************
  134. * @brief Get Button Event
  135. * @param RT_NULL
  136. * @return RT_NULL
  137. * @author jiejie
  138. * @github https://github.com/jiejieTop
  139. * @date 2018-xx-xx
  140. * @version v1.0
  141. ***********************************************************/
  142. rt_uint8_t Get_Button_Event(Button_t *btn)
  143. {
  144. return (rt_uint8_t)(btn->Button_Trigger_Event);
  145. }
  146. /************************************************************
  147. * @brief Get Button State
  148. * @param RT_NULL
  149. * @return RT_NULL
  150. * @author jiejie
  151. * @github https://github.com/jiejieTop
  152. * @date 2018-xx-xx
  153. * @version v1.0
  154. ***********************************************************/
  155. rt_uint8_t Get_Button_State(Button_t *btn)
  156. {
  157. return (rt_uint8_t)(btn->Button_State);
  158. }
  159. /************************************************************
  160. * @brief button cycle processing function
  161. * @param btn:button structure
  162. * @return RT_NULL
  163. * @author jiejie
  164. * @github https://github.com/jiejieTop
  165. * @date 2018-xx-xx
  166. * @version v1.0
  167. * @note This function must be called in a certain period. The recommended period is 20~50ms.
  168. ***********************************************************/
  169. void Button_Cycle_Process(Button_t *btn)
  170. {
  171. /* Get the current button level */
  172. rt_uint8_t current_level = (rt_uint8_t)btn->Read_Button_Level();
  173. /* Button level changes, debounce */
  174. if((current_level != btn->Button_Last_Level)&&(++(btn->Debounce_Time) >= BUTTON_DEBOUNCE_TIME))
  175. {
  176. /* Update current button level */
  177. btn->Button_Last_Level = current_level;
  178. /* button is pressed */
  179. btn->Debounce_Time = 0;
  180. /* If the button is not pressed, change the button state to press (first press / double trigger) */
  181. if(((btn->Button_State == NONE_TRIGGER) || (btn->Button_State == BUTTON_DOUBLE))
  182. && current_level == btn->Button_Trigger_Level)
  183. {
  184. btn->Button_State = BUTTON_DOWM;
  185. TRIGGER_CB(BUTTON_DOWM);
  186. }
  187. //free button
  188. else if(btn->Button_State == BUTTON_DOWM)
  189. {
  190. btn->Button_State = BUTTON_UP;
  191. TRIGGER_CB(BUTTON_UP);
  192. RT_DEBUG_LOG(RT_DEBUG_THREAD,("button release"));
  193. }
  194. }
  195. switch(btn->Button_State)
  196. {
  197. /* button dowm */
  198. case BUTTON_DOWM :
  199. {
  200. if(btn->Button_Last_Level == btn->Button_Trigger_Level)
  201. {
  202. /* Support continuous triggering */
  203. #ifdef CONTINUOS_TRIGGER
  204. if(++(btn->Button_Cycle) >= BUTTON_CONTINUOS_CYCLE)
  205. {
  206. btn->Button_Cycle = 0;
  207. btn->Button_Trigger_Event = BUTTON_CONTINUOS;
  208. /* continuous triggering */
  209. TRIGGER_CB(BUTTON_CONTINUOS);
  210. RT_DEBUG_LOG(RT_DEBUG_THREAD,("continuous triggering"));
  211. }
  212. #else
  213. btn->Button_Trigger_Event = BUTTON_DOWM;
  214. /* Update the trigger event before releasing the button as long press */
  215. if(++(btn->Long_Time) >= BUTTON_LONG_TIME)
  216. {
  217. #ifdef LONG_FREE_TRIGGER
  218. btn->Button_Trigger_Event = BUTTON_LONG;
  219. #else
  220. /* Continuous triggering of long press cycles */
  221. if(++(btn->Button_Cycle) >= BUTTON_LONG_CYCLE)
  222. {
  223. btn->Button_Cycle = 0;
  224. btn->Button_Trigger_Event = BUTTON_LONG;
  225. /* long triggering */
  226. TRIGGER_CB(BUTTON_LONG);
  227. }
  228. #endif
  229. /* Update time overflow */
  230. if(btn->Long_Time == 0xFF)
  231. {
  232. btn->Long_Time = BUTTON_LONG_TIME;
  233. }
  234. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Long press"));
  235. }
  236. #endif
  237. }
  238. break;
  239. }
  240. /* button up */
  241. case BUTTON_UP :
  242. {
  243. /* Trigger click */
  244. if(btn->Button_Trigger_Event == BUTTON_DOWM)
  245. {
  246. /* double click */
  247. if((btn->Timer_Count <= BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State == BUTTON_DOUBLE))
  248. {
  249. btn->Button_Trigger_Event = BUTTON_DOUBLE;
  250. TRIGGER_CB(BUTTON_DOUBLE);
  251. RT_DEBUG_LOG(RT_DEBUG_THREAD,("double click"));
  252. btn->Button_State = NONE_TRIGGER;
  253. btn->Button_Last_State = NONE_TRIGGER;
  254. }
  255. else
  256. {
  257. btn->Timer_Count=0;
  258. /* Detection long press failed, clear 0 */
  259. btn->Long_Time = 0;
  260. #ifndef SINGLE_AND_DOUBLE_TRIGGER
  261. /* click */
  262. TRIGGER_CB(BUTTON_CLICK);
  263. #endif
  264. btn->Button_State = BUTTON_DOUBLE;
  265. btn->Button_Last_State = BUTTON_DOUBLE;
  266. }
  267. }
  268. else if(btn->Button_Trigger_Event == BUTTON_LONG)
  269. {
  270. #ifdef LONG_FREE_TRIGGER
  271. /* Long press */
  272. TRIGGER_CB(BUTTON_LONG);
  273. #else
  274. /* Long press free */
  275. TRIGGER_CB(BUTTON_LONG_FREE);
  276. #endif
  277. btn->Long_Time = 0;
  278. btn->Button_State = NONE_TRIGGER;
  279. btn->Button_Last_State = BUTTON_LONG;
  280. }
  281. #ifdef CONTINUOS_TRIGGER
  282. /* Press continuously */
  283. else if(btn->Button_Trigger_Event == BUTTON_CONTINUOS)
  284. {
  285. btn->Long_Time = 0;
  286. /* Press continuously free */
  287. TRIGGER_CB(BUTTON_CONTINUOS_FREE);
  288. btn->Button_State = NONE_TRIGGER;
  289. btn->Button_Last_State = BUTTON_CONTINUOS;
  290. }
  291. #endif
  292. break;
  293. }
  294. case BUTTON_DOUBLE :
  295. {
  296. /* Update time */
  297. btn->Timer_Count++;
  298. if(btn->Timer_Count>=BUTTON_DOUBLE_TIME)
  299. {
  300. btn->Button_State = NONE_TRIGGER;
  301. btn->Button_Last_State = NONE_TRIGGER;
  302. }
  303. #ifdef SINGLE_AND_DOUBLE_TRIGGER
  304. if((btn->Timer_Count>=BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State != BUTTON_DOWM))
  305. {
  306. btn->Timer_Count=0;
  307. TRIGGER_CB(BUTTON_CLICK);
  308. btn->Button_State = NONE_TRIGGER;
  309. btn->Button_Last_State = BUTTON_DOWM;
  310. }
  311. #endif
  312. break;
  313. }
  314. default :
  315. break;
  316. }
  317. }
  318. /************************************************************
  319. * @brief Traversing the way to scan the button without losing each button
  320. * @param RT_NULL
  321. * @return RT_NULL
  322. * @author jiejie
  323. * @github https://github.com/jiejieTop
  324. * @date 2018-xx-xx
  325. * @version v1.0
  326. * @note This function is called periodically, it is recommended to call 20-50ms once.
  327. ***********************************************************/
  328. void Button_Process(void)
  329. {
  330. struct button* pass_btn;
  331. for(pass_btn = Head_Button; pass_btn != RT_NULL; pass_btn = pass_btn->Next)
  332. {
  333. Button_Cycle_Process(pass_btn);
  334. }
  335. }
  336. /************************************************************
  337. * @brief Search Button
  338. * @param RT_NULL
  339. * @return RT_NULL
  340. * @author jiejie
  341. * @github https://github.com/jiejieTop
  342. * @date 2018-xx-xx
  343. * @version v1.0
  344. * @note RT_NULL
  345. ***********************************************************/
  346. void Search_Button(void)
  347. {
  348. struct button* pass_btn;
  349. for(pass_btn = Head_Button; pass_btn != RT_NULL; pass_btn = pass_btn->Next)
  350. {
  351. RT_DEBUG_LOG(RT_DEBUG_THREAD,("button node have %s",pass_btn->Name));
  352. }
  353. }
  354. /************************************************************
  355. * @brief Handle all button callback functions
  356. * @param RT_NULL
  357. * @return RT_NULL
  358. * @author jiejie
  359. * @github https://github.com/jiejieTop
  360. * @date 2018-xx-xx
  361. * @version v1.0
  362. * @note Not implemented yet
  363. ***********************************************************/
  364. void Button_Process_CallBack(void *btn)
  365. {
  366. rt_uint8_t btn_event = Get_Button_Event(btn);
  367. switch(btn_event)
  368. {
  369. case BUTTON_DOWM:
  370. {
  371. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add processing logic for your press trigger"));
  372. break;
  373. }
  374. case BUTTON_UP:
  375. {
  376. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add processing logic for your trigger release"));
  377. break;
  378. }
  379. case BUTTON_DOUBLE:
  380. {
  381. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add processing logic for your double-click trigger"));
  382. break;
  383. }
  384. case BUTTON_LONG:
  385. {
  386. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add processing logic for your long press trigger"));
  387. break;
  388. }
  389. case BUTTON_LONG_FREE:
  390. {
  391. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add processing logic for your long press trigger free"));
  392. break;
  393. }
  394. case BUTTON_CONTINUOS:
  395. {
  396. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add your continuous trigger processing logic"));
  397. break;
  398. }
  399. case BUTTON_CONTINUOS_FREE:
  400. {
  401. RT_DEBUG_LOG(RT_DEBUG_THREAD,("Add processing logic for your continuous trigger release"));
  402. break;
  403. }
  404. }
  405. }
  406. /**************************** The following is the internal call function ********************/
  407. /************************************************************
  408. * @brief Copy the specified length string
  409. * @param RT_NULL
  410. * @return RT_NULL
  411. * @author jiejie
  412. * @github https://github.com/jiejieTop
  413. * @date 2018-xx-xx
  414. * @version v1.0
  415. * @note RT_NULL
  416. ***********************************************************/
  417. static char *StrnCopy(char *dst, const char *src, rt_uint32_t n)
  418. {
  419. if (n != 0)
  420. {
  421. char *d = dst;
  422. const char *s = src;
  423. do
  424. {
  425. if ((*d++ = *s++) == 0)
  426. {
  427. while (--n != 0)
  428. *d++ = 0;
  429. break;
  430. }
  431. } while (--n != 0);
  432. }
  433. return (dst);
  434. }
  435. /************************************************************
  436. * @brief Print button related information
  437. * @param RT_NULL
  438. * @return RT_NULL
  439. * @author jiejie
  440. * @github https://github.com/jiejieTop
  441. * @date 2018-xx-xx
  442. * @version v1.0
  443. * @note RT_NULL
  444. ***********************************************************/
  445. static void Print_Btn_Info(Button_t* btn)
  446. {
  447. RT_DEBUG_LOG(RT_DEBUG_THREAD,("button struct information:\n\
  448. btn->Name:%s \n\
  449. btn->Button_State:%d \n\
  450. btn->Button_Trigger_Event:%d \n\
  451. btn->Button_Trigger_Level:%d \n\
  452. btn->Button_Last_Level:%d \n\
  453. ",
  454. btn->Name,
  455. btn->Button_State,
  456. btn->Button_Trigger_Event,
  457. btn->Button_Trigger_Level,
  458. btn->Button_Last_Level));
  459. Search_Button();
  460. }
  461. /************************************************************
  462. * @brief Connect buttons with a single linked list
  463. * @param RT_NULL
  464. * @return RT_NULL
  465. * @author jiejie
  466. * @github https://github.com/jiejieTop
  467. * @date 2018-xx-xx
  468. * @version v1.0
  469. * @note RT_NULL
  470. ***********************************************************/
  471. static void Add_Button(Button_t* btn)
  472. {
  473. struct button *pass_btn = Head_Button;
  474. while(pass_btn)
  475. {
  476. pass_btn = pass_btn->Next;
  477. }
  478. btn->Next = Head_Button;
  479. Head_Button = btn;
  480. }
  481. #endif