├── .gitignore ├── LICENSE ├── README.md ├── sm.c └── sm.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, leijian001 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SM: 一个状态机库的C语言实现 2 | === 3 | 4 | SM是一个状态机库的C语言实现,支持FSM和HSM。该库参考了QP-nano。 5 | 6 | 7 | SM库以BSD协议发布源代码 8 | -------------------------------------------------------------------------------- /sm.c: -------------------------------------------------------------------------------- 1 | #include "sm.h" 2 | 3 | sm_event_t sm_reserved_event[] = 4 | { 5 | { SM_EMPTY_SIG, 0 }, 6 | { SM_ENTRY_SIG, 0 }, 7 | { SM_EXIT_SIG, 0 }, 8 | { SM_INIT_SIG, 0 }, 9 | { SM_USER_SIG, 0 }, 10 | }; 11 | 12 | 13 | #if CONFIG_SM_FSM 14 | void fsm_ctor(sm_t *me, sm_state_handler_t init) 15 | { 16 | SM_ASSERT(0 != me); 17 | SM_ASSERT(0 != init); 18 | 19 | me->state = 0; 20 | me->temp = init; 21 | } 22 | sm_ret_t fsm_init(sm_t *me, sm_event_t *e) 23 | { 24 | sm_ret_t ret; 25 | 26 | SM_ASSERT(0 != me); 27 | SM_ASSERT(0 != me->temp); 28 | 29 | ret = (me->temp)(me, e); 30 | if(ret != SM_RET_TRAN) 31 | { 32 | return ret; 33 | } 34 | 35 | SM_ENTRY(me, me->temp); 36 | 37 | me->state = me->temp; 38 | 39 | return ret; 40 | } 41 | void fsm_dispatch(sm_t *me, sm_event_t *e) 42 | { 43 | sm_ret_t ret; 44 | 45 | SM_ASSERT(me->state == me->temp); 46 | 47 | ret = (me->temp)(me, e); 48 | if(SM_RET_TRAN == ret) 49 | { 50 | SM_EXIT(me, me->state); 51 | SM_ENTRY(me, me->temp); 52 | me->state = me->temp; 53 | } 54 | } 55 | #endif 56 | 57 | #if CONFIG_SM_HSM 58 | /** 59 | * @brief HSM根状态 60 | */ 61 | sm_ret_t hsm_top(sm_t *me, const sm_event_t *e) 62 | { 63 | (void)me; 64 | (void)e; 65 | 66 | return SM_IGNORE(); 67 | } 68 | 69 | static unsigned char hsm_find_path(sm_t *me, 70 | sm_state_handler_t t, 71 | sm_state_handler_t s, 72 | sm_state_handler_t path[SM_MAX_NEST_DEPTH]) 73 | { 74 | signed char ip = -1; 75 | signed char iq; 76 | sm_ret_t ret; 77 | 78 | /* (a) check source==target (transition to self) */ 79 | if( s == t) 80 | { 81 | SM_EXIT(me, s); 82 | ip = 0; 83 | 84 | goto hsm_find_path_end; 85 | } 86 | 87 | SM_TRIG(me, t, SM_EMPTY_SIG); 88 | t = me->temp; 89 | 90 | /* (b) check source==target->super */ 91 | if( s == t ) 92 | { 93 | ip = 0; 94 | goto hsm_find_path_end; 95 | } 96 | 97 | SM_TRIG(me, s, SM_EMPTY_SIG); 98 | 99 | /* (c) check source->super==target->super */ 100 | if(me->temp == t) 101 | { 102 | SM_EXIT(me, s); 103 | ip = 0; 104 | goto hsm_find_path_end; 105 | } 106 | 107 | /* (d) check source->super==target */ 108 | if( me->temp == path[0] ) 109 | { 110 | SM_EXIT(me, s); 111 | goto hsm_find_path_end; 112 | } 113 | 114 | /* (e) check rest of source==target->super->super.. 115 | * and store the entry path along the way 116 | */ 117 | ip = 1; 118 | iq = 0; 119 | path[1] = t; 120 | t = me->temp; 121 | 122 | /* find target->super->super... */ 123 | ret = SM_TRIG(me, path[1], SM_EMPTY_SIG); 124 | while(SM_RET_SUPER == ret) 125 | { 126 | path[++ip] = me->temp; 127 | if(s == me->temp) 128 | { 129 | iq = 1; 130 | SM_ASSERT(ip < SM_MAX_NEST_DEPTH); 131 | ip--; 132 | 133 | ret = SM_RET_HANDLED; 134 | } 135 | else 136 | { 137 | ret = SM_TRIG(me, me->temp, SM_EMPTY_SIG); 138 | } 139 | } 140 | 141 | /* the LCA not found yet? */ 142 | if(0 == iq) 143 | { 144 | SM_ASSERT(ip < SM_MAX_NEST_DEPTH); 145 | 146 | SM_EXIT(me, s); 147 | 148 | /* (f) check the rest of source->super 149 | * == target->super->super... 150 | */ 151 | iq = ip; 152 | ret = SM_RET_IGNORE; /* LCA NOT found */ 153 | do 154 | { 155 | s = path[iq]; 156 | /* is this the LCA? */ 157 | if(t == s) 158 | { 159 | ret = SM_RET_HANDLED; 160 | 161 | ip = iq - 1; 162 | iq = -1; 163 | } 164 | else 165 | { 166 | iq--; /* try lower superstate of target */ 167 | } 168 | }while(iq >= 0); 169 | 170 | /* LCA not found? */ 171 | if( SM_RET_HANDLED != ret ) 172 | { 173 | /* (g) check each source->super->... 174 | * for each target->super... 175 | */ 176 | ret = SM_RET_IGNORE; 177 | do 178 | { 179 | if(SM_RET_HANDLED == SM_EXIT(me, t)) 180 | { 181 | SM_TRIG(me, t, SM_EMPTY_SIG); 182 | } 183 | t = me->temp; 184 | iq = ip; 185 | do 186 | { 187 | s = path[iq]; 188 | if( t == s) 189 | { 190 | ip = iq -1; 191 | iq = -1; 192 | 193 | ret = SM_RET_HANDLED; /* break */ 194 | } 195 | else 196 | { 197 | iq--; 198 | } 199 | }while(iq >= 0); 200 | }while(SM_RET_HANDLED != ret); 201 | } 202 | } 203 | 204 | hsm_find_path_end: 205 | return ip; 206 | } 207 | 208 | void hsm_ctor(sm_t *me, sm_state_handler_t init) 209 | { 210 | SM_ASSERT(0 != me); 211 | SM_ASSERT(0 != init); 212 | 213 | me->state = hsm_top; 214 | me->temp = init; 215 | } 216 | void hsm_init(sm_t *me, sm_event_t *e) 217 | { 218 | sm_ret_t ret; 219 | signed char ip; 220 | 221 | sm_state_handler_t path[SM_MAX_NEST_DEPTH]; 222 | sm_state_handler_t t = me->state; 223 | 224 | SM_ASSERT(0 != me); 225 | SM_ASSERT(0 != me->temp); 226 | SM_ASSERT(hsm_top == t); 227 | 228 | ret = (me->temp)(me, e); 229 | SM_ASSERT(SM_RET_TRAN == ret); 230 | 231 | do 232 | { 233 | ip = 0; 234 | 235 | path[0] = me->temp; 236 | SM_TRIG(me, me->temp,SM_EMPTY_SIG); 237 | while( t != me->temp ) 238 | { 239 | path[++ip] = me->temp; 240 | SM_TRIG(me, me->temp,SM_EMPTY_SIG); 241 | } 242 | me->temp = path[0]; 243 | 244 | SM_ASSERT(ip < SM_MAX_NEST_DEPTH); 245 | 246 | do 247 | { 248 | SM_ENTRY(me, path[ip--]); 249 | }while(ip >= 0); 250 | 251 | t = path[0]; 252 | }while(SM_RET_TRAN == SM_TRIG(me, t, SM_INIT_SIG)); 253 | 254 | me->temp = t; 255 | me->state = me->temp; 256 | } 257 | 258 | 259 | void hsm_dispatch(sm_t *me, sm_event_t *e) 260 | { 261 | sm_state_handler_t t = me->state; 262 | sm_state_handler_t s; 263 | 264 | sm_ret_t ret; 265 | 266 | // 状态必须稳定 267 | SM_ASSERT(me->state == me->temp); 268 | 269 | /* process the event hierarchically... */ 270 | // 事件递归触发, 直到某个状态处理该事件 271 | do 272 | { 273 | s = me->temp; 274 | ret = s(me, e); // 调用状态处理函数 275 | if(SM_RET_UNHANDLED == ret) 276 | { 277 | ret = SM_TRIG(me, s, SM_EMPTY_SIG); 278 | } 279 | }while(SM_RET_SUPER == ret); 280 | 281 | // 如果发生状态转换 282 | if(SM_RET_TRAN == ret) 283 | { 284 | sm_state_handler_t path[SM_MAX_NEST_DEPTH]; 285 | signed char ip = -1; 286 | 287 | path[0] = me->temp; // 状态转换的目的状态 288 | path[1] = t; // 状态转换的源状态 289 | 290 | /* exit current state to transition source s... */ 291 | for( ; s != t; t = me->temp) 292 | { 293 | ret = SM_EXIT(me, t); 294 | if(SM_RET_HANDLED == ret) 295 | { 296 | SM_TRIG(me, t, SM_EMPTY_SIG); 297 | } 298 | } 299 | 300 | ip = hsm_find_path(me, path[0], s, path); 301 | 302 | for(; ip>=0; ip--) 303 | { 304 | SM_ENTRY(me, path[ip]); 305 | } 306 | 307 | t = path[0]; 308 | me->temp = t; 309 | 310 | /* drill into the target hierarchy... */ 311 | while( SM_RET_TRAN == SM_TRIG(me, t, SM_INIT_SIG) ) 312 | { 313 | ip = 0; 314 | path[0] = me->temp; 315 | 316 | SM_TRIG(me, me->temp, SM_EMPTY_SIG); 317 | while(t != me->temp) 318 | { 319 | path[++ip] = me->temp; 320 | SM_TRIG(me, me->temp, SM_EMPTY_SIG); 321 | } 322 | me->temp = path[0]; 323 | 324 | SM_ASSERT(ip < SM_MAX_NEST_DEPTH); 325 | 326 | do 327 | { 328 | SM_ENTRY(me, path[ip--]); 329 | }while(ip >= 0); 330 | 331 | t = path[0]; 332 | }// end: while( SM_RET_TRAN == SM_TRIG(me, t, SM_INIT_SIG) ) 333 | } // end: if(SM_RET_TRAN == ret) 334 | 335 | me->temp = t; 336 | me->state = t; 337 | } 338 | #endif 339 | -------------------------------------------------------------------------------- /sm.h: -------------------------------------------------------------------------------- 1 | #ifndef __SM_H__ 2 | #define __SM_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | #define CONFIG_SM_DEBUG 1 11 | 12 | #ifndef CONFIG_SM_FSM 13 | #define CONFIG_SM_FSM 1 14 | #endif 15 | 16 | #ifndef CONFIG_SM_HSM 17 | #define CONFIG_SM_HSM 1 18 | #endif 19 | 20 | #if ! (CONFIG_SM_FSM || CONFIG_SM_HSM) 21 | #error "FSM and HSM must chose one!" 22 | #endif 23 | 24 | #ifndef SM_MAX_NEST_DEPTH 25 | #define SM_MAX_NEST_DEPTH 6 26 | #endif 27 | 28 | #ifndef offsetof 29 | #define offsetof(type, member) ((unsigned int) &((type *)0)->member) 30 | #endif 31 | 32 | #ifndef container_of 33 | #define container_of(ptr, type, member) ((type *)( (char *)(ptr) - offsetof(type,member) )) 34 | #endif 35 | 36 | #define sm_entry() 37 | 38 | typedef int sm_sig_t; 39 | 40 | /** 41 | * @bref 状态机事件 42 | */ 43 | typedef struct sm_event_s 44 | { 45 | sm_sig_t sig; 46 | void *event; 47 | }sm_event_t; 48 | 49 | /** 50 | * @bref 状态处理函数返回值, 指示事件被怎么处理了 51 | */ 52 | typedef unsigned char sm_ret_t; 53 | 54 | //struct sm_fsm_s; 55 | typedef struct sm_s sm_t; 56 | typedef sm_ret_t (*sm_state_handler_t)(sm_t *fsm, sm_event_t const *e); 57 | 58 | /** 59 | * @bref 状态机 60 | */ 61 | struct sm_s 62 | { 63 | sm_state_handler_t state; 64 | sm_state_handler_t temp; 65 | }; 66 | 67 | /** 68 | * @bref 状态机返回值 69 | * 70 | */ 71 | enum 72 | { 73 | SM_RET_HANDLED, 74 | SM_RET_IGNORE, 75 | SM_RET_UNHANDLED, 76 | 77 | SM_RET_TRAN, 78 | SM_RET_SUPER, 79 | }; 80 | #define SM_RET_CAST(x) ( (sm_ret_t)(x) ) 81 | 82 | #define SM_HANDLED() SM_RET_CAST(SM_RET_HANDLED) 83 | #define SM_IGNORE() SM_RET_CAST(SM_RET_IGNORE) 84 | #define SM_UNHANDLED() SM_RET_CAST(SM_RET_UNHANDLED) 85 | 86 | #define SM_TRAN(me, target) \ 87 | ((me)->temp = (target), SM_RET_CAST(SM_RET_TRAN)) 88 | #define SM_SUPER(me, super) \ 89 | ((me)->temp = (super), SM_RET_CAST(SM_RET_SUPER)) 90 | 91 | 92 | enum sm_reserved_sig 93 | { 94 | SM_EMPTY_SIG = -5, 95 | SM_ENTRY_SIG = -4, 96 | SM_EXIT_SIG = -3, 97 | SM_INIT_SIG = -2, 98 | SM_USER_SIG = -1, 99 | }; 100 | extern sm_event_t sm_reserved_event[]; 101 | #define SM_TRIG(me, state, sig) ((state)(me, &sm_reserved_event[5 + (sig)])) 102 | #define SM_ENTRY(me, state) SM_TRIG(me, state, SM_ENTRY_SIG) 103 | #define SM_EXIT(me, state) SM_TRIG(me, state, SM_EXIT_SIG) 104 | 105 | #if CONFIG_SM_FSM 106 | void fsm_ctor(sm_t *me, sm_state_handler_t init); 107 | sm_ret_t fsm_init(sm_t *me, sm_event_t *e); 108 | void fsm_dispatch(sm_t *me, sm_event_t *e); 109 | #endif 110 | 111 | #if CONFIG_SM_HSM 112 | void hsm_ctor(sm_t *me, sm_state_handler_t init); 113 | sm_ret_t hsm_top(sm_t *me, const sm_event_t *e); 114 | void hsm_init(sm_t *me, sm_event_t *e); 115 | void hsm_dispatch(sm_t *me, sm_event_t *e); 116 | #endif 117 | 118 | #if CONFIG_SM_DEBUG 119 | #define SM_ASSERT(cond) do{ if(!(cond)){ while(1); } }while(0) 120 | #else 121 | #define SM_ASSERT(cond) /* NULL */ 122 | #endif 123 | 124 | #ifdef __cplusplus 125 | } 126 | #endif 127 | 128 | #endif 129 | --------------------------------------------------------------------------------