os_tmr.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. /*
  2. ************************************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * TIMER MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2009, Micrium, Weston, FL
  8. * All Rights Reserved
  9. *
  10. *
  11. * File : OS_TMR.C
  12. * By : Jean J. Labrosse
  13. * Version : V2.91
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. * uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
  18. * If you plan on using uC/OS-II in a commercial product you need to contact Micriµm to properly license
  19. * its use in your product. We provide ALL the source code for your convenience and to help you experience
  20. * uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
  21. * licensing fee.
  22. ************************************************************************************************************************
  23. */
  24. #include <ucos_ii.h>
  25. /*
  26. ************************************************************************************************************************
  27. * NOTES
  28. *
  29. * 1) Your application MUST define the following #define constants:
  30. *
  31. * OS_TASK_TMR_PRIO The priority of the Timer management task
  32. * OS_TASK_TMR_STK_SIZE The size of the Timer management task's stack
  33. *
  34. * 2) You must call OSTmrSignal() to notify the Timer management task that it's time to update the timers.
  35. ************************************************************************************************************************
  36. */
  37. /*
  38. ************************************************************************************************************************
  39. * CONSTANTS
  40. ************************************************************************************************************************
  41. */
  42. #define OS_TMR_LINK_DLY 0u
  43. #define OS_TMR_LINK_PERIODIC 1u
  44. /*
  45. ************************************************************************************************************************
  46. * LOCAL PROTOTYPES
  47. ************************************************************************************************************************
  48. */
  49. #if OS_TMR_EN > 0u
  50. static OS_TMR *OSTmr_Alloc (void);
  51. static void OSTmr_Free (OS_TMR *ptmr);
  52. static void OSTmr_InitTask (void);
  53. static void OSTmr_Link (OS_TMR *ptmr, INT8U type);
  54. static void OSTmr_Unlink (OS_TMR *ptmr);
  55. static void OSTmr_Task (void *p_arg);
  56. #endif
  57. /*$PAGE*/
  58. /*
  59. ************************************************************************************************************************
  60. * CREATE A TIMER
  61. *
  62. * Description: This function is called by your application code to create a timer.
  63. *
  64. * Arguments : dly Initial delay.
  65. * If the timer is configured for ONE-SHOT mode, this is the timeout used
  66. * If the timer is configured for PERIODIC mode, this is the first timeout to wait for
  67. * before the timer starts entering periodic mode
  68. *
  69. * period The 'period' being repeated for the timer.
  70. * If you specified 'OS_TMR_OPT_PERIODIC' as an option, when the timer expires, it will
  71. * automatically restart with the same period.
  72. *
  73. * opt Specifies either:
  74. * OS_TMR_OPT_ONE_SHOT The timer counts down only once
  75. * OS_TMR_OPT_PERIODIC The timer counts down and then reloads itself
  76. *
  77. * callback Is a pointer to a callback function that will be called when the timer expires. The
  78. * callback function must be declared as follows:
  79. *
  80. * void MyCallback (OS_TMR *ptmr, void *p_arg);
  81. *
  82. * callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
  83. *
  84. * pname Is a pointer to an ASCII string that is used to name the timer. Names are useful for
  85. * debugging.
  86. *
  87. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  88. * OS_ERR_NONE
  89. * OS_ERR_TMR_INVALID_DLY you specified an invalid delay
  90. * OS_ERR_TMR_INVALID_PERIOD you specified an invalid period
  91. * OS_ERR_TMR_INVALID_OPT you specified an invalid option
  92. * OS_ERR_TMR_ISR if the call was made from an ISR
  93. * OS_ERR_TMR_NON_AVAIL if there are no free timers from the timer pool
  94. *
  95. * Returns : A pointer to an OS_TMR data structure.
  96. * This is the 'handle' that your application will use to reference the timer created.
  97. ************************************************************************************************************************
  98. */
  99. #if OS_TMR_EN > 0u
  100. OS_TMR *OSTmrCreate (INT32U dly,
  101. INT32U period,
  102. INT8U opt,
  103. OS_TMR_CALLBACK callback,
  104. void *callback_arg,
  105. INT8U *pname,
  106. INT8U *perr)
  107. {
  108. OS_TMR *ptmr;
  109. #ifdef OS_SAFETY_CRITICAL
  110. if (perr == (INT8U *)0) {
  111. OS_SAFETY_CRITICAL_EXCEPTION();
  112. }
  113. #endif
  114. #ifdef OS_SAFETY_CRITICAL_IEC61508
  115. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  116. OS_SAFETY_CRITICAL_EXCEPTION();
  117. }
  118. #endif
  119. #if OS_ARG_CHK_EN > 0u
  120. switch (opt) { /* Validate arguments */
  121. case OS_TMR_OPT_PERIODIC:
  122. if (period == 0u) {
  123. *perr = OS_ERR_TMR_INVALID_PERIOD;
  124. return ((OS_TMR *)0);
  125. }
  126. break;
  127. case OS_TMR_OPT_ONE_SHOT:
  128. if (dly == 0u) {
  129. *perr = OS_ERR_TMR_INVALID_DLY;
  130. return ((OS_TMR *)0);
  131. }
  132. break;
  133. default:
  134. *perr = OS_ERR_TMR_INVALID_OPT;
  135. return ((OS_TMR *)0);
  136. }
  137. #endif
  138. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  139. *perr = OS_ERR_TMR_ISR;
  140. return ((OS_TMR *)0);
  141. }
  142. OSSchedLock();
  143. ptmr = OSTmr_Alloc(); /* Obtain a timer from the free pool */
  144. if (ptmr == (OS_TMR *)0) {
  145. OSSchedUnlock();
  146. *perr = OS_ERR_TMR_NON_AVAIL;
  147. return ((OS_TMR *)0);
  148. }
  149. ptmr->OSTmrState = OS_TMR_STATE_STOPPED; /* Indicate that timer is not running yet */
  150. ptmr->OSTmrDly = dly;
  151. ptmr->OSTmrPeriod = period;
  152. ptmr->OSTmrOpt = opt;
  153. ptmr->OSTmrCallback = callback;
  154. ptmr->OSTmrCallbackArg = callback_arg;
  155. #if OS_TMR_CFG_NAME_EN > 0u
  156. ptmr->OSTmrName = pname;
  157. #endif
  158. OSSchedUnlock();
  159. *perr = OS_ERR_NONE;
  160. return (ptmr);
  161. }
  162. #endif
  163. /*$PAGE*/
  164. /*
  165. ************************************************************************************************************************
  166. * DELETE A TIMER
  167. *
  168. * Description: This function is called by your application code to delete a timer.
  169. *
  170. * Arguments : ptmr Is a pointer to the timer to stop and delete.
  171. *
  172. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  173. * OS_ERR_NONE
  174. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  175. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  176. * OS_ERR_TMR_ISR if the function was called from an ISR
  177. * OS_ERR_TMR_INACTIVE if the timer was not created
  178. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  179. *
  180. * Returns : OS_TRUE If the call was successful
  181. * OS_FALSE If not
  182. ************************************************************************************************************************
  183. */
  184. #if OS_TMR_EN > 0u
  185. BOOLEAN OSTmrDel (OS_TMR *ptmr,
  186. INT8U *perr)
  187. {
  188. #ifdef OS_SAFETY_CRITICAL
  189. if (perr == (INT8U *)0) {
  190. OS_SAFETY_CRITICAL_EXCEPTION();
  191. }
  192. #endif
  193. #if OS_ARG_CHK_EN > 0u
  194. if (ptmr == (OS_TMR *)0) {
  195. *perr = OS_ERR_TMR_INVALID;
  196. return (OS_FALSE);
  197. }
  198. #endif
  199. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  200. *perr = OS_ERR_TMR_INVALID_TYPE;
  201. return (OS_FALSE);
  202. }
  203. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  204. *perr = OS_ERR_TMR_ISR;
  205. return (OS_FALSE);
  206. }
  207. OSSchedLock();
  208. switch (ptmr->OSTmrState) {
  209. case OS_TMR_STATE_RUNNING:
  210. OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
  211. OSTmr_Free(ptmr); /* Return timer to free list of timers */
  212. OSSchedUnlock();
  213. *perr = OS_ERR_NONE;
  214. return (OS_TRUE);
  215. case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
  216. case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
  217. OSTmr_Free(ptmr); /* Return timer to free list of timers */
  218. OSSchedUnlock();
  219. *perr = OS_ERR_NONE;
  220. return (OS_TRUE);
  221. case OS_TMR_STATE_UNUSED: /* Already deleted */
  222. OSSchedUnlock();
  223. *perr = OS_ERR_TMR_INACTIVE;
  224. return (OS_FALSE);
  225. default:
  226. OSSchedUnlock();
  227. *perr = OS_ERR_TMR_INVALID_STATE;
  228. return (OS_FALSE);
  229. }
  230. }
  231. #endif
  232. /*$PAGE*/
  233. /*
  234. ************************************************************************************************************************
  235. * GET THE NAME OF A TIMER
  236. *
  237. * Description: This function is called to obtain the name of a timer.
  238. *
  239. * Arguments : ptmr Is a pointer to the timer to obtain the name for
  240. *
  241. * pdest Is a pointer to pointer to where the name of the timer will be placed.
  242. *
  243. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  244. * OS_ERR_NONE The call was successful
  245. * OS_ERR_TMR_INVALID_DEST 'pdest' is a NULL pointer
  246. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  247. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  248. * OS_ERR_NAME_GET_ISR if the call was made from an ISR
  249. * OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
  250. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  251. *
  252. * Returns : The length of the string or 0 if the timer does not exist.
  253. ************************************************************************************************************************
  254. */
  255. #if OS_TMR_EN > 0u && OS_TMR_CFG_NAME_EN > 0u
  256. INT8U OSTmrNameGet (OS_TMR *ptmr,
  257. INT8U **pdest,
  258. INT8U *perr)
  259. {
  260. INT8U len;
  261. #ifdef OS_SAFETY_CRITICAL
  262. if (perr == (INT8U *)0) {
  263. OS_SAFETY_CRITICAL_EXCEPTION();
  264. }
  265. #endif
  266. #if OS_ARG_CHK_EN > 0u
  267. if (pdest == (INT8U **)0) {
  268. *perr = OS_ERR_TMR_INVALID_DEST;
  269. return (0u);
  270. }
  271. if (ptmr == (OS_TMR *)0) {
  272. *perr = OS_ERR_TMR_INVALID;
  273. return (0u);
  274. }
  275. #endif
  276. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  277. *perr = OS_ERR_TMR_INVALID_TYPE;
  278. return (0u);
  279. }
  280. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  281. *perr = OS_ERR_NAME_GET_ISR;
  282. return (0u);
  283. }
  284. OSSchedLock();
  285. switch (ptmr->OSTmrState) {
  286. case OS_TMR_STATE_RUNNING:
  287. case OS_TMR_STATE_STOPPED:
  288. case OS_TMR_STATE_COMPLETED:
  289. *pdest = ptmr->OSTmrName;
  290. len = OS_StrLen(*pdest);
  291. OSSchedUnlock();
  292. *perr = OS_ERR_NONE;
  293. return (len);
  294. case OS_TMR_STATE_UNUSED: /* Timer is not allocated */
  295. OSSchedUnlock();
  296. *perr = OS_ERR_TMR_INACTIVE;
  297. return (0u);
  298. default:
  299. OSSchedUnlock();
  300. *perr = OS_ERR_TMR_INVALID_STATE;
  301. return (0u);
  302. }
  303. }
  304. #endif
  305. /*$PAGE*/
  306. /*
  307. ************************************************************************************************************************
  308. * GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
  309. *
  310. * Description: This function is called to get the number of ticks before a timer times out.
  311. *
  312. * Arguments : ptmr Is a pointer to the timer to obtain the remaining time from.
  313. *
  314. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  315. * OS_ERR_NONE
  316. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  317. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  318. * OS_ERR_TMR_ISR if the call was made from an ISR
  319. * OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
  320. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  321. *
  322. * Returns : The time remaining for the timer to expire. The time represents 'timer' increments. In other words, if
  323. * OSTmr_Task() is signaled every 1/10 of a second then the returned value represents the number of 1/10 of
  324. * a second remaining before the timer expires.
  325. ************************************************************************************************************************
  326. */
  327. #if OS_TMR_EN > 0u
  328. INT32U OSTmrRemainGet (OS_TMR *ptmr,
  329. INT8U *perr)
  330. {
  331. INT32U remain;
  332. #ifdef OS_SAFETY_CRITICAL
  333. if (perr == (INT8U *)0) {
  334. OS_SAFETY_CRITICAL_EXCEPTION();
  335. }
  336. #endif
  337. #if OS_ARG_CHK_EN > 0u
  338. if (ptmr == (OS_TMR *)0) {
  339. *perr = OS_ERR_TMR_INVALID;
  340. return (0u);
  341. }
  342. #endif
  343. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  344. *perr = OS_ERR_TMR_INVALID_TYPE;
  345. return (0u);
  346. }
  347. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  348. *perr = OS_ERR_TMR_ISR;
  349. return (0u);
  350. }
  351. OSSchedLock();
  352. switch (ptmr->OSTmrState) {
  353. case OS_TMR_STATE_RUNNING:
  354. remain = ptmr->OSTmrMatch - OSTmrTime; /* Determine how much time is left to timeout */
  355. OSSchedUnlock();
  356. *perr = OS_ERR_NONE;
  357. return (remain);
  358. case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
  359. switch (ptmr->OSTmrOpt) {
  360. case OS_TMR_OPT_PERIODIC:
  361. if (ptmr->OSTmrDly == 0u) {
  362. remain = ptmr->OSTmrPeriod;
  363. } else {
  364. remain = ptmr->OSTmrDly;
  365. }
  366. OSSchedUnlock();
  367. *perr = OS_ERR_NONE;
  368. break;
  369. case OS_TMR_OPT_ONE_SHOT:
  370. default:
  371. remain = ptmr->OSTmrDly;
  372. OSSchedUnlock();
  373. *perr = OS_ERR_NONE;
  374. break;
  375. }
  376. return (remain);
  377. case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT that timed out can be in this state */
  378. OSSchedUnlock();
  379. *perr = OS_ERR_NONE;
  380. return (0u);
  381. case OS_TMR_STATE_UNUSED:
  382. OSSchedUnlock();
  383. *perr = OS_ERR_TMR_INACTIVE;
  384. return (0u);
  385. default:
  386. OSSchedUnlock();
  387. *perr = OS_ERR_TMR_INVALID_STATE;
  388. return (0u);
  389. }
  390. }
  391. #endif
  392. /*$PAGE*/
  393. /*
  394. ************************************************************************************************************************
  395. * FIND OUT WHAT STATE A TIMER IS IN
  396. *
  397. * Description: This function is called to determine what state the timer is in:
  398. *
  399. * OS_TMR_STATE_UNUSED the timer has not been created
  400. * OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped
  401. * OS_TMR_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout
  402. * OS_TMR_RUNNING the timer is currently running
  403. *
  404. * Arguments : ptmr Is a pointer to the desired timer
  405. *
  406. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  407. * OS_ERR_NONE
  408. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  409. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  410. * OS_ERR_TMR_ISR if the call was made from an ISR
  411. * OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
  412. * OS_ERR_TMR_INVALID_STATE if the timer is not in a valid state
  413. *
  414. * Returns : The current state of the timer (see description).
  415. ************************************************************************************************************************
  416. */
  417. #if OS_TMR_EN > 0u
  418. INT8U OSTmrStateGet (OS_TMR *ptmr,
  419. INT8U *perr)
  420. {
  421. INT8U state;
  422. #ifdef OS_SAFETY_CRITICAL
  423. if (perr == (INT8U *)0) {
  424. OS_SAFETY_CRITICAL_EXCEPTION();
  425. }
  426. #endif
  427. #if OS_ARG_CHK_EN > 0u
  428. if (ptmr == (OS_TMR *)0) {
  429. *perr = OS_ERR_TMR_INVALID;
  430. return (0u);
  431. }
  432. #endif
  433. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  434. *perr = OS_ERR_TMR_INVALID_TYPE;
  435. return (0u);
  436. }
  437. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  438. *perr = OS_ERR_TMR_ISR;
  439. return (0u);
  440. }
  441. OSSchedLock();
  442. state = ptmr->OSTmrState;
  443. switch (state) {
  444. case OS_TMR_STATE_UNUSED:
  445. case OS_TMR_STATE_STOPPED:
  446. case OS_TMR_STATE_COMPLETED:
  447. case OS_TMR_STATE_RUNNING:
  448. *perr = OS_ERR_NONE;
  449. break;
  450. default:
  451. *perr = OS_ERR_TMR_INVALID_STATE;
  452. break;
  453. }
  454. OSSchedUnlock();
  455. return (state);
  456. }
  457. #endif
  458. /*$PAGE*/
  459. /*
  460. ************************************************************************************************************************
  461. * START A TIMER
  462. *
  463. * Description: This function is called by your application code to start a timer.
  464. *
  465. * Arguments : ptmr Is a pointer to an OS_TMR
  466. *
  467. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  468. * OS_ERR_NONE
  469. * OS_ERR_TMR_INVALID
  470. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  471. * OS_ERR_TMR_ISR if the call was made from an ISR
  472. * OS_ERR_TMR_INACTIVE if the timer was not created
  473. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  474. *
  475. * Returns : OS_TRUE if the timer was started
  476. * OS_FALSE if an error was detected
  477. ************************************************************************************************************************
  478. */
  479. #if OS_TMR_EN > 0u
  480. BOOLEAN OSTmrStart (OS_TMR *ptmr,
  481. INT8U *perr)
  482. {
  483. #ifdef OS_SAFETY_CRITICAL
  484. if (perr == (INT8U *)0) {
  485. OS_SAFETY_CRITICAL_EXCEPTION();
  486. }
  487. #endif
  488. #if OS_ARG_CHK_EN > 0u
  489. if (ptmr == (OS_TMR *)0) {
  490. *perr = OS_ERR_TMR_INVALID;
  491. return (OS_FALSE);
  492. }
  493. #endif
  494. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  495. *perr = OS_ERR_TMR_INVALID_TYPE;
  496. return (OS_FALSE);
  497. }
  498. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  499. *perr = OS_ERR_TMR_ISR;
  500. return (OS_FALSE);
  501. }
  502. OSSchedLock();
  503. switch (ptmr->OSTmrState) {
  504. case OS_TMR_STATE_RUNNING: /* Restart the timer */
  505. OSTmr_Unlink(ptmr); /* ... Stop the timer */
  506. OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */
  507. OSSchedUnlock();
  508. *perr = OS_ERR_NONE;
  509. return (OS_TRUE);
  510. case OS_TMR_STATE_STOPPED: /* Start the timer */
  511. case OS_TMR_STATE_COMPLETED:
  512. OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */
  513. OSSchedUnlock();
  514. *perr = OS_ERR_NONE;
  515. return (OS_TRUE);
  516. case OS_TMR_STATE_UNUSED: /* Timer not created */
  517. OSSchedUnlock();
  518. *perr = OS_ERR_TMR_INACTIVE;
  519. return (OS_FALSE);
  520. default:
  521. OSSchedUnlock();
  522. *perr = OS_ERR_TMR_INVALID_STATE;
  523. return (OS_FALSE);
  524. }
  525. }
  526. #endif
  527. /*$PAGE*/
  528. /*
  529. ************************************************************************************************************************
  530. * STOP A TIMER
  531. *
  532. * Description: This function is called by your application code to stop a timer.
  533. *
  534. * Arguments : ptmr Is a pointer to the timer to stop.
  535. *
  536. * opt Allows you to specify an option to this functions which can be:
  537. *
  538. * OS_TMR_OPT_NONE Do nothing special but stop the timer
  539. * OS_TMR_OPT_CALLBACK Execute the callback function, pass it the callback argument
  540. * specified when the timer was created.
  541. * OS_TMR_OPT_CALLBACK_ARG Execute the callback function, pass it the callback argument
  542. * specified in THIS function call
  543. *
  544. * callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function
  545. * instead of the timer's callback argument. In other words, use 'callback_arg' passed in
  546. * THIS function INSTEAD of ptmr->OSTmrCallbackArg
  547. *
  548. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  549. * OS_ERR_NONE
  550. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  551. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  552. * OS_ERR_TMR_ISR if the function was called from an ISR
  553. * OS_ERR_TMR_INACTIVE if the timer was not created
  554. * OS_ERR_TMR_INVALID_OPT if you specified an invalid option for 'opt'
  555. * OS_ERR_TMR_STOPPED if the timer was already stopped
  556. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  557. * OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined
  558. *
  559. * Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE)
  560. * OS_FALSE If not
  561. ************************************************************************************************************************
  562. */
  563. #if OS_TMR_EN > 0u
  564. BOOLEAN OSTmrStop (OS_TMR *ptmr,
  565. INT8U opt,
  566. void *callback_arg,
  567. INT8U *perr)
  568. {
  569. OS_TMR_CALLBACK pfnct;
  570. #ifdef OS_SAFETY_CRITICAL
  571. if (perr == (INT8U *)0) {
  572. OS_SAFETY_CRITICAL_EXCEPTION();
  573. }
  574. #endif
  575. #if OS_ARG_CHK_EN > 0u
  576. if (ptmr == (OS_TMR *)0) {
  577. *perr = OS_ERR_TMR_INVALID;
  578. return (OS_FALSE);
  579. }
  580. #endif
  581. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  582. *perr = OS_ERR_TMR_INVALID_TYPE;
  583. return (OS_FALSE);
  584. }
  585. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  586. *perr = OS_ERR_TMR_ISR;
  587. return (OS_FALSE);
  588. }
  589. OSSchedLock();
  590. switch (ptmr->OSTmrState) {
  591. case OS_TMR_STATE_RUNNING:
  592. OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
  593. *perr = OS_ERR_NONE;
  594. switch (opt) {
  595. case OS_TMR_OPT_CALLBACK:
  596. pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */
  597. if (pfnct != (OS_TMR_CALLBACK)0) {
  598. (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg); /* Use callback arg when timer was created */
  599. } else {
  600. *perr = OS_ERR_TMR_NO_CALLBACK;
  601. }
  602. break;
  603. case OS_TMR_OPT_CALLBACK_ARG:
  604. pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */
  605. if (pfnct != (OS_TMR_CALLBACK)0) {
  606. (*pfnct)((void *)ptmr, callback_arg); /* ... using the 'callback_arg' provided in call */
  607. } else {
  608. *perr = OS_ERR_TMR_NO_CALLBACK;
  609. }
  610. break;
  611. case OS_TMR_OPT_NONE:
  612. break;
  613. default:
  614. *perr = OS_ERR_TMR_INVALID_OPT;
  615. break;
  616. }
  617. OSSchedUnlock();
  618. return (OS_TRUE);
  619. case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or ... */
  620. case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
  621. OSSchedUnlock();
  622. *perr = OS_ERR_TMR_STOPPED;
  623. return (OS_TRUE);
  624. case OS_TMR_STATE_UNUSED: /* Timer was not created */
  625. OSSchedUnlock();
  626. *perr = OS_ERR_TMR_INACTIVE;
  627. return (OS_FALSE);
  628. default:
  629. OSSchedUnlock();
  630. *perr = OS_ERR_TMR_INVALID_STATE;
  631. return (OS_FALSE);
  632. }
  633. }
  634. #endif
  635. /*$PAGE*/
  636. /*
  637. ************************************************************************************************************************
  638. * SIGNAL THAT IT'S TIME TO UPDATE THE TIMERS
  639. *
  640. * Description: This function is typically called by the ISR that occurs at the timer tick rate and is used to signal to
  641. * OSTmr_Task() that it's time to update the timers.
  642. *
  643. * Arguments : none
  644. *
  645. * Returns : OS_ERR_NONE The call was successful and the timer task was signaled.
  646. * OS_ERR_SEM_OVF If OSTmrSignal() was called more often than OSTmr_Task() can handle the timers.
  647. * This would indicate that your system is heavily loaded.
  648. * OS_ERR_EVENT_TYPE Unlikely you would get this error because the semaphore used for signaling is created
  649. * by uC/OS-II.
  650. * OS_ERR_PEVENT_NULL Again, unlikely you would ever get this error because the semaphore used for signaling
  651. * is created by uC/OS-II.
  652. ************************************************************************************************************************
  653. */
  654. #if OS_TMR_EN > 0u
  655. INT8U OSTmrSignal (void)
  656. {
  657. INT8U err;
  658. err = OSSemPost(OSTmrSemSignal);
  659. return (err);
  660. }
  661. #endif
  662. /*$PAGE*/
  663. /*
  664. ************************************************************************************************************************
  665. * ALLOCATE AND FREE A TIMER
  666. *
  667. * Description: This function is called to allocate a timer.
  668. *
  669. * Arguments : none
  670. *
  671. * Returns : a pointer to a timer if one is available
  672. ************************************************************************************************************************
  673. */
  674. #if OS_TMR_EN > 0u
  675. static OS_TMR *OSTmr_Alloc (void)
  676. {
  677. OS_TMR *ptmr;
  678. if (OSTmrFreeList == (OS_TMR *)0) {
  679. return ((OS_TMR *)0);
  680. }
  681. ptmr = (OS_TMR *)OSTmrFreeList;
  682. OSTmrFreeList = (OS_TMR *)ptmr->OSTmrNext;
  683. ptmr->OSTmrNext = (OS_TCB *)0;
  684. ptmr->OSTmrPrev = (OS_TCB *)0;
  685. OSTmrUsed++;
  686. OSTmrFree--;
  687. return (ptmr);
  688. }
  689. #endif
  690. /*
  691. ************************************************************************************************************************
  692. * RETURN A TIMER TO THE FREE LIST
  693. *
  694. * Description: This function is called to return a timer object to the free list of timers.
  695. *
  696. * Arguments : ptmr is a pointer to the timer to free
  697. *
  698. * Returns : none
  699. ************************************************************************************************************************
  700. */
  701. #if OS_TMR_EN > 0u
  702. static void OSTmr_Free (OS_TMR *ptmr)
  703. {
  704. ptmr->OSTmrState = OS_TMR_STATE_UNUSED; /* Clear timer object fields */
  705. ptmr->OSTmrOpt = OS_TMR_OPT_NONE;
  706. ptmr->OSTmrPeriod = 0u;
  707. ptmr->OSTmrMatch = 0u;
  708. ptmr->OSTmrCallback = (OS_TMR_CALLBACK)0;
  709. ptmr->OSTmrCallbackArg = (void *)0;
  710. #if OS_TMR_CFG_NAME_EN > 0u
  711. ptmr->OSTmrName = (INT8U *)(void *)"?";
  712. #endif
  713. ptmr->OSTmrPrev = (OS_TCB *)0; /* Chain timer to free list */
  714. ptmr->OSTmrNext = OSTmrFreeList;
  715. OSTmrFreeList = ptmr;
  716. OSTmrUsed--; /* Update timer object statistics */
  717. OSTmrFree++;
  718. }
  719. #endif
  720. /*$PAGE*/
  721. /*
  722. ************************************************************************************************************************
  723. * INITIALIZATION
  724. * INITIALIZE THE FREE LIST OF TIMERS
  725. *
  726. * Description: This function is called by OSInit() to initialize the free list of OS_TMRs.
  727. *
  728. * Arguments : none
  729. *
  730. * Returns : none
  731. ************************************************************************************************************************
  732. */
  733. #if OS_TMR_EN > 0u
  734. void OSTmr_Init (void)
  735. {
  736. #if OS_EVENT_NAME_EN > 0u
  737. INT8U err;
  738. #endif
  739. INT16U ix;
  740. INT16U ix_next;
  741. OS_TMR *ptmr1;
  742. OS_TMR *ptmr2;
  743. OS_MemClr((INT8U *)&OSTmrTbl[0], sizeof(OSTmrTbl)); /* Clear all the TMRs */
  744. OS_MemClr((INT8U *)&OSTmrWheelTbl[0], sizeof(OSTmrWheelTbl)); /* Clear the timer wheel */
  745. for (ix = 0u; ix < (OS_TMR_CFG_MAX - 1u); ix++) { /* Init. list of free TMRs */
  746. ix_next = ix + 1u;
  747. ptmr1 = &OSTmrTbl[ix];
  748. ptmr2 = &OSTmrTbl[ix_next];
  749. ptmr1->OSTmrType = OS_TMR_TYPE;
  750. ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */
  751. ptmr1->OSTmrNext = (void *)ptmr2; /* Link to next timer */
  752. #if OS_TMR_CFG_NAME_EN > 0u
  753. ptmr1->OSTmrName = (INT8U *)(void *)"?";
  754. #endif
  755. }
  756. ptmr1 = &OSTmrTbl[ix];
  757. ptmr1->OSTmrType = OS_TMR_TYPE;
  758. ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */
  759. ptmr1->OSTmrNext = (void *)0; /* Last OS_TMR */
  760. #if OS_TMR_CFG_NAME_EN > 0u
  761. ptmr1->OSTmrName = (INT8U *)(void *)"?";
  762. #endif
  763. OSTmrTime = 0u;
  764. OSTmrUsed = 0u;
  765. OSTmrFree = OS_TMR_CFG_MAX;
  766. OSTmrFreeList = &OSTmrTbl[0];
  767. OSTmrSem = OSSemCreate(1u);
  768. OSTmrSemSignal = OSSemCreate(0u);
  769. #if OS_EVENT_NAME_EN > 0u /* Assign names to semaphores */
  770. OSEventNameSet(OSTmrSem, (INT8U *)(void *)"uC/OS-II TmrLock", &err);
  771. OSEventNameSet(OSTmrSemSignal, (INT8U *)(void *)"uC/OS-II TmrSignal", &err);
  772. #endif
  773. OSTmr_InitTask();
  774. }
  775. #endif
  776. /*$PAGE*/
  777. /*
  778. ************************************************************************************************************************
  779. * INITIALIZE THE TIMER MANAGEMENT TASK
  780. *
  781. * Description: This function is called by OSTmrInit() to create the timer management task.
  782. * * Arguments : none
  783. *
  784. * Returns : none
  785. ************************************************************************************************************************
  786. */
  787. #if OS_TMR_EN > 0u
  788. static void OSTmr_InitTask (void)
  789. {
  790. #if OS_TASK_NAME_EN > 0u
  791. INT8U err;
  792. #endif
  793. #if OS_TASK_CREATE_EXT_EN > 0u
  794. #if OS_STK_GROWTH == 1u
  795. (void)OSTaskCreateExt(OSTmr_Task,
  796. (void *)0, /* No arguments passed to OSTmrTask() */
  797. &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Top-Of-Stack */
  798. OS_TASK_TMR_PRIO,
  799. OS_TASK_TMR_ID,
  800. &OSTmrTaskStk[0], /* Set Bottom-Of-Stack */
  801. OS_TASK_TMR_STK_SIZE,
  802. (void *)0, /* No TCB extension */
  803. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */
  804. #else
  805. (void)OSTaskCreateExt(OSTmr_Task,
  806. (void *)0, /* No arguments passed to OSTmrTask() */
  807. &OSTmrTaskStk[0], /* Set Top-Of-Stack */
  808. OS_TASK_TMR_PRIO,
  809. OS_TASK_TMR_ID,
  810. &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Bottom-Of-Stack */
  811. OS_TASK_TMR_STK_SIZE,
  812. (void *)0, /* No TCB extension */
  813. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */
  814. #endif
  815. #else
  816. #if OS_STK_GROWTH == 1u
  817. (void)OSTaskCreate(OSTmr_Task,
  818. (void *)0,
  819. &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u],
  820. OS_TASK_TMR_PRIO);
  821. #else
  822. (void)OSTaskCreate(OSTmr_Task,
  823. (void *)0,
  824. &OSTmrTaskStk[0],
  825. OS_TASK_TMR_PRIO);
  826. #endif
  827. #endif
  828. #if OS_TASK_NAME_EN > 0u
  829. OSTaskNameSet(OS_TASK_TMR_PRIO, (INT8U *)(void *)"uC/OS-II Tmr", &err);
  830. #endif
  831. }
  832. #endif
  833. /*$PAGE*/
  834. /*
  835. ************************************************************************************************************************
  836. * INSERT A TIMER INTO THE TIMER WHEEL
  837. *
  838. * Description: This function is called to insert the timer into the timer wheel. The timer is always inserted at the
  839. * beginning of the list.
  840. *
  841. * Arguments : ptmr Is a pointer to the timer to insert.
  842. *
  843. * type Is either:
  844. * OS_TMR_LINK_PERIODIC Means to re-insert the timer after a period expired
  845. * OS_TMR_LINK_DLY Means to insert the timer the first time
  846. *
  847. * Returns : none
  848. ************************************************************************************************************************
  849. */
  850. #if OS_TMR_EN > 0u
  851. static void OSTmr_Link (OS_TMR *ptmr,
  852. INT8U type)
  853. {
  854. OS_TMR *ptmr1;
  855. OS_TMR_WHEEL *pspoke;
  856. INT16U spoke;
  857. ptmr->OSTmrState = OS_TMR_STATE_RUNNING;
  858. if (type == OS_TMR_LINK_PERIODIC) { /* Determine when timer will expire */
  859. ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
  860. } else {
  861. if (ptmr->OSTmrDly == 0u) {
  862. ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
  863. } else {
  864. ptmr->OSTmrMatch = ptmr->OSTmrDly + OSTmrTime;
  865. }
  866. }
  867. spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
  868. pspoke = &OSTmrWheelTbl[spoke];
  869. if (pspoke->OSTmrFirst == (OS_TMR *)0) { /* Link into timer wheel */
  870. pspoke->OSTmrFirst = ptmr;
  871. ptmr->OSTmrNext = (OS_TMR *)0;
  872. pspoke->OSTmrEntries = 1u;
  873. } else {
  874. ptmr1 = pspoke->OSTmrFirst; /* Point to first timer in the spoke */
  875. pspoke->OSTmrFirst = ptmr;
  876. ptmr->OSTmrNext = (void *)ptmr1;
  877. ptmr1->OSTmrPrev = (void *)ptmr;
  878. pspoke->OSTmrEntries++;
  879. }
  880. ptmr->OSTmrPrev = (void *)0; /* Timer always inserted as first node in list */
  881. }
  882. #endif
  883. /*$PAGE*/
  884. /*
  885. ************************************************************************************************************************
  886. * REMOVE A TIMER FROM THE TIMER WHEEL
  887. *
  888. * Description: This function is called to remove the timer from the timer wheel.
  889. *
  890. * Arguments : ptmr Is a pointer to the timer to remove.
  891. *
  892. * Returns : none
  893. ************************************************************************************************************************
  894. */
  895. #if OS_TMR_EN > 0u
  896. static void OSTmr_Unlink (OS_TMR *ptmr)
  897. {
  898. OS_TMR *ptmr1;
  899. OS_TMR *ptmr2;
  900. OS_TMR_WHEEL *pspoke;
  901. INT16U spoke;
  902. spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
  903. pspoke = &OSTmrWheelTbl[spoke];
  904. if (pspoke->OSTmrFirst == ptmr) { /* See if timer to remove is at the beginning of list */
  905. ptmr1 = (OS_TMR *)ptmr->OSTmrNext;
  906. pspoke->OSTmrFirst = (OS_TMR *)ptmr1;
  907. if (ptmr1 != (OS_TMR *)0) {
  908. ptmr1->OSTmrPrev = (void *)0;
  909. }
  910. } else {
  911. ptmr1 = (OS_TMR *)ptmr->OSTmrPrev; /* Remove timer from somewhere in the list */
  912. ptmr2 = (OS_TMR *)ptmr->OSTmrNext;
  913. ptmr1->OSTmrNext = ptmr2;
  914. if (ptmr2 != (OS_TMR *)0) {
  915. ptmr2->OSTmrPrev = (void *)ptmr1;
  916. }
  917. }
  918. ptmr->OSTmrState = OS_TMR_STATE_STOPPED;
  919. ptmr->OSTmrNext = (void *)0;
  920. ptmr->OSTmrPrev = (void *)0;
  921. pspoke->OSTmrEntries--;
  922. }
  923. #endif
  924. /*$PAGE*/
  925. /*
  926. ************************************************************************************************************************
  927. * TIMER MANAGEMENT TASK
  928. *
  929. * Description: This task is created by OSTmrInit().
  930. *
  931. * Arguments : none
  932. *
  933. * Returns : none
  934. ************************************************************************************************************************
  935. */
  936. #if OS_TMR_EN > 0u
  937. static void OSTmr_Task (void *p_arg)
  938. {
  939. INT8U err;
  940. OS_TMR *ptmr;
  941. OS_TMR *ptmr_next;
  942. OS_TMR_CALLBACK pfnct;
  943. OS_TMR_WHEEL *pspoke;
  944. INT16U spoke;
  945. p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
  946. for (;;) {
  947. OSSemPend(OSTmrSemSignal, 0u, &err); /* Wait for signal indicating time to update timers */
  948. OSSchedLock();
  949. OSTmrTime++; /* Increment the current time */
  950. spoke = (INT16U)(OSTmrTime % OS_TMR_CFG_WHEEL_SIZE); /* Position on current timer wheel entry */
  951. pspoke = &OSTmrWheelTbl[spoke];
  952. ptmr = pspoke->OSTmrFirst;
  953. while (ptmr != (OS_TMR *)0) {
  954. ptmr_next = (OS_TMR *)ptmr->OSTmrNext; /* Point to next timer to update because current ... */
  955. /* ... timer could get unlinked from the wheel. */
  956. if (OSTmrTime == ptmr->OSTmrMatch) { /* Process each timer that expires */
  957. OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
  958. if (ptmr->OSTmrOpt == OS_TMR_OPT_PERIODIC) {
  959. OSTmr_Link(ptmr, OS_TMR_LINK_PERIODIC); /* Recalculate new position of timer in wheel */
  960. } else {
  961. ptmr->OSTmrState = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */
  962. }
  963. pfnct = ptmr->OSTmrCallback; /* Execute callback function if available */
  964. if (pfnct != (OS_TMR_CALLBACK)0) {
  965. (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg);
  966. }
  967. }
  968. ptmr = ptmr_next;
  969. }
  970. OSSchedUnlock();
  971. }
  972. }
  973. #endif