You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1141 lines
44 KiB

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