state_machine_example.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (c) 2013 Andreas Misje
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. #include <stdint.h>
  23. #include <stdio.h>
  24. #include "state_machine.h"
  25. #include "rtthread.h"
  26. /* This simple example checks keyboad input against the two allowed strings
  27. * "han" and "hin". If an unrecognised character is read, a group state will
  28. * handle this by printing a message and returning to the idle state. If the
  29. * character '!' is encountered, a "reset" message is printed, and the group
  30. * state's entry state will be entered (the idle state).
  31. *
  32. * print 'reset'
  33. * o +---------------------+
  34. * | | | '!'
  35. * | v group state |
  36. * +-----v-----------------------------------+----+
  37. * | +------+ 'h' +---+ 'a' +---+ 'n' |
  38. * +->| idle | ----> | h | ----> | a | ---------+ |
  39. * | +------+ +---+\ +---+ | |
  40. * | ^ ^ ^ \'i' +---+ 'n' | |
  41. * | | | | \--> | i | ------+ | |
  42. * | | | | +---+ | | |
  43. * +---|-|-|----------------+----------------|--|-+
  44. * | | | | | |
  45. * | | | | '[^hai!\n]' | |
  46. * | | | print unrecog. | | |
  47. * | | +----------------+ print 'hi' | |
  48. * | +-----------------------------------+ |
  49. * | print 'ha' |
  50. * +----------------------------------------+
  51. */
  52. /* Types of events */
  53. enum event_type {
  54. EVENT_KEYBOARD,
  55. };
  56. /* Compare keyboard character from transition's condition variable against
  57. * data in event. */
  58. static bool keyboard_char_compare( void *ch, struct event *event );
  59. static void print_msg_recognised_char( void *state_data, struct event *event );
  60. static void print_msg_unrecognised_char( void *oldstate_data, struct event *event,
  61. void *state_new_data );
  62. static void print_msg_reset( void *oldstate_data, struct event *event,
  63. void *state_new_data );
  64. static void print_msg_hi( void *oldstate_data, struct event *event,
  65. void *state_new_data );
  66. static void print_msg_ha( void *oldstate_data, struct event *event,
  67. void *state_new_data );
  68. static void print_msg_err( void *state_data, struct event *event );
  69. static void print_msg_enter( void *state_data, struct event *event );
  70. static void print_msg_exit( void *state_data, struct event *event );
  71. /* Forward declaration of states so that they can be defined in an logical
  72. * order: */
  73. static struct state state_charsgroup_check, state_idle, state_h, state_i, state_a;
  74. /* All the following states (apart from the error state) are children of this
  75. * group state. This way, any unrecognised character will be handled by this
  76. * state's transition, eliminating the need for adding the same transition to
  77. * all the children states. */
  78. static struct state state_charsgroup_check = {
  79. .state_parent = NULL,
  80. /* The entry state is defined in order to demontrate that the 'reset'
  81. * transtition, going to this group state, will be 'redirected' to the
  82. * 'idle' state (the transition could of course go directly to the 'idle'
  83. * state): */
  84. .state_entry = &state_idle,
  85. .transitions = (struct transition[]){
  86. /* event_type data guard action next state */
  87. { EVENT_KEYBOARD, (void *)(intptr_t)'!', &keyboard_char_compare,
  88. &print_msg_reset, &state_idle, },
  89. { EVENT_KEYBOARD, NULL, NULL, &print_msg_unrecognised_char, &state_idle, },
  90. },
  91. .transition_nums = 2,
  92. .data = "group",
  93. .action_entry = &print_msg_enter,
  94. .action_exti = &print_msg_exit,
  95. };
  96. static struct state state_idle = {
  97. .state_parent = &state_charsgroup_check,
  98. .state_entry = NULL,
  99. .transitions = (struct transition[]){
  100. { EVENT_KEYBOARD, (void *)(intptr_t)'h', &keyboard_char_compare, NULL, &state_h },
  101. },
  102. .transition_nums = 1,
  103. .data = "idle",
  104. .action_entry = &print_msg_enter,
  105. .action_exti = &print_msg_exit,
  106. };
  107. static struct state state_h = {
  108. .state_parent = &state_charsgroup_check,
  109. .state_entry = NULL,
  110. .transitions = (struct transition[]){
  111. { EVENT_KEYBOARD, (void *)(intptr_t)'a', &keyboard_char_compare, NULL, &state_a },
  112. { EVENT_KEYBOARD, (void *)(intptr_t)'i', &keyboard_char_compare, NULL, &state_i },
  113. },
  114. .transition_nums = 2,
  115. .data = "H",
  116. .action_entry = &print_msg_recognised_char,
  117. .action_exti = &print_msg_exit,
  118. };
  119. static struct state state_i = {
  120. .state_parent = &state_charsgroup_check,
  121. .state_entry = NULL,
  122. .transitions = (struct transition[]){
  123. { EVENT_KEYBOARD, (void *)(intptr_t)'n', &keyboard_char_compare, &print_msg_hi, &state_idle }
  124. },
  125. .transition_nums = 1,
  126. .data = "I",
  127. .action_entry = &print_msg_recognised_char,
  128. .action_exti = &print_msg_exit,
  129. };
  130. static struct state state_a = {
  131. .state_parent = &state_charsgroup_check,
  132. .state_entry = NULL,
  133. .transitions = (struct transition[]){
  134. { EVENT_KEYBOARD, (void *)(intptr_t)'n', &keyboard_char_compare, &print_msg_ha, &state_idle }
  135. },
  136. .transition_nums = 1,
  137. .data = "A",
  138. .action_entry = &print_msg_recognised_char,
  139. .action_exti = &print_msg_exit
  140. };
  141. static struct state state_error = {
  142. .transitions = (struct transition[]){
  143. { EVENT_KEYBOARD, (void *)(intptr_t)'i', &keyboard_char_compare, NULL, &state_i },
  144. },
  145. .transition_nums = 1,
  146. .data = "Error",
  147. .action_entry = &print_msg_err
  148. };
  149. static bool keyboard_char_compare( void *ch, struct event *event )
  150. {
  151. if ( event->type != EVENT_KEYBOARD )
  152. {
  153. return false;
  154. }
  155. // ch = t->conditon
  156. // t->conditon == event->data
  157. // 就是说当前转移的条件要和事件的data吻合
  158. return ((intptr_t)ch == (intptr_t)event->data);
  159. }
  160. static void print_msg_recognised_char( void *state_data, struct event *event )
  161. {
  162. print_msg_enter( state_data, event );
  163. rt_kprintf( "parsed: %c\n", (char)(intptr_t)event->data );
  164. }
  165. static void print_msg_unrecognised_char( void *oldstate_data, struct event *event,
  166. void *state_new_data )
  167. {
  168. rt_kprintf( "unrecognised character: %c\n",(char)(intptr_t)event->data );
  169. }
  170. static void print_msg_reset( void *oldstate_data, struct event *event,
  171. void *state_new_data )
  172. {
  173. rt_kprintf( "Resetting\n" );
  174. }
  175. static void print_msg_hi( void *oldstate_data, struct event *event,
  176. void *state_new_data )
  177. {
  178. rt_kprintf( "Hi!\n" );
  179. }
  180. static void print_msg_ha( void *oldstate_data, struct event *event,
  181. void *state_new_data )
  182. {
  183. rt_kprintf( "Ha-ha\n" );
  184. }
  185. static void print_msg_err( void *state_data, struct event *event )
  186. {
  187. rt_kprintf( "ENTERED ERROR STATE!\n" );
  188. }
  189. static void print_msg_enter( void *state_data, struct event *event )
  190. {
  191. rt_kprintf( "Entering %s state\n", (char *)state_data );
  192. }
  193. static void print_msg_exit( void *state_data, struct event *event )
  194. {
  195. rt_kprintf( "Exiting %s state\n", (char *)state_data );
  196. }
  197. rt_mailbox_t mb_key;
  198. static void state_process(void *parameter)
  199. {
  200. struct state_machine m;
  201. int ch;
  202. statem_init( &m, &state_idle, &state_error );
  203. while(1)
  204. {
  205. if(RT_EOK == rt_mb_recv(mb_key, (rt_ubase_t*)&ch, 20))
  206. {
  207. statem_handle_event( &m, &(struct event){ EVENT_KEYBOARD, (void *)(intptr_t)ch } );
  208. }
  209. }
  210. }
  211. static int state_init(void)
  212. {
  213. rt_thread_t tid = RT_NULL;
  214. mb_key = rt_mb_create("key", 8, RT_IPC_FLAG_FIFO);
  215. tid = rt_thread_create("state", state_process, RT_NULL,
  216. 1024, 10, 100);
  217. if (tid == RT_NULL)
  218. {
  219. rt_kprintf("state initialize failed! thread create failed!\r\n");
  220. return -RT_ENOMEM;
  221. }
  222. rt_thread_startup(tid);
  223. return RT_EOK;
  224. }
  225. INIT_APP_EXPORT(state_init);
  226. #ifdef FINSH_USING_MSH
  227. static void state_key_set(uint8_t argc, char **argv)
  228. {
  229. if (argc == 2)
  230. {
  231. rt_kprintf("state key set:%c\n",argv[1][0]);
  232. rt_mb_send(mb_key, argv[1][0]);
  233. }
  234. else
  235. {
  236. rt_kprintf("state key set<a-z>\n");
  237. }
  238. }
  239. MSH_CMD_EXPORT(state_key_set, state key set<a-z>.);
  240. #endif /* FINSH_USING_MSH */