Quantum Hierarchical State Machine (量子层级状态机)

Samek量子层级状态机

源代码(qf4net)是用C/C++写的,主要用于嵌入式系统,没有C#版本的,不利于使用。
不同于使用固定大小的数组,新的方法采用数组列表的方式,可以适用于任意复杂度,和深度的层级状态机。
完整翻译文章挺困难的,我还是比较喜欢应用的角度来解读代码,并用于实际工作中。只是一个梳理的过程,随着自己理解的程度,对代码的理解又是不一定对。

c – Boost StateCharts与Samek的“量子状态图”的比较


原子状态机AFSM介绍


FSM是有限状态自动机(Finite State Machine)的缩写
原子状态机(Atom FSM) 简称AFSM,代表基本状态机

FSM与AFSM

当我们引入FSM的时候,我们假定一个对象有很多个状态,以连接后台的Connection对象为例,可能有disconnected、connecting、reconnecting、connected状态,我们利用FSM可以很容易在多个状态间正确的流转
必须简化FSM模型,使得万物都可以用同一种FSM描述。 犹如四种基本力(或者两仪生四象、四个方向、四个季节、四冲程内燃机)一样,我们可以将FSM简化为四种状态的基本FSM——AFSM。
image.png
对于只包含3种状态或者2种状态的对象也可以统一成4种状态,比如启动同步成功,或者停止也是同步成功,仍然可以经历4种状态,只是连续变化一下即可。为何要统一成4状态?这样就可以在组合这些AFSM时做一些抽象的封装,产生级联效果。

基于量子平台的PMU软件及状态机描述

基于量子平台的软件开发方法非常适合用于嵌入式软件领域,其软件设计方法主要通过软件系统结构量子化,软件运行状态量子化和实体静态结构量子化,活动对象动态行为量子化和实体配置量子化等步骤实施.基于量子平台的PMU软件系统中不同的任务和共享资源分别封装在5类活动对象中,活动对象的实现采用量子节拍机制,活动对象相互间的通信采用异步事件交换机制

Quantum Leaps发布免费状态机建模工具QM

Quantum Leaps发布了一款免费的状态机建模工具QM(QP Modeler),用于设计嵌入式实时应用并无缝地在QP(Quantum Platform,量子平台)实现。
QP是一套状态机的实现框架,支持的RTOS和处理器非常广泛,已经在消费电子、医疗、工业、无线、网络、国防、机器人,汽车等许多领域的实时嵌入式开发中使用。QP的作者Miro Samek的著作《Practical UML Statecharts in C/C++》更是学习状态机建模和实现状态机不可不看的深度教材,第一版2004年由国内出版社引进,第二版中译本也即将在国内出版。
QM是先有QP这个实现框架,再有图形建模工具,图形工具建立在代码框架的基础上。其他状态图工具如IAR VisualState(最新版本6.3.2),还有IBM Rational Rhapsody(最新版本7.5.3)走的是自上而下的路线,也支持状态图的验证和测试,生成的代码和RTOS整合。
现在使用的状态图是由David Harel在1980年代发明提出的,增加了层次、并行等元素,改进了之前常规FSM(有限状态机)复杂性很快增加的缺陷。状态图是面向对象建模中非常重要的要素。对象身上发生的行为导致对象属性值的变化,属性值的变化又导致行为的变化,这种不同行为之间精妙的互动关系,通过状态图展现出来。可以这样说,如果没有把核心的逻辑封装到关键类的状态机中,只能说这样的面向对象建模是“假面向对象”。通过状态图可以帮助开发人员确定一个类合适的责任到底是哪些,往往可以起到缩窄类和外界的接口,加强封装的作用。

资源
http://www.state-machine.com/downloads/index.php#QM
QM下载
http://www.wisdom.weizmann.ac.il/~harel/papers/Statecharts.pdf
1984年David Harel发表的关于状态图的文献:Statecharts: A visual formalism for complex systems
http://www.youtube.com/watch?v=KJ9WaUa_4m0
2010年David Harel在Federated Logic Conference (FLoC)上缅怀图灵奖获得者Amir Pnueli的演讲视频。
(UMLChina,不得转载用于商业用途)

qp-nano代码大餐

  1. /*****************************************************************************
  2. * Product: QEP-nano implemenation
  3. * Last Updated for Version: 4.1.05
  4. * Date of the Last Update: Oct 27, 2010
  5. *
  6. * Q u a n t u m L e a P s
  7. * ---------------------------
  8. * innovating embedded systems
  9. *
  10. * Copyright (C) 2002-2010 Quantum Leaps, LLC. All rights reserved.
  11. *
  12. * This software may be distributed and modified under the terms of the GNU
  13. * General Public License version 2 (GPL) as published by the Free Software
  14. * Foundation and appearing in the file GPL.TXT included in the packaging of
  15. * this file. Please note that GPL Section 2[b] requires that all works based
  16. * on this software must also be made publicly available under the terms of
  17. * the GPL ("Copyleft").
  18. *
  19. * Alternatively, this software may be distributed and modified under the
  20. * terms of Quantum Leaps commercial licenses, which expressly supersede
  21. * the GPL and are specifically designed for licensees interested in
  22. * retaining the proprietary status of their code.
  23. *
  24. * Contact information:
  25. * Quantum Leaps Web site: http://www.quantum-leaps.com
  26. * e-mail: info@quantum-leaps.com
  27. *****************************************************************************/
  28. #include "qpn_port.h" /* QP-nano port */
  29. #ifndef Q_NHSM
  30. Q_DEFINE_THIS_MODULE(qepn)
  31. #endif
  32. /**
  33. * \file
  34. * \ingroup qepn qfn
  35. * QEP-nano implementation.
  36. */
  37. /** empty signal for internal use only */
  38. #define QEP_EMPTY_SIG_ 0
  39. /** maximum depth of state nesting (including the top level), must be >= 2 */
  40. #define QEP_MAX_NEST_DEPTH_ 5
  41. /*..........................................................................*/
  42. /*lint -e970 -e971 */ /* ignore MISRA rules 13 and 14 in this function */
  43. char const Q_ROM * Q_ROM_VAR QP_getVersion(void) {
  44. static char const Q_ROM Q_ROM_VAR version[] = {
  45. ((QP_VERSION >> 12) & 0xF) + '0',
  46. '.',
  47. ((QP_VERSION >> 8) & 0xF) + '0',
  48. '.',
  49. ((QP_VERSION >> 4) & 0xF) + '0',
  50. (QP_VERSION & 0xF) + '0',
  51. '\0'
  52. };
  53. return version;
  54. }
  55. #ifndef Q_NFSM
  56. /*..........................................................................*/
  57. void QFsm_init(QFsm *me) {
  58. (void)(*me->state)(me); /* execute the top-most initial transition */
  59. Q_SIG(me) = (QSignal)Q_ENTRY_SIG;
  60. (void)(*me->state)(me); /* enter the target */
  61. }
  62. /*..........................................................................*/
  63. #ifndef QK_PREEMPTIVE
  64. void QFsm_dispatch(QFsm *me)
  65. {
  66. #else
  67. void QFsm_dispatch(QFsm *me) Q_REENTRANT
  68. {
  69. #endif
  70. QStateHandler s = me->state;
  71. if ((*s)(me) == Q_RET_TRAN) { /* transition taken? */
  72. Q_SIG(me) = (QSignal)Q_EXIT_SIG;
  73. (void)(*s)(me); /* exit the source */
  74. Q_SIG(me) = (QSignal)Q_ENTRY_SIG;
  75. (void)(*me->state)(me); /* enter the target */
  76. }
  77. }
  78. #endif /* Q_NFSM */
  79. #ifndef Q_NHSM
  80. /*..........................................................................*/
  81. QState QHsm_top(QHsm *me) {
  82. (void)me; /* supress the "unused argument" compiler warning */
  83. return Q_IGNORED(); /* the top state ignores all events */
  84. }
  85. /*..........................................................................*/
  86. void QHsm_init(QHsm *me) {
  87. QStateHandler t;
  88. /* 初始化状态机时必须转换到一个明确的状态 */
  89. Q_ALLEGE((*me->state)(me) == Q_RET_TRAN);/* initial tran. must be taken */
  90. /*从顶层状态开始,执行递归的进入操作
  91. * 此时me->state已经为初始化后的目标状态
  92. */
  93. t = (QStateHandler)&QHsm_top; /* an HSM starts in the top state */
  94. do { /* drill into the target hierarchy... */
  95. QStateHandler path[QEP_MAX_NEST_DEPTH_];
  96. int8_t ip = (int8_t)0;
  97. /*利用QEP_EMPTY_SIG_信号,从目标状态回溯到顶状态,
  98. * QEP_EMPTY_SIG_信号除把状态转换到超状态,不做任何操作
  99. * 保存回溯的路径到ip数组中,保存为逆序
  100. * 即第一个数组元素为目标状态,上层状态其后
  101. * 顶层状态并不包括在路径中
  102. */
  103. path[0] = me->state;
  104. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  105. (void)(*me->state)(me);
  106. while (me->state != t) {
  107. ++ip;
  108. path[ip] = me->state;
  109. (void)(*me->state)(me);
  110. }
  111. /* 回到目标状态 */
  112. me->state = path[0];
  113. /* 确保深度在预定内 */
  114. /* entry path must not overflow */
  115. Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
  116. /* 从进入路径执行Q_ENTRY_SIG信号事件 */
  117. Q_SIG(me) = (QSignal)Q_ENTRY_SIG;
  118. do { /* retrace the entry path in reverse (correct) order... */
  119. (void)(*path[ip])(me); /* enter path[ip] */
  120. --ip;
  121. } while (ip >= (int8_t)0);
  122. /* 在目标状态上执行初始化 */
  123. t = path[0];
  124. Q_SIG(me) = (QSignal)Q_INIT_SIG;
  125. /*在目标状态上执行初始化操作
  126. * 如果目标状态的初始化导致状态转换,则重复上述过程
  127. * 直到进入一个状态在执行初始化后不再转换
  128. */
  129. } while ((*t)(me) == Q_RET_TRAN); /* initial transition handled? */
  130. me->state = t;
  131. }
  132. /*..........................................................................*/
  133. #ifndef QK_PREEMPTIVE
  134. void QHsm_dispatch(QHsm *me) {
  135. #else
  136. void QHsm_dispatch(QHsm *me) Q_REENTRANT {
  137. #endif
  138. QStateHandler path[QEP_MAX_NEST_DEPTH_];
  139. QStateHandler s;
  140. QStateHandler t;
  141. QState r;
  142. t = me->state; /* save the current state */
  143. /*事件处理,直到被当前状态或层次上的超状态处理
  144. * 因为在被处理前一直返回 Q_RET_SUPER
  145. * 所以此循环退出时,事件肯定已经被处理了
  146. * s 保存的是处理事件的超状态!
  147. * 当前的me->state则为在处理事件的超状态中转换的目标状态
  148. */
  149. do { /* process the event hierarchically... */
  150. s = me->state;
  151. r = (*s)(me); /* invoke state handler s */
  152. } while (r == Q_RET_SUPER);
  153. if (r == Q_RET_TRAN) { /* transition taken? */
  154. /*
  155. * 在事件处理时,发生了状态转换
  156. * 这个转换要么发生在分发事件的初始状态(入口参数me->state),
  157. * 要么就在初始状态的超状态
  158. * s就保存了这个发生转换的状态
  159. */
  160. int8_t ip = (int8_t)(-1); /* transition entry path index */
  161. int8_t iq; /* helper transition entry path index */
  162. /* 把转换的目标状态保存到path[0] */
  163. path[0] = me->state; /* save the target of the transition */
  164. /* 把转换的起源状态保存到path[1],
  165. * 起源状态为入口参数me->state,先前存放在t中
  166. */
  167. path[1] = t;
  168. /*如果转换发生在超状态中,则执行从起源状态到超状态的退出操作
  169. * 注意,最后的超状态是不会执行退出操作的
  170. */
  171. while (t != s) { /* exit current state to transition source s... */
  172. /*
  173. * 执行退出事件不能有转换,除非返回超状态
  174. */
  175. Q_SIG(me) = (QSignal)Q_EXIT_SIG; /* find superstate of t */
  176. if ((*t)(me) == Q_RET_HANDLED) { /* exit action handled? */
  177. /*
  178. * 退出被处理则要执行空信号,强迫返回超状态
  179. */
  180. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  181. (void)(*t)(me); /* find superstate of t */
  182. }
  183. /*
  184. * me->state必定已变为超状态!
  185. */
  186. t = me->state; /* me->state holds the superstate */
  187. }
  188. /* 现在,me->state回到了执行转换状态的超状态 */
  189. /* 提出目标状态 */
  190. t = path[0]; /* target of the transition */
  191. /*t已经为目标状态,
  192. * s为执行状态转换的那个状态,即实际执行处理被分发的事件的那个状态
  193. * 这个状态要么是分发事件的初始状态(入口参数me->state),
  194. * 要么是初始状态的超状态
  195. */
  196. if (s == t) { /* (a) check source==target (transition to self) */
  197. /*转换的目标状态与转换操作发生的状态相同
  198. * 执行一个自转换,即退出操作
  199. */
  200. Q_SIG(me) = (QSignal)Q_EXIT_SIG;
  201. (void)(*s)(me); /* exit the source */
  202. /* 准备进入目标状态, path[0]就是目标状态 */
  203. ip = (int8_t)0; /* enter the target */
  204. }
  205. else {
  206. /*
  207. * 目标状态与转换源状态不同,
  208. * 即从处理事件的那个状态转换到了一个新状态
  209. * 此时,并不知道目标状态在状态树中的哪个位置
  210. * 麻烦即将来临!
  211. *
  212. * s: 执行转换的起源状态 t: 目标状态
  213. */
  214. /* 求得目标状态的超状态 */
  215. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  216. (void)(*t)(me); /* find superstate of target */
  217. t = me->state;
  218. /* t: 已变成目标状态的超状态 */
  219. /* 目标状态是否起源状态的子状态? */
  220. /* 目标状态的超状态就是起源状态么? */
  221. if (s == t) { /* (b) check source==target->super */
  222. /*
  223. * 目标状态的超状态就是起源状态
  224. */
  225. /* 准备进入目标状态, path[0]就是目标状态 */
  226. ip = (int8_t)0; /* enter the target */
  227. }
  228. else {
  229. /*
  230. * 目标状态的超状态不是起源状态
  231. */
  232. /* 求得起源状态的超状态 */
  233. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  234. (void)(*s)(me); /* find superstate of source */
  235. /* 是否兄弟状态?*/
  236. /* 即起源状态的超状态和目标状态的超状态相同么 ? */
  237. /* (c) check source->super==target->super */
  238. if (me->state == t) {
  239. /*
  240. * 起源状态的超状态和目标状态的超状态相同, 
  241. * 这个超状态就是LCA(最小公共超状态)
  242. */
  243. /* 退出起源状态,准备进入目标状态, path[0]就是目标状态 */
  244. Q_SIG(me) = (QSignal)Q_EXIT_SIG;
  245. (void)(*s)(me); /* exit the source */
  246. ip = (int8_t)0; /* enter the target */
  247. }
  248. else {
  249. /*
  250. * 不是兄弟状态,那么是目标状态是起源状态的父亲么 ?
  251. * me->state已经是起源状态的超状态
  252. */
  253. /* (d) check source->super==target */
  254. if (me->state == path[0]) {
  255. /*
  256. * 目标状态确实是父状态
  257. * 退出起源状态
  258. * 转换到父状态不需要执行进入操作
  259. * 因为源状态本身就在父状态之中
  260. * 故ip=-1,没有ip=0这句
  261. */
  262. Q_SIG(me) = (QSignal)Q_EXIT_SIG;
  263. (void)(*s)(me); /* exit the source */
  264. }
  265. else { /* (e) check rest of source==target->super->super..
  266. * and store the entry path along the way
  267. */
  268. /*
  269. * 彻底看看源状态是不是目标状态的超状态
  270. * 即目标状态是否在源状态的状态树上
  271. */
  272. /* iq指示是否找到LCA */
  273. iq = (int8_t)0; /* indicate that LCA not found */
  274. /* path[0]已经是目标状态 */
  275. ip = (int8_t)1; /* enter target and its superstate */
  276. /* path[1]存放目标状态的超状态 */
  277. path[1] = t; /* save the superstate of target */
  278. /* 至此,me->state是神马玩意了呢 ? */
  279. /* OK,它已经是起源状态的超状态了 */
  280. t = me->state; /* save source->super */
  281. /*
  282. * 现在,从目标状态的超状态往上走
  283. * 目标状态的超状态在path[1]里
  284. */
  285. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  286. r = (*path[1])(me); /* find target->super->super */
  287. /* Go up! */
  288. /*
  289. * 到顶或者
  290. * 从超状态链中找到起源状态
  291. */
  292. while (r == Q_RET_SUPER) {
  293. /*
  294. * 保存路径
  295. */
  296. path[++ip] = me->state; /* store the entry path */
  297. if (me->state == s) { /* is it the source? */
  298. /*
  299. * 找到了,那个找我麻烦的状态:-)
  300. * 设置标志
  301. */
  302. iq = (int8_t)1; /* indicate that LCA found */
  303. /* entry path must not overflow */
  304. Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
  305. /* 扣除目标状态 */
  306. --ip; /* do not enter the source */
  307. /*
  308. * r还有用么,舍不得用break?
  309. * 结构化真他妈的那么重要?
  310. */
  311. r = Q_RET_HANDLED; /* terminate the loop */
  312. }
  313. else { /* it is not the source, keep going up */
  314. /*
  315. * Go up continue!
  316. * 对QEP_EMPTY_SIG_,
  317. * 只要有超状态就会返回Q_RET_SUPER
  318. * 否则就是到顶了
  319. */
  320. r = (*me->state)(me); /* superstate of t */
  321. }
  322. }
  323. /*
  324. * 在目标状态的超状态中找到源状态了么?
  325. * 实际上是看目标状态与源状态是否在同一条树枝路径上
  326. */
  327. if (iq == (int8_t)0) { /* the LCA not found yet? */
  328. /*
  329. * 悲剧啊,不在一条树枝上!
  330. * LCA自然是还没找到
  331. */
  332. /* entry path must not overflow */
  333. Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
  334. /*
  335. * 没办法,LCA肯定在源状态的某个超状态上了
  336. * 来,现在沿着源状态的超状态往上走
  337. * 去找与目标状态的共同祖先LCA
  338. * path已经记录了目标状态的超状态链
  339. */
  340. /*
  341. * 毫无疑问,这次需要从源状态一路退出到LCA
  342. */
  343. Q_SIG(me) = (QSignal)Q_EXIT_SIG;
  344. (void)(*s)(me); /* exit the source */
  345. /* 注意,俺开始退出了 */
  346. /*
  347. * iq的作用变了,用于辅助跟踪状态链
  348. */
  349. /* (f) check the rest of source->super
  350. * == target->super->super...
  351. */
  352. iq = ip;
  353. r = Q_RET_IGNORED; /* indicate LCA NOT found */
  354. /* 此时,t为起源状态的父状态,即第一层超状态 */
  355. do {
  356. /*
  357. * 从目标状态超状态链的最上面开始
  358. */
  359. s = path[iq];
  360. if (t == s) { /* is this the LCA? */
  361. /*
  362. * 这么容易就找到了?真没劲啊
  363. */
  364. r = Q_RET_HANDLED;/* indicate LCA found */
  365. /*
  366. * 目标状态的超状态链不包括LCA
  367. * 注意:如果iq=0,
  368. * 即目标状态就是超源状态的父状态
  369. * ip=0-1=-1,此后不会执行父状态的进入
  370. * 因为此时源状态本身就在目标状态中!
  371. */
  372. ip = (int8_t)(iq - 1);/*do not enter LCA*/
  373. /*
  374. * 结束循环的标志,我日,还是不用break!
  375. */
  376. iq = (int8_t)(-1);/* terminate the loop */
  377. }
  378. else {
  379. /*
  380. * 向目标状态的超状态链向下辗个位置
  381. */
  382. --iq; /* try lower superstate of target */
  383. }
  384. } while (iq >= (int8_t)0);
  385. /* 源状态的父状态也不是LCA? */
  386. if (r != Q_RET_HANDLED) { /* LCA not found yet? */
  387. /* (g) check each source->super->...
  388. * for each target->super...
  389. */
  390. /*
  391. * 确实不是,还得继续找,肏他妈的真累啊
  392. * 这下该怎么找啊,好晕
  393. * 这些变量都变成什么玩意儿了?
  394. * t:还是为起源状态的父状态
  395. */
  396. r = Q_RET_IGNORED; /* keep looping */
  397. do {
  398. /*
  399. * 唉,从源状态的父状态往上一层层地退吧!
  400. * 兄弟,听过“王霞”的故事么?见附录
  401. */
  402. /* exit t unhandled? */
  403. Q_SIG(me) = (QSignal)Q_EXIT_SIG;
  404. if ((*t)(me) == Q_RET_HANDLED) {
  405. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  406. (void)(*t)(me); /* find super of t */
  407. }
  408. t = me->state; /* set to super of t */
  409. /*
  410. * 一边执行退出一边往上走
  411. */
  412. /*
  413. * path为目标状态的超状态链
  414. * 这个链中开始找LCA
  415. * 就是每得到一个源状态的超状态
  416. * 就在目标状态的超状态中找
  417. * 找到的第一个就是LCA
  418. * 不信?你可以画个图看看
  419. */
  420. iq = ip;
  421. do {
  422. s = path[iq];
  423. if (t == s) { /* is this LCA? */
  424. /*
  425. * 终于找到了,我的妈呀
  426. */
  427. /* do not enter LCA */
  428. ip = (int8_t)(iq - 1);
  429. iq = (int8_t)(-1);/*break inner */
  430. r = Q_RET_HANDLED;/*break outer */
  431. }
  432. else {
  433. --iq;
  434. }
  435. } while (iq >= (int8_t)0);
  436. } while (r != Q_RET_HANDLED);
  437. }
  438. }
  439. }
  440. }
  441. }
  442. }
  443. /*
  444. * 在上述过程中,退出操作已经干了
  445. * 进入链也保存在path中了
  446. * 开始进入吧,慢点哦^_^
  447. */
  448. /* retrace the entry path in reverse (desired) order... */
  449. Q_SIG(me) = (QSignal)Q_ENTRY_SIG;
  450. for (; ip >= (int8_t)0; --ip) {
  451. (void)(*path[ip])(me); /* enter path[ip] */
  452. }
  453. /* 目标状态提取出来 */
  454. t = path[0]; /* stick the target into register */
  455. /* 更新状态机的目标状态 */
  456. me->state = t; /* update the current state */
  457. /*
  458. * 最后一件事,在目标状态上执行初始化
  459. * 这个过程真他妈的应该和QHsm_init好好地复用一下代码
  460. * 这两个地方类似的递归初始化的代码没有复用相当挫
  461. * 注:初始化转换只能在引起初始化状态的状态树枝里
  462. */
  463. /* drill into the target hierarchy... */
  464. Q_SIG(me) = (QSignal)Q_INIT_SIG;
  465. while ((*t)(me) == Q_RET_TRAN) {
  466. ip = (int8_t)0;
  467. /*
  468. * 初始化时如果状态转换则生成超状态链
  469. */
  470. path[0] = me->state;
  471. Q_SIG(me) = (QSignal)QEP_EMPTY_SIG_;
  472. (void)(*me->state)(me); /* find the superstate */
  473. while (me->state != t) {
  474. ++ip;
  475. path[ip] = me->state;
  476. (void)(*me->state)(me); /* find the superstate */
  477. }
  478. me->state = path[0];
  479. /* entry path must not overflow */
  480. Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
  481. /* 在状态链上执行进入 */
  482. Q_SIG(me) = (QSignal)Q_ENTRY_SIG;
  483. do { /* retrace the entry path in reverse (correct) order... */
  484. (void)(*path[ip])(me); /* enter path[ip] */
  485. --ip;
  486. } while (ip >= (int8_t)0);
  487. /*
  488. * 在目标状态上继续执行初始化
  489. * 最后,没有状态转换的初始化操作的状态为最后的状态
  490. * 这个最后的状态为最终的目标状态,放在t中
  491. */
  492. t = path[0];
  493. Q_SIG(me) = (QSignal)Q_INIT_SIG;
  494. }
  495. }
  496. /* 目标状态终于确定,俺洗洗睡了 */
  497. me->state = t; /* set new state or restore the current state */
  498. }
  499. #endif /* Q_NHSM */
  500. ————————————————
  501. 版权声明:本文为CSDN博主「lyqdy1」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
  502. 原文链接:https://blog.csdn.net/lyqdy1/article/details/7085959
void QF_init(uint_fast8_t maxActive) {
    QActive *a;
    uint_fast8_t p;
    uint_fast8_t n;

    /** @pre the number of active objects must be in range */
    Q_REQUIRE_ID(100, ((uint_fast8_t)1 < maxActive)
                      && (maxActive <= (uint_fast8_t)33));
    QF_maxActive_ = (uint_fast8_t)maxActive - (uint_fast8_t)1;

#ifdef QF_TIMEEVT_USAGE
    for (n = (uint_fast8_t)0; n < (uint_fast8_t)QF_MAX_TICK_RATE; ++n) {
        QF_timerSetX_[n] = (uint_fast8_t)0;
    }
#endif /* QF_TIMEEVT_USAGE */

    QF_readySet_ = (uint_fast32_t)0;

#ifdef qkn_h
    QK_attr_.actPrio = (uint_fast8_t)8; /* QK-nano scheduler locked */

#ifdef QF_ISR_NEST
    QK_attr_.intNest = (uint_fast8_t)0;
#endif

#ifdef QK_SCHED_LOCK
    QK_attr_.lockPrio   = (uint_fast8_t)0;
    QK_attr_.lockHolder = (uint_fast8_t)0;
#endif

#endif /* #ifdef qkn_h */

    /* clear all registered active objects... */
    for (p = (uint_fast8_t)1; p <= QF_maxActive_; ++p) {
        a = QF_ROM_ACTIVE_GET_(p);

        /* QF_active[p] must be initialized */
        Q_ASSERT_ID(110, a != (QActive *)0);

        a->head    = (uint8_t)0;
        a->tail    = (uint8_t)0;
        a->nUsed   = (uint8_t)0;
#if (QF_TIMEEVT_CTR_SIZE != 0)
        for (n = (uint_fast8_t)0; n < (uint_fast8_t)QF_MAX_TICK_RATE; ++n) {
            a->tickCtr[n].nTicks   = (QTimeEvtCtr)0;
#ifdef QF_TIMEEVT_PERIODIC
            a->tickCtr[n].interval = (QTimeEvtCtr)0;
#endif /* def QF_TIMEEVT_PERIODIC */
        }
#endif /* (QF_TIMEEVT_CTR_SIZE != 0) */
    }

#ifdef QV_INIT /* initialization of the QV-nano kernel defined? */
    QV_INIT(); /* port-specific initialization of the QV-nano kernel */
#elif defined QK_INIT /* initialization of the QK-nano kernel defined? */
    QK_INIT(); /* port-specific initialization of the QK-nano kernel */
#endif
}
typedef struct QActive {
    QHsm super; /**< derives from the ::QHsm base class */

#if (QF_TIMEEVT_CTR_SIZE != 0)
    /*! Timer for the active object */
    QTimer tickCtr[QF_MAX_TICK_RATE];
#endif /* (QF_TIMEEVT_CTR_SIZE != 0) */

    /*! priority of the active object (1..8) */
    uint8_t prio;

    /*! offset to where next event will be inserted into the buffer */
    uint8_t volatile head;

    /*! offset of where next event will be extracted from the buffer */
    uint8_t volatile tail;

    /*! number of events currently present in the queue
    * (events in the ring buffer + 1 event in the state machine)
    */
    uint8_t volatile nUsed;

} QActive;