os_tmr.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  1. /*
  2. ************************************************************************************************************************
  3. * uC/OS-III
  4. * The Real-Time Kernel
  5. *
  6. * (c) Copyright 2009-2011; Micrium, Inc.; Weston, FL
  7. * All rights reserved. Protected by international copyright laws.
  8. *
  9. * TIMER MANAGEMENT
  10. *
  11. * File : OS_TMR.C
  12. * By : JJL
  13. * Version : V3.02.00
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
  18. * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
  19. * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
  20. * application/product. We provide ALL the source code for your convenience and to help you
  21. * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
  22. * it commercially without paying a licensing fee.
  23. *
  24. * Knowledge of the source code may NOT be used to develop a similar product.
  25. *
  26. * Please help us continue to provide the embedded community with the finest software available.
  27. * Your honesty is greatly appreciated.
  28. *
  29. * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
  30. ************************************************************************************************************************
  31. */
  32. #include <os.h>
  33. #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
  34. const CPU_CHAR *os_tmr__c = "$Id: $";
  35. #endif
  36. #if OS_CFG_TMR_EN > 0u
  37. /*
  38. ************************************************************************************************************************
  39. * CONSTANTS
  40. ************************************************************************************************************************
  41. */
  42. #define OS_OPT_LINK_DLY (OS_OPT)(0u)
  43. #define OS_OPT_LINK_PERIODIC (OS_OPT)(1u)
  44. /*$PAGE*/
  45. /*
  46. ************************************************************************************************************************
  47. * CREATE A TIMER
  48. *
  49. * Description: This function is called by your application code to create a timer.
  50. *
  51. * Arguments : p_tmr Is a pointer to a timer control block
  52. *
  53. * p_name Is a pointer to an ASCII string that is used to name the timer. Names are useful for
  54. * debugging.
  55. *
  56. * dly Initial delay.
  57. * If the timer is configured for ONE-SHOT mode, this is the timeout used
  58. * If the timer is configured for PERIODIC mode, this is the first timeout to wait for
  59. * before the timer starts entering periodic mode
  60. *
  61. * period The 'period' being repeated for the timer.
  62. * If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will
  63. * automatically restart with the same period.
  64. *
  65. * opt Specifies either:
  66. *
  67. * OS_OPT_TMR_ONE_SHOT The timer counts down only once
  68. * OS_OPT_TMR_PERIODIC The timer counts down and then reloads itself
  69. *
  70. * p_callback Is a pointer to a callback function that will be called when the timer expires. The
  71. * callback function must be declared as follows:
  72. *
  73. * void MyCallback (OS_TMR *p_tmr, void *p_arg);
  74. *
  75. * p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
  76. *
  77. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  78. *
  79. * OS_ERR_NONE
  80. * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the timer after you called
  81. * OSSafetyCriticalStart().
  82. * OS_ERR_OBJ_CREATED if the timer has already been created
  83. * OS_ERR_OBJ_PTR_NULL is 'p_tmr' is a NULL pointer
  84. * OS_ERR_OBJ_TYPE if the object type is invalid
  85. * OS_ERR_OPT_INVALID you specified an invalid option
  86. * OS_ERR_TMR_INVALID_DLY you specified an invalid delay
  87. * OS_ERR_TMR_INVALID_PERIOD you specified an invalid period
  88. * OS_ERR_TMR_ISR if the call was made from an ISR
  89. *
  90. * Returns : none
  91. *
  92. * Note(s) : 1) This function only creates the timer. In other words, the timer is not started when created. To
  93. * start the timer, call OSTmrStart().
  94. ************************************************************************************************************************
  95. */
  96. void OSTmrCreate (OS_TMR *p_tmr,
  97. CPU_CHAR *p_name,
  98. OS_TICK dly,
  99. OS_TICK period,
  100. OS_OPT opt,
  101. OS_TMR_CALLBACK_PTR p_callback,
  102. void *p_callback_arg,
  103. OS_ERR *p_err)
  104. {
  105. CPU_SR_ALLOC();
  106. #ifdef OS_SAFETY_CRITICAL
  107. if (p_err == (OS_ERR *)0) {
  108. OS_SAFETY_CRITICAL_EXCEPTION();
  109. return;
  110. }
  111. #endif
  112. #ifdef OS_SAFETY_CRITICAL_IEC61508
  113. if (OSSafetyCriticalStartFlag == DEF_TRUE) {
  114. *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  115. return;
  116. }
  117. #endif
  118. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  119. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
  120. *p_err = OS_ERR_TMR_ISR;
  121. return;
  122. }
  123. #endif
  124. #if OS_CFG_ARG_CHK_EN > 0u
  125. if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */
  126. *p_err = OS_ERR_OBJ_PTR_NULL;
  127. return;
  128. }
  129. switch (opt) {
  130. case OS_OPT_TMR_PERIODIC:
  131. if (period == (OS_TICK)0) {
  132. *p_err = OS_ERR_TMR_INVALID_PERIOD;
  133. return;
  134. }
  135. break;
  136. case OS_OPT_TMR_ONE_SHOT:
  137. if (dly == (OS_TICK)0) {
  138. *p_err = OS_ERR_TMR_INVALID_DLY;
  139. return;
  140. }
  141. break;
  142. default:
  143. *p_err = OS_ERR_OPT_INVALID;
  144. return;
  145. }
  146. #endif
  147. CPU_CRITICAL_ENTER();
  148. p_tmr->State = (OS_STATE )OS_TMR_STATE_STOPPED; /* Initialize the timer fields */
  149. p_tmr->Type = (OS_OBJ_TYPE )OS_OBJ_TYPE_TMR;
  150. p_tmr->NamePtr = (CPU_CHAR *)p_name;
  151. p_tmr->Dly = (OS_TICK )dly;
  152. p_tmr->Match = (OS_TICK )0;
  153. p_tmr->Remain = (OS_TICK )0;
  154. p_tmr->Period = (OS_TICK )period;
  155. p_tmr->Opt = (OS_OPT )opt;
  156. p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)p_callback;
  157. p_tmr->CallbackPtrArg = (void *)p_callback_arg;
  158. p_tmr->NextPtr = (OS_TMR *)0;
  159. p_tmr->PrevPtr = (OS_TMR *)0;
  160. #if OS_CFG_DBG_EN > 0u
  161. OS_TmrDbgListAdd(p_tmr);
  162. #endif
  163. OSTmrQty++; /* Keep track of the number of timers created */
  164. CPU_CRITICAL_EXIT();
  165. *p_err = OS_ERR_NONE;
  166. }
  167. /*$PAGE*/
  168. /*
  169. ************************************************************************************************************************
  170. * DELETE A TIMER
  171. *
  172. * Description: This function is called by your application code to delete a timer.
  173. *
  174. * Arguments : p_tmr Is a pointer to the timer to stop and delete.
  175. *
  176. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  177. *
  178. * OS_ERR_NONE
  179. * OS_ERR_OBJ_TYPE 'p_tmr' is not pointing to a timer
  180. * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
  181. * OS_ERR_TMR_ISR if the function was called from an ISR
  182. * OS_ERR_TMR_INACTIVE if the timer was not created
  183. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  184. *
  185. * Returns : DEF_TRUE if the timer was deleted
  186. * DEF_FALSE if not or upon an error
  187. ************************************************************************************************************************
  188. */
  189. #if OS_CFG_TMR_DEL_EN > 0u
  190. CPU_BOOLEAN OSTmrDel (OS_TMR *p_tmr,
  191. OS_ERR *p_err)
  192. {
  193. OS_ERR err;
  194. #ifdef OS_SAFETY_CRITICAL
  195. if (p_err == (OS_ERR *)0) {
  196. OS_SAFETY_CRITICAL_EXCEPTION();
  197. return (DEF_FALSE);
  198. }
  199. #endif
  200. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  201. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
  202. *p_err = OS_ERR_TMR_ISR;
  203. return (DEF_FALSE);
  204. }
  205. #endif
  206. #if OS_CFG_ARG_CHK_EN > 0u
  207. if (p_tmr == (OS_TMR *)0) {
  208. *p_err = OS_ERR_TMR_INVALID;
  209. return (DEF_FALSE);
  210. }
  211. #endif
  212. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  213. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  214. *p_err = OS_ERR_OBJ_TYPE;
  215. return (DEF_FALSE);
  216. }
  217. #endif
  218. OSSchedLock(&err);
  219. #if OS_CFG_DBG_EN > 0u
  220. OS_TmrDbgListRemove(p_tmr);
  221. #endif
  222. OSTmrQty--; /* One less timer */
  223. switch (p_tmr->State) {
  224. case OS_TMR_STATE_RUNNING:
  225. OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */
  226. OS_TmrClr(p_tmr);
  227. OSSchedUnlock(&err);
  228. *p_err = OS_ERR_NONE;
  229. return (DEF_TRUE);
  230. case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
  231. case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
  232. OS_TmrClr(p_tmr); /* Clear timer fields */
  233. OSSchedUnlock(&err);
  234. *p_err = OS_ERR_NONE;
  235. return (DEF_TRUE);
  236. case OS_TMR_STATE_UNUSED: /* Already deleted */
  237. OSSchedUnlock(&err);
  238. *p_err = OS_ERR_TMR_INACTIVE;
  239. return (DEF_FALSE);
  240. default:
  241. OSSchedUnlock(&err);
  242. *p_err = OS_ERR_TMR_INVALID_STATE;
  243. return (DEF_FALSE);
  244. }
  245. }
  246. #endif
  247. /*$PAGE*/
  248. /*
  249. ************************************************************************************************************************
  250. * GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
  251. *
  252. * Description: This function is called to get the number of ticks before a timer times out.
  253. *
  254. * Arguments : p_tmr Is a pointer to the timer to obtain the remaining time from.
  255. *
  256. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  257. *
  258. * OS_ERR_NONE
  259. * OS_ERR_OBJ_TYPE 'p_tmr' is not pointing to a timer
  260. * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
  261. * OS_ERR_TMR_ISR if the call was made from an ISR
  262. * OS_ERR_TMR_INACTIVE 'p_tmr' points to a timer that is not active
  263. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  264. *
  265. * Returns : The time remaining for the timer to expire. The time represents 'timer' increments. In other words, if
  266. * OS_TmrTask() is signaled every 1/10 of a second then the returned value represents the number of 1/10 of
  267. * a second remaining before the timer expires.
  268. ************************************************************************************************************************
  269. */
  270. OS_TICK OSTmrRemainGet (OS_TMR *p_tmr,
  271. OS_ERR *p_err)
  272. {
  273. OS_TICK remain;
  274. OS_ERR err;
  275. #ifdef OS_SAFETY_CRITICAL
  276. if (p_err == (OS_ERR *)0) {
  277. OS_SAFETY_CRITICAL_EXCEPTION();
  278. return ((OS_TICK)0);
  279. }
  280. #endif
  281. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  282. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
  283. *p_err = OS_ERR_TMR_ISR;
  284. return ((OS_TICK)0);
  285. }
  286. #endif
  287. #if OS_CFG_ARG_CHK_EN > 0u
  288. if (p_tmr == (OS_TMR *)0) {
  289. *p_err = OS_ERR_TMR_INVALID;
  290. return ((OS_TICK)0);
  291. }
  292. #endif
  293. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  294. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  295. *p_err = OS_ERR_OBJ_TYPE;
  296. return ((OS_TICK)0);
  297. }
  298. #endif
  299. OSSchedLock(&err);
  300. switch (p_tmr->State) {
  301. case OS_TMR_STATE_RUNNING:
  302. remain = p_tmr->Match /* Determine how much time is left to timeout */
  303. - OSTmrTickCtr;
  304. p_tmr->Remain = remain;
  305. OSSchedUnlock(&err);
  306. *p_err = OS_ERR_NONE;
  307. return (remain);
  308. case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
  309. if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
  310. if (p_tmr->Dly == 0u) {
  311. remain = p_tmr->Period;
  312. } else {
  313. remain = p_tmr->Dly;
  314. }
  315. } else {
  316. remain = p_tmr->Dly;
  317. }
  318. p_tmr->Remain = remain;
  319. OSSchedUnlock(&err);
  320. *p_err = OS_ERR_NONE;
  321. return (remain);
  322. case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT that timed out can be in this state */
  323. OSSchedUnlock(&err);
  324. *p_err = OS_ERR_NONE;
  325. return ((OS_TICK)0);
  326. case OS_TMR_STATE_UNUSED:
  327. OSSchedUnlock(&err);
  328. *p_err = OS_ERR_TMR_INACTIVE;
  329. return ((OS_TICK)0);
  330. default:
  331. OSSchedUnlock(&err);
  332. *p_err = OS_ERR_TMR_INVALID_STATE;
  333. return ((OS_TICK)0);
  334. }
  335. }
  336. /*$PAGE*/
  337. /*
  338. ************************************************************************************************************************
  339. * START A TIMER
  340. *
  341. * Description: This function is called by your application code to start a timer.
  342. *
  343. * Arguments : p_tmr Is a pointer to an OS_TMR
  344. *
  345. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  346. *
  347. * OS_ERR_NONE
  348. * OS_ERR_OBJ_TYPE if 'p_tmr' is not pointing to a timer
  349. * OS_ERR_TMR_INVALID
  350. * OS_ERR_TMR_INACTIVE if the timer was not created
  351. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  352. * OS_ERR_TMR_ISR if the call was made from an ISR
  353. *
  354. * Returns : DEF_TRUE is the timer was started
  355. * DEF_FALSE if not or upon an error
  356. *
  357. * Note(s) : 1) When starting/restarting a timer, regardless if it is in PERIODIC or ONE-SHOT mode, the timer is
  358. * linked to the timer wheel with the OS_OPT_LINK_DLY option. This option sets the initial expiration
  359. * time for the timer. For timers in PERIODIC mode, subsequent expiration times are handled by
  360. * the OS_TmrTask().
  361. ************************************************************************************************************************
  362. */
  363. CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr,
  364. OS_ERR *p_err)
  365. {
  366. OS_ERR err;
  367. #ifdef OS_SAFETY_CRITICAL
  368. if (p_err == (OS_ERR *)0) {
  369. OS_SAFETY_CRITICAL_EXCEPTION();
  370. return (DEF_FALSE);
  371. }
  372. #endif
  373. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  374. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
  375. *p_err = OS_ERR_TMR_ISR;
  376. return (DEF_FALSE);
  377. }
  378. #endif
  379. #if OS_CFG_ARG_CHK_EN > 0u
  380. if (p_tmr == (OS_TMR *)0) {
  381. *p_err = OS_ERR_TMR_INVALID;
  382. return (DEF_FALSE);
  383. }
  384. #endif
  385. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  386. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  387. *p_err = OS_ERR_OBJ_TYPE;
  388. return (DEF_FALSE);
  389. }
  390. #endif
  391. OSSchedLock(&err);
  392. switch (p_tmr->State) {
  393. case OS_TMR_STATE_RUNNING: /* Restart the timer */
  394. OS_TmrUnlink(p_tmr); /* ... Stop the timer */
  395. OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); /* ... Link timer to timer wheel (see Note #1). */
  396. OSSchedUnlock(&err);
  397. *p_err = OS_ERR_NONE;
  398. return (DEF_TRUE);
  399. case OS_TMR_STATE_STOPPED: /* Start the timer */
  400. case OS_TMR_STATE_COMPLETED:
  401. OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); /* ... Link timer to timer wheel (see Note #1). */
  402. OSSchedUnlock(&err);
  403. *p_err = OS_ERR_NONE;
  404. return (DEF_TRUE);
  405. case OS_TMR_STATE_UNUSED: /* Timer not created */
  406. OSSchedUnlock(&err);
  407. *p_err = OS_ERR_TMR_INACTIVE;
  408. return (DEF_FALSE);
  409. default:
  410. OSSchedUnlock(&err);
  411. *p_err = OS_ERR_TMR_INVALID_STATE;
  412. return (DEF_FALSE);
  413. }
  414. }
  415. /*$PAGE*/
  416. /*
  417. ************************************************************************************************************************
  418. * FIND OUT WHAT STATE A TIMER IS IN
  419. *
  420. * Description: This function is called to determine what state the timer is in:
  421. *
  422. * OS_TMR_STATE_UNUSED the timer has not been created
  423. * OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped
  424. * OS_TMR_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout
  425. * OS_TMR_RUNNING the timer is currently running
  426. *
  427. * Arguments : p_tmr Is a pointer to the desired timer
  428. *
  429. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  430. *
  431. * OS_ERR_NONE
  432. * OS_ERR_OBJ_TYPE if 'p_tmr' is not pointing to a timer
  433. * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
  434. * OS_ERR_TMR_INVALID_STATE if the timer is not in a valid state
  435. * OS_ERR_TMR_ISR if the call was made from an ISR
  436. *
  437. * Returns : The current state of the timer (see description).
  438. ************************************************************************************************************************
  439. */
  440. OS_STATE OSTmrStateGet (OS_TMR *p_tmr,
  441. OS_ERR *p_err)
  442. {
  443. OS_STATE state;
  444. CPU_SR_ALLOC();
  445. #ifdef OS_SAFETY_CRITICAL
  446. if (p_err == (OS_ERR *)0) {
  447. OS_SAFETY_CRITICAL_EXCEPTION();
  448. return (OS_TMR_STATE_UNUSED);
  449. }
  450. #endif
  451. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  452. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
  453. *p_err = OS_ERR_TMR_ISR;
  454. return (OS_TMR_STATE_UNUSED);
  455. }
  456. #endif
  457. #if OS_CFG_ARG_CHK_EN > 0u
  458. if (p_tmr == (OS_TMR *)0) {
  459. *p_err = OS_ERR_TMR_INVALID;
  460. return (OS_TMR_STATE_UNUSED);
  461. }
  462. #endif
  463. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  464. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  465. *p_err = OS_ERR_OBJ_TYPE;
  466. return (OS_TMR_STATE_UNUSED);
  467. }
  468. #endif
  469. CPU_CRITICAL_ENTER();
  470. state = p_tmr->State;
  471. switch (state) {
  472. case OS_TMR_STATE_UNUSED:
  473. case OS_TMR_STATE_STOPPED:
  474. case OS_TMR_STATE_COMPLETED:
  475. case OS_TMR_STATE_RUNNING:
  476. *p_err = OS_ERR_NONE;
  477. break;
  478. default:
  479. *p_err = OS_ERR_TMR_INVALID_STATE;
  480. break;
  481. }
  482. CPU_CRITICAL_EXIT();
  483. return (state);
  484. }
  485. /*$PAGE*/
  486. /*
  487. ************************************************************************************************************************
  488. * STOP A TIMER
  489. *
  490. * Description: This function is called by your application code to stop a timer.
  491. *
  492. * Arguments : p_tmr Is a pointer to the timer to stop.
  493. *
  494. * opt Allows you to specify an option to this functions which can be:
  495. *
  496. * OS_OPT_TMR_NONE Do nothing special but stop the timer
  497. * OS_OPT_TMR_CALLBACK Execute the callback function, pass it the callback argument
  498. * specified when the timer was created.
  499. * OS_OPT_TMR_CALLBACK_ARG Execute the callback function, pass it the callback argument
  500. * specified in THIS function call
  501. *
  502. * callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function
  503. * instead of the timer's callback argument. In other words, use 'callback_arg' passed in
  504. * THIS function INSTEAD of p_tmr->OSTmrCallbackArg
  505. *
  506. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  507. * OS_ERR_NONE
  508. * OS_ERR_OBJ_TYPE if 'p_tmr' is not pointing to a timer
  509. * OS_ERR_OPT_INVALID if you specified an invalid option for 'opt'
  510. * OS_ERR_TMR_INACTIVE if the timer was not created
  511. * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
  512. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  513. * OS_ERR_TMR_ISR if the function was called from an ISR
  514. * OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined
  515. * OS_ERR_TMR_STOPPED if the timer was already stopped
  516. *
  517. * Returns : DEF_TRUE If we stopped the timer (if the timer is already stopped, we also return DEF_TRUE)
  518. * DEF_FALSE If not
  519. ************************************************************************************************************************
  520. */
  521. CPU_BOOLEAN OSTmrStop (OS_TMR *p_tmr,
  522. OS_OPT opt,
  523. void *p_callback_arg,
  524. OS_ERR *p_err)
  525. {
  526. OS_TMR_CALLBACK_PTR p_fnct;
  527. OS_ERR err;
  528. #ifdef OS_SAFETY_CRITICAL
  529. if (p_err == (OS_ERR *)0) {
  530. OS_SAFETY_CRITICAL_EXCEPTION();
  531. return (DEF_FALSE);
  532. }
  533. #endif
  534. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  535. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
  536. *p_err = OS_ERR_TMR_ISR;
  537. return (DEF_FALSE);
  538. }
  539. #endif
  540. #if OS_CFG_ARG_CHK_EN > 0u
  541. if (p_tmr == (OS_TMR *)0) {
  542. *p_err = OS_ERR_TMR_INVALID;
  543. return (DEF_FALSE);
  544. }
  545. #endif
  546. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  547. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  548. *p_err = OS_ERR_OBJ_TYPE;
  549. return (DEF_FALSE);
  550. }
  551. #endif
  552. OSSchedLock(&err);
  553. switch (p_tmr->State) {
  554. case OS_TMR_STATE_RUNNING:
  555. OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */
  556. *p_err = OS_ERR_NONE;
  557. switch (opt) {
  558. case OS_OPT_TMR_CALLBACK:
  559. p_fnct = p_tmr->CallbackPtr; /* Execute callback function ... */
  560. if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { /* ... if available */
  561. (*p_fnct)((void *)p_tmr, p_tmr->CallbackPtrArg); /* Use callback arg when timer was created */
  562. } else {
  563. *p_err = OS_ERR_TMR_NO_CALLBACK;
  564. }
  565. break;
  566. case OS_OPT_TMR_CALLBACK_ARG:
  567. p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available ... */
  568. if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
  569. (*p_fnct)((void *)p_tmr, p_callback_arg); /* .. using the 'callback_arg' provided in call */
  570. } else {
  571. *p_err = OS_ERR_TMR_NO_CALLBACK;
  572. }
  573. break;
  574. case OS_OPT_TMR_NONE:
  575. break;
  576. default:
  577. OSSchedUnlock(&err);
  578. *p_err = OS_ERR_OPT_INVALID;
  579. return (DEF_FALSE);
  580. }
  581. OSSchedUnlock(&err);
  582. return (DEF_TRUE);
  583. case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or */
  584. case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
  585. OSSchedUnlock(&err);
  586. *p_err = OS_ERR_TMR_STOPPED;
  587. return (DEF_TRUE);
  588. case OS_TMR_STATE_UNUSED: /* Timer was not created */
  589. OSSchedUnlock(&err);
  590. *p_err = OS_ERR_TMR_INACTIVE;
  591. return (DEF_FALSE);
  592. default:
  593. OSSchedUnlock(&err);
  594. *p_err = OS_ERR_TMR_INVALID_STATE;
  595. return (DEF_FALSE);
  596. }
  597. }
  598. /*$PAGE*/
  599. /*
  600. ************************************************************************************************************************
  601. * CLEAR TIMER FIELDS
  602. *
  603. * Description: This function is called to clear all timer fields.
  604. *
  605. * Argument(s): p_tmr is a pointer to the timer to clear
  606. * -----
  607. *
  608. * Returns : none
  609. *
  610. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  611. ************************************************************************************************************************
  612. */
  613. void OS_TmrClr (OS_TMR *p_tmr)
  614. {
  615. p_tmr->State = OS_TMR_STATE_UNUSED; /* Clear timer fields */
  616. p_tmr->Type = OS_OBJ_TYPE_NONE;
  617. p_tmr->NamePtr = (CPU_CHAR *)((void *)"?TMR");
  618. p_tmr->Dly = (OS_TICK )0;
  619. p_tmr->Match = (OS_TICK )0;
  620. p_tmr->Remain = (OS_TICK )0;
  621. p_tmr->Period = (OS_TICK )0;
  622. p_tmr->Opt = (OS_OPT )0;
  623. p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)0;
  624. p_tmr->CallbackPtrArg = (void *)0;
  625. p_tmr->NextPtr = (OS_TMR *)0;
  626. p_tmr->PrevPtr = (OS_TMR *)0;
  627. }
  628. /*$PAGE*/
  629. /*
  630. ************************************************************************************************************************
  631. * ADD/REMOVE TIMER TO/FROM DEBUG TABLE
  632. *
  633. * Description: These functions are called by uC/OS-III to add or remove a timer to/from a timer debug table.
  634. *
  635. * Arguments : p_tmr is a pointer to the timer to add/remove
  636. *
  637. * Returns : none
  638. *
  639. * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
  640. ************************************************************************************************************************
  641. */
  642. #if OS_CFG_DBG_EN > 0u
  643. void OS_TmrDbgListAdd (OS_TMR *p_tmr)
  644. {
  645. p_tmr->DbgPrevPtr = (OS_TMR *)0;
  646. if (OSTmrDbgListPtr == (OS_TMR *)0) {
  647. p_tmr->DbgNextPtr = (OS_TMR *)0;
  648. } else {
  649. p_tmr->DbgNextPtr = OSTmrDbgListPtr;
  650. OSTmrDbgListPtr->DbgPrevPtr = p_tmr;
  651. }
  652. OSTmrDbgListPtr = p_tmr;
  653. }
  654. void OS_TmrDbgListRemove (OS_TMR *p_tmr)
  655. {
  656. OS_TMR *p_tmr_next;
  657. OS_TMR *p_tmr_prev;
  658. p_tmr_prev = p_tmr->DbgPrevPtr;
  659. p_tmr_next = p_tmr->DbgNextPtr;
  660. if (p_tmr_prev == (OS_TMR *)0) {
  661. OSTmrDbgListPtr = p_tmr_next;
  662. if (p_tmr_next != (OS_TMR *)0) {
  663. p_tmr_next->DbgPrevPtr = (OS_TMR *)0;
  664. }
  665. p_tmr->DbgNextPtr = (OS_TMR *)0;
  666. } else if (p_tmr_next == (OS_TMR *)0) {
  667. p_tmr_prev->DbgNextPtr = (OS_TMR *)0;
  668. p_tmr->DbgPrevPtr = (OS_TMR *)0;
  669. } else {
  670. p_tmr_prev->DbgNextPtr = p_tmr_next;
  671. p_tmr_next->DbgPrevPtr = p_tmr_prev;
  672. p_tmr->DbgNextPtr = (OS_TMR *)0;
  673. p_tmr->DbgPrevPtr = (OS_TMR *)0;
  674. }
  675. }
  676. #endif
  677. /*$PAGE*/
  678. /*
  679. ************************************************************************************************************************
  680. * INITIALIZE THE TIMER MANAGER
  681. *
  682. * Description: This function is called by OSInit() to initialize the timer manager module.
  683. *
  684. * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
  685. *
  686. * OS_ERR_NONE
  687. * OS_ERR_TMR_STK_INVALID if you didn't specify a stack for the timer task
  688. * OS_ERR_TMR_STK_SIZE_INVALID if you didn't allocate enough space for the timer stack
  689. * OS_ERR_PRIO_INVALID if you specified the same priority as the idle task
  690. * OS_ERR_xxx any error code returned by OSTaskCreate()
  691. *
  692. * Returns : none
  693. *
  694. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  695. ************************************************************************************************************************
  696. */
  697. void OS_TmrInit (OS_ERR *p_err)
  698. {
  699. OS_TMR_SPOKE_IX i;
  700. OS_TMR_SPOKE *p_spoke;
  701. #ifdef OS_SAFETY_CRITICAL
  702. if (p_err == (OS_ERR *)0) {
  703. OS_SAFETY_CRITICAL_EXCEPTION();
  704. return;
  705. }
  706. #endif
  707. #if OS_CFG_DBG_EN > 0u
  708. OSTmrDbgListPtr = (OS_TMR *)0;
  709. #endif
  710. if (OSCfg_TmrTaskRate_Hz > (OS_RATE_HZ)0) {
  711. OSTmrUpdateCnt = OSCfg_TickRate_Hz / OSCfg_TmrTaskRate_Hz;
  712. } else {
  713. OSTmrUpdateCnt = OSCfg_TickRate_Hz / (OS_RATE_HZ)10;
  714. }
  715. OSTmrUpdateCtr = OSTmrUpdateCnt;
  716. OSTmrTickCtr = (OS_TICK)0;
  717. OSTmrTaskTimeMax = (CPU_TS)0;
  718. for (i = 0u; i < OSCfg_TmrWheelSize; i++) {
  719. p_spoke = &OSCfg_TmrWheel[i];
  720. p_spoke->NbrEntries = (OS_OBJ_QTY)0;
  721. p_spoke->NbrEntriesMax = (OS_OBJ_QTY)0;
  722. p_spoke->FirstPtr = (OS_TMR *)0;
  723. }
  724. /* ---------------- CREATE THE TIMER TASK --------------- */
  725. if (OSCfg_TmrTaskStkBasePtr == (CPU_STK*)0) {
  726. *p_err = OS_ERR_TMR_STK_INVALID;
  727. return;
  728. }
  729. if (OSCfg_TmrTaskStkSize < OSCfg_StkSizeMin) {
  730. *p_err = OS_ERR_TMR_STK_INVALID;
  731. return;
  732. }
  733. if (OSCfg_TmrTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) {
  734. *p_err = OS_ERR_PRIO_INVALID;
  735. return;
  736. }
  737. OSTaskCreate((OS_TCB *)&OSTmrTaskTCB,
  738. (CPU_CHAR *)((void *)"uC/OS-III Timer Task"),
  739. (OS_TASK_PTR )OS_TmrTask,
  740. (void *)0,
  741. (OS_PRIO )OSCfg_TmrTaskPrio,
  742. (CPU_STK *)OSCfg_TmrTaskStkBasePtr,
  743. (CPU_STK_SIZE)OSCfg_TmrTaskStkLimit,
  744. (CPU_STK_SIZE)OSCfg_TmrTaskStkSize,
  745. (OS_MSG_QTY )0,
  746. (OS_TICK )0,
  747. (void *)0,
  748. (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
  749. (OS_ERR *)p_err);
  750. }
  751. /*$PAGE*/
  752. /*
  753. ************************************************************************************************************************
  754. * INSERT A TIMER INTO THE TIMER WHEEL
  755. *
  756. * Description: This function is called to insert the timer into the timer wheel. The timer is always inserted at the
  757. * beginning of the list.
  758. *
  759. * Arguments : p_tmr Is a pointer to the timer to insert.
  760. * -----
  761. *
  762. * opt Is either:
  763. *
  764. * OS_OPT_LINK_PERIODIC Means to re-insert the timer after a period expired
  765. * OS_OPT_LINK_DLY Means to insert the timer the first time
  766. *
  767. * Returns : none
  768. *
  769. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  770. ************************************************************************************************************************
  771. */
  772. void OS_TmrLink (OS_TMR *p_tmr,
  773. OS_OPT opt)
  774. {
  775. OS_TMR_SPOKE *p_spoke;
  776. OS_TMR *p_tmr0;
  777. OS_TMR *p_tmr1;
  778. OS_TMR_SPOKE_IX spoke;
  779. p_tmr->State = OS_TMR_STATE_RUNNING;
  780. if (opt == OS_OPT_LINK_PERIODIC) { /* Determine when timer will expire */
  781. p_tmr->Match = p_tmr->Period + OSTmrTickCtr;
  782. } else {
  783. if (p_tmr->Dly == (OS_TICK)0) {
  784. p_tmr->Match = p_tmr->Period + OSTmrTickCtr;
  785. } else {
  786. p_tmr->Match = p_tmr->Dly + OSTmrTickCtr;
  787. }
  788. }
  789. spoke = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize);
  790. p_spoke = &OSCfg_TmrWheel[spoke];
  791. if (p_spoke->FirstPtr == (OS_TMR *)0) { /* Link into timer wheel */
  792. p_tmr->NextPtr = (OS_TMR *)0;
  793. p_tmr->PrevPtr = (OS_TMR *)0;
  794. p_spoke->FirstPtr = p_tmr;
  795. p_spoke->NbrEntries = 1u;
  796. } else {
  797. p_tmr->Remain = p_tmr->Match /* Compute remaining time for timer */
  798. - OSTmrTickCtr;
  799. p_tmr1 = p_spoke->FirstPtr; /* Point to current first timer in the list */
  800. while (p_tmr1 != (OS_TMR *)0) {
  801. p_tmr1->Remain = p_tmr1->Match /* Compute time remaining of current timer in list */
  802. - OSTmrTickCtr;
  803. if (p_tmr->Remain > p_tmr1->Remain) { /* Do we need to insert AFTER current timer in list? */
  804. if (p_tmr1->NextPtr != (OS_TMR *)0) { /* Yes, are we pointing at the last timer in the list? */
  805. p_tmr1 = p_tmr1->NextPtr; /* No, Point to next timer in the list */
  806. } else {
  807. p_tmr->NextPtr = (OS_TMR *)0;
  808. p_tmr->PrevPtr = p_tmr1;
  809. p_tmr1->NextPtr = p_tmr; /* Yes, timer to insert is now new last entry in the list */
  810. p_tmr1 = (OS_TMR *)0; /* Break loop */
  811. }
  812. } else { /* Insert before the current timer */
  813. if (p_tmr1->PrevPtr == (OS_TMR *)0) { /* Are we inserting before the first timer? */
  814. p_tmr->PrevPtr = (OS_TMR *)0;
  815. p_tmr->NextPtr = p_tmr1;
  816. p_tmr1->PrevPtr = p_tmr;
  817. p_spoke->FirstPtr = p_tmr;
  818. } else { /* Insert in between 2 timers already in the list */
  819. p_tmr0 = p_tmr1->PrevPtr;
  820. p_tmr->PrevPtr = p_tmr0;
  821. p_tmr->NextPtr = p_tmr1;
  822. p_tmr0->NextPtr = p_tmr;
  823. p_tmr1->PrevPtr = p_tmr;
  824. }
  825. p_tmr1 = (OS_TMR *)0; /* Break loop */
  826. }
  827. }
  828. p_spoke->NbrEntries++;
  829. }
  830. if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) { /* Keep track of maximum number of entries in each spoke */
  831. p_spoke->NbrEntriesMax = p_spoke->NbrEntries;
  832. }
  833. }
  834. /*$PAGE*/
  835. /*
  836. ************************************************************************************************************************
  837. * RESET TIMER LIST PEAK DETECTOR
  838. *
  839. * Description: This function is used to reset the peak detector for the number of entries in each spoke.
  840. *
  841. * Arguments : void
  842. *
  843. * Returns : none
  844. *
  845. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  846. ************************************************************************************************************************
  847. */
  848. void OS_TmrResetPeak (void)
  849. {
  850. OS_TMR_SPOKE *p_spoke;
  851. OS_TMR_SPOKE_IX i;
  852. for (i = 0u; i < OSCfg_TmrWheelSize; i++) {
  853. p_spoke = (OS_TMR_SPOKE *)&OSCfg_TmrWheel[i];
  854. p_spoke->NbrEntriesMax = (OS_OBJ_QTY )0u;
  855. }
  856. }
  857. /*$PAGE*/
  858. /*
  859. ************************************************************************************************************************
  860. * REMOVE A TIMER FROM THE TIMER WHEEL
  861. *
  862. * Description: This function is called to remove the timer from the timer wheel.
  863. *
  864. * Arguments : p_tmr Is a pointer to the timer to remove.
  865. * -----
  866. *
  867. * Returns : none
  868. *
  869. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  870. ************************************************************************************************************************
  871. */
  872. void OS_TmrUnlink (OS_TMR *p_tmr)
  873. {
  874. OS_TMR_SPOKE *p_spoke;
  875. OS_TMR *p_tmr1;
  876. OS_TMR *p_tmr2;
  877. OS_TMR_SPOKE_IX spoke;
  878. spoke = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize);
  879. p_spoke = &OSCfg_TmrWheel[spoke];
  880. if (p_spoke->FirstPtr == p_tmr) { /* See if timer to remove is at the beginning of list */
  881. p_tmr1 = (OS_TMR *)p_tmr->NextPtr;
  882. p_spoke->FirstPtr = (OS_TMR *)p_tmr1;
  883. if (p_tmr1 != (OS_TMR *)0) {
  884. p_tmr1->PrevPtr = (OS_TMR *)0;
  885. }
  886. } else {
  887. p_tmr1 = (OS_TMR *)p_tmr->PrevPtr; /* Remove timer from somewhere in the list */
  888. p_tmr2 = (OS_TMR *)p_tmr->NextPtr;
  889. p_tmr1->NextPtr = p_tmr2;
  890. if (p_tmr2 != (OS_TMR *)0) {
  891. p_tmr2->PrevPtr = (OS_TMR *)p_tmr1;
  892. }
  893. }
  894. p_tmr->State = OS_TMR_STATE_STOPPED;
  895. p_tmr->NextPtr = (OS_TMR *)0;
  896. p_tmr->PrevPtr = (OS_TMR *)0;
  897. p_spoke->NbrEntries--;
  898. }
  899. /*$PAGE*/
  900. /*
  901. ************************************************************************************************************************
  902. * TIMER MANAGEMENT TASK
  903. *
  904. * Description: This task is created by OS_TmrInit().
  905. *
  906. * Arguments : none
  907. *
  908. * Returns : none
  909. *
  910. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  911. ************************************************************************************************************************
  912. */
  913. void OS_TmrTask (void *p_arg)
  914. {
  915. CPU_BOOLEAN done;
  916. OS_ERR err;
  917. OS_TMR_CALLBACK_PTR p_fnct;
  918. OS_TMR_SPOKE *p_spoke;
  919. OS_TMR *p_tmr;
  920. OS_TMR *p_tmr_next;
  921. OS_TMR_SPOKE_IX spoke;
  922. CPU_TS ts;
  923. CPU_TS ts_start;
  924. CPU_TS ts_end;
  925. p_arg = p_arg; /* Not using 'p_arg', prevent compiler warning */
  926. while (DEF_ON) {
  927. (void)OSTaskSemPend((OS_TICK )0, /* Wait for signal indicating time to update tmrs */
  928. (OS_OPT )OS_OPT_PEND_BLOCKING,
  929. (CPU_TS *)&ts,
  930. (OS_ERR *)&err);
  931. OSSchedLock(&err);
  932. ts_start = OS_TS_GET();
  933. OSTmrTickCtr++; /* Increment the current time */
  934. spoke = (OS_TMR_SPOKE_IX)(OSTmrTickCtr % OSCfg_TmrWheelSize);
  935. p_spoke = &OSCfg_TmrWheel[spoke];
  936. p_tmr = p_spoke->FirstPtr;
  937. done = DEF_FALSE;
  938. while (done == DEF_FALSE) {
  939. if (p_tmr != (OS_TMR *)0) {
  940. p_tmr_next = (OS_TMR *)p_tmr->NextPtr; /* Point to next tmr to update because current ... */
  941. /* ... timer could get unlinked from the wheel. */
  942. if (OSTmrTickCtr == p_tmr->Match) { /* Process each timer that expires */
  943. OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */
  944. if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
  945. OS_TmrLink(p_tmr,
  946. OS_OPT_LINK_PERIODIC); /* Recalculate new position of timer in wheel */
  947. } else {
  948. p_tmr->State = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */
  949. }
  950. p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available */
  951. if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
  952. (*p_fnct)((void *)p_tmr,
  953. p_tmr->CallbackPtrArg);
  954. }
  955. p_tmr = p_tmr_next; /* See if next timer matches */
  956. } else {
  957. done = DEF_TRUE;
  958. }
  959. } else {
  960. done = DEF_TRUE;
  961. }
  962. }
  963. ts_end = OS_TS_GET() - ts_start; /* Measure execution time of timer task */
  964. OSSchedUnlock(&err);
  965. if (ts_end > OSTmrTaskTimeMax) {
  966. OSTmrTaskTimeMax = ts_end;
  967. }
  968. }
  969. }
  970. #endif