timers.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. /*
  2. * FreeRTOS Kernel V10.5.1
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * SPDX-License-Identifier: MIT
  6. *
  7. */
  8. /* Standard includes. */
  9. #include <stdlib.h>
  10. /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
  11. * all the API functions to use the MPU wrappers. That should only be done when
  12. * task.h is included from an application file. */
  13. #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
  14. #include "FreeRTOS.h"
  15. #include "task.h"
  16. #include "queue.h"
  17. #include "timers.h"
  18. #if (INCLUDE_xTimerPendFunctionCall == 1) && (configUSE_TIMERS == 0)
  19. #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available.
  20. #endif
  21. /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
  22. * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
  23. * for the header files above, but not in this file, in order to generate the
  24. * correct privileged Vs unprivileged linkage and placement. */
  25. #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */
  26. /* This entire source file will be skipped if the application is not configured
  27. * to include software timer functionality. This #if is closed at the very bottom
  28. * of this file. If you want to include software timer functionality then ensure
  29. * configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
  30. #if (configUSE_TIMERS == 1)
  31. /* Misc definitions. */
  32. #define tmrNO_DELAY ((TickType_t)0U)
  33. #define tmrMAX_TIME_BEFORE_OVERFLOW ((TickType_t)-1)
  34. /* The name assigned to the timer service task. This can be overridden by
  35. * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
  36. #ifndef configTIMER_SERVICE_TASK_NAME
  37. #define configTIMER_SERVICE_TASK_NAME "Tmr Svc"
  38. #endif
  39. /* Bit definitions used in the ucStatus member of a timer structure. */
  40. #define tmrSTATUS_IS_ACTIVE ((uint8_t)0x01)
  41. #define tmrSTATUS_IS_STATICALLY_ALLOCATED ((uint8_t)0x02)
  42. #define tmrSTATUS_IS_AUTORELOAD ((uint8_t)0x04)
  43. /**
  44. * 定时器节点管理结构
  45. */
  46. typedef struct tmrTimerControl
  47. {
  48. const char * pcTimerName; /* 定时器节点名字 */
  49. ListItem_t xTimerListItem; /* 插入链表的节点信息 */
  50. TickType_t xTimerPeriodInTicks; /* 定时器超时时钟数 */
  51. void * pvTimerID; /* 定时器ID */
  52. TimerCallbackFunction_t pxCallbackFunction; /* 超时后的回调函数 */
  53. #if (configUSE_TRACE_FACILITY == 1)
  54. UBaseType_t uxTimerNumber; /* trace ID */
  55. #endif
  56. uint8_t ucStatus; /* 定时器的状态 */
  57. } xTIMER;
  58. /* The old xTIMER name is maintained above then typedefed to the new Timer_t
  59. * name below to enable the use of older kernel aware debuggers. */
  60. typedef xTIMER Timer_t;
  61. /* The definition of messages that can be sent and received on the timer queue.
  62. * Two types of message can be queued - messages that manipulate a software timer,
  63. * and messages that request the execution of a non-timer related callback. The
  64. * two message types are defined in two separate structures, xTimerParametersType
  65. * and xCallbackParametersType respectively.
  66. */
  67. typedef struct tmrTimerParameters
  68. {
  69. TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
  70. Timer_t * pxTimer; /*<< The timer to which the command will be applied. */
  71. } TimerParameter_t;
  72. typedef struct tmrCallbackParameters
  73. {
  74. PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */
  75. void * pvParameter1; /* << The value that will be used as the callback functions first parameter. */
  76. uint32_t ulParameter2; /* << The value that will be used as the callback functions second parameter. */
  77. } CallbackParameters_t;
  78. /**
  79. * The structure that contains the two message types, along with an identifier
  80. * that is used to determine which message type is valid.
  81. * 向定时器队列发送消息管理结构
  82. */
  83. typedef struct tmrTimerQueueMessage
  84. {
  85. BaseType_t xMessageID; /*<< The command being sent to the timer service task. */
  86. union
  87. {
  88. TimerParameter_t xTimerParameters;
  89. /* Don't include xCallbackParameters if it is not going to be used as
  90. * it makes the structure (and therefore the timer queue) larger. */
  91. #if (INCLUDE_xTimerPendFunctionCall == 1)
  92. CallbackParameters_t xCallbackParameters;
  93. #endif /* INCLUDE_xTimerPendFunctionCall */
  94. } u;
  95. } DaemonTaskMessage_t;
  96. /* The list in which active timers are stored. Timers are referenced in expire
  97. * time order, with the nearest expiry time at the front of the list. Only the
  98. * timer service task is allowed to access these lists.
  99. * xActiveTimerList1 and xActiveTimerList2 could be at function scope but that
  100. * breaks some kernel aware debuggers, and debuggers that reply on removing the
  101. * static qualifier. */
  102. PRIVILEGED_DATA static List_t xActiveTimerList1;
  103. PRIVILEGED_DATA static List_t xActiveTimerList2;
  104. PRIVILEGED_DATA static List_t * pxCurrentTimerList;
  105. PRIVILEGED_DATA static List_t * pxOverflowTimerList;
  106. /* A queue that is used to send commands to the timer service task. */
  107. PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
  108. PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
  109. /*
  110. * Initialise the infrastructure used by the timer service task if it has not
  111. * been initialised already.
  112. */
  113. static void prvCheckForValidListAndQueue(void) PRIVILEGED_FUNCTION;
  114. /*
  115. * The timer service task (daemon). Timer functionality is controlled by this
  116. * task. Other tasks communicate with the timer service task using the
  117. * xTimerQueue queue.
  118. */
  119. static portTASK_FUNCTION_PROTO(prvTimerTask, pvParameters) PRIVILEGED_FUNCTION;
  120. /*
  121. * Called by the timer service task to interpret and process a command it
  122. * received on the timer queue.
  123. */
  124. static void prvProcessReceivedCommands(void) PRIVILEGED_FUNCTION;
  125. /*
  126. * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
  127. * depending on if the expire time causes a timer counter overflow.
  128. */
  129. static BaseType_t prvInsertTimerInActiveList(Timer_t * const pxTimer,
  130. const TickType_t xNextExpiryTime,
  131. const TickType_t xTimeNow,
  132. const TickType_t xCommandTime) PRIVILEGED_FUNCTION;
  133. /*
  134. * Reload the specified auto-reload timer. If the reloading is backlogged,
  135. * clear the backlog, calling the callback for each additional reload. When
  136. * this function returns, the next expiry time is after xTimeNow.
  137. */
  138. static void prvReloadTimer(Timer_t * const pxTimer,
  139. TickType_t xExpiredTime,
  140. const TickType_t xTimeNow) PRIVILEGED_FUNCTION;
  141. /*
  142. * An active timer has reached its expire time. Reload the timer if it is an
  143. * auto-reload timer, then call its callback.
  144. */
  145. static void prvProcessExpiredTimer(const TickType_t xNextExpireTime,
  146. const TickType_t xTimeNow) PRIVILEGED_FUNCTION;
  147. /*
  148. * The tick count has overflowed. Switch the timer lists after ensuring the
  149. * current timer list does not still reference some timers.
  150. */
  151. static void prvSwitchTimerLists(void) PRIVILEGED_FUNCTION;
  152. /*
  153. * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
  154. * if a tick count overflow occurred since prvSampleTimeNow() was last called.
  155. */
  156. static TickType_t prvSampleTimeNow(BaseType_t * const pxTimerListsWereSwitched) PRIVILEGED_FUNCTION;
  157. /*
  158. * If the timer list contains any active timers then return the expire time of
  159. * the timer that will expire first and set *pxListWasEmpty to false. If the
  160. * timer list does not contain any timers then return 0 and set *pxListWasEmpty
  161. * to pdTRUE.
  162. */
  163. static TickType_t prvGetNextExpireTime(BaseType_t * const pxListWasEmpty) PRIVILEGED_FUNCTION;
  164. /*
  165. * If a timer has expired, process it. Otherwise, block the timer service task
  166. * until either a timer does expire or a command is received.
  167. */
  168. static void prvProcessTimerOrBlockTask(const TickType_t xNextExpireTime,
  169. BaseType_t xListWasEmpty) PRIVILEGED_FUNCTION;
  170. /*
  171. * Called after a Timer_t structure has been allocated either statically or
  172. * dynamically to fill in the structure's members.
  173. */
  174. static void prvInitialiseNewTimer(const char * const pcTimerName,
  175. const TickType_t xTimerPeriodInTicks,
  176. const BaseType_t xAutoReload,
  177. void * const pvTimerID,
  178. TimerCallbackFunction_t pxCallbackFunction,
  179. Timer_t * pxNewTimer) PRIVILEGED_FUNCTION;
  180. /**
  181. * 创建处理软件定时器的任务
  182. */
  183. BaseType_t xTimerCreateTimerTask(void)
  184. {
  185. BaseType_t xReturn = pdFAIL;
  186. /* This function is called when the scheduler is started if
  187. * configUSE_TIMERS is set to 1. Check that the infrastructure used by the
  188. * timer service task has been created/initialised. If timers have already
  189. * been created then the initialisation will already have been performed. */
  190. prvCheckForValidListAndQueue();
  191. if (xTimerQueue != NULL)
  192. {
  193. /* 创建处理软件定时器的任务 */
  194. xReturn = xTaskCreate(prvTimerTask,
  195. configTIMER_SERVICE_TASK_NAME, /* 任务名称 */
  196. configTIMER_TASK_STACK_DEPTH, /* 堆栈大小 */
  197. NULL,
  198. ((UBaseType_t) configTIMER_TASK_PRIORITY) | portPRIVILEGE_BIT, /* 优先级 */
  199. &xTimerTaskHandle);
  200. }
  201. configASSERT(xReturn);
  202. return xReturn;
  203. }
  204. /**
  205. * 创建软件定时器
  206. * @xAutoReload: 是否为周期性定时器
  207. */
  208. TimerHandle_t xTimerCreate(const char *const pcTimerName,
  209. const TickType_t xTimerPeriodInTicks,
  210. const BaseType_t xAutoReload,
  211. void * const pvTimerID,
  212. TimerCallbackFunction_t pxCallbackFunction)
  213. {
  214. Timer_t * pxNewTimer;
  215. pxNewTimer = (Timer_t *)pvPortMalloc(sizeof(Timer_t));
  216. if (pxNewTimer != NULL)
  217. {
  218. /* Status is thus far zero as the timer is not created statically
  219. * and has not been started. The auto-reload bit may get set in
  220. * prvInitialiseNewTimer. */
  221. pxNewTimer->ucStatus = 0x00;
  222. prvInitialiseNewTimer(pcTimerName,
  223. xTimerPeriodInTicks,
  224. xAutoReload,
  225. pvTimerID,
  226. pxCallbackFunction,
  227. pxNewTimer);
  228. }
  229. return pxNewTimer;
  230. }
  231. /**
  232. * 设置软件定时器
  233. * @pcTimerName: 定期器的名字
  234. * @xTimerPeriodInTicks: 定时器超时时钟数
  235. * @xAutoReload: 是否为周期性定时器
  236. * @pxCallbackFunction: 定时器超时执行函数
  237. */
  238. static void prvInitialiseNewTimer(const char * const pcTimerName,
  239. const TickType_t xTimerPeriodInTicks,
  240. const BaseType_t xAutoReload,
  241. void * const pvTimerID,
  242. TimerCallbackFunction_t pxCallbackFunction,
  243. Timer_t * pxNewTimer)
  244. {
  245. configASSERT((xTimerPeriodInTicks > 0));
  246. prvCheckForValidListAndQueue();
  247. pxNewTimer->pcTimerName = pcTimerName;
  248. pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
  249. pxNewTimer->pvTimerID = pvTimerID;
  250. pxNewTimer->pxCallbackFunction = pxCallbackFunction;
  251. vListInitialiseItem(&(pxNewTimer->xTimerListItem));
  252. if (xAutoReload != pdFALSE)
  253. {
  254. pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
  255. }
  256. traceTIMER_CREATE(pxNewTimer);
  257. }
  258. /**
  259. * 向软件定时器消息队列发送命令
  260. */
  261. BaseType_t xTimerGenericCommand(TimerHandle_t xTimer,
  262. const BaseType_t xCommandID,
  263. const TickType_t xOptionalValue,
  264. BaseType_t * const pxHigherPriorityTaskWoken,
  265. const TickType_t xTicksToWait)
  266. {
  267. BaseType_t xReturn = pdFAIL;
  268. DaemonTaskMessage_t xMessage;
  269. configASSERT(xTimer);
  270. /* Send a message to the timer service task to perform a particular action
  271. * on a particular timer definition. */
  272. if (xTimerQueue != NULL)
  273. {
  274. /* Send a command to the timer service task to start the xTimer timer. */
  275. xMessage.xMessageID = xCommandID;
  276. xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
  277. xMessage.u.xTimerParameters.pxTimer = xTimer;
  278. if (xCommandID < tmrFIRST_FROM_ISR_COMMAND)
  279. {
  280. if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
  281. {
  282. xReturn = xQueueSendToBack(xTimerQueue, &xMessage, xTicksToWait);
  283. }
  284. else
  285. {
  286. xReturn = xQueueSendToBack(xTimerQueue, &xMessage, tmrNO_DELAY);
  287. }
  288. }
  289. else
  290. {
  291. xReturn = xQueueSendToBackFromISR(xTimerQueue, &xMessage, pxHigherPriorityTaskWoken);
  292. }
  293. traceTIMER_COMMAND_SEND(xTimer, xCommandID, xOptionalValue, xReturn);
  294. }
  295. return xReturn;
  296. }
  297. TaskHandle_t xTimerGetTimerDaemonTaskHandle(void)
  298. {
  299. /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
  300. * started, then xTimerTaskHandle will be NULL.
  301. */
  302. configASSERT((xTimerTaskHandle != NULL));
  303. return xTimerTaskHandle;
  304. }
  305. TickType_t xTimerGetPeriod(TimerHandle_t xTimer)
  306. {
  307. Timer_t * pxTimer = xTimer;
  308. configASSERT(xTimer);
  309. return pxTimer->xTimerPeriodInTicks;
  310. }
  311. /**
  312. * 设置timer为周期性触发定时器
  313. */
  314. void vTimerSetReloadMode(TimerHandle_t xTimer, const BaseType_t xAutoReload)
  315. {
  316. Timer_t * pxTimer = xTimer;
  317. configASSERT(xTimer);
  318. taskENTER_CRITICAL();
  319. {
  320. if (xAutoReload != pdFALSE)
  321. {
  322. pxTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
  323. }
  324. else
  325. {
  326. pxTimer->ucStatus &= ((uint8_t) ~tmrSTATUS_IS_AUTORELOAD);
  327. }
  328. }
  329. taskEXIT_CRITICAL();
  330. }
  331. /**
  332. * 判断定时器xTimer是否为周期性触发定时器
  333. */
  334. BaseType_t xTimerGetReloadMode(TimerHandle_t xTimer)
  335. {
  336. Timer_t * pxTimer = xTimer;
  337. BaseType_t xReturn;
  338. configASSERT(xTimer);
  339. taskENTER_CRITICAL();
  340. {
  341. if ((pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD) == 0)
  342. {
  343. /* Not an auto-reload timer. */
  344. xReturn = pdFALSE;
  345. }
  346. else
  347. {
  348. /* Is an auto-reload timer. */
  349. xReturn = pdTRUE;
  350. }
  351. }
  352. taskEXIT_CRITICAL();
  353. return xReturn;
  354. }
  355. UBaseType_t uxTimerGetReloadMode(TimerHandle_t xTimer)
  356. {
  357. return (UBaseType_t)xTimerGetReloadMode(xTimer);
  358. }
  359. TickType_t xTimerGetExpiryTime(TimerHandle_t xTimer)
  360. {
  361. Timer_t * pxTimer = xTimer;
  362. TickType_t xReturn;
  363. configASSERT(xTimer);
  364. xReturn = listGET_LIST_ITEM_VALUE(&(pxTimer->xTimerListItem));
  365. return xReturn;
  366. }
  367. const char * pcTimerGetName(TimerHandle_t xTimer)
  368. {
  369. Timer_t * pxTimer = xTimer;
  370. configASSERT(xTimer);
  371. return pxTimer->pcTimerName;
  372. }
  373. static void prvReloadTimer(Timer_t * const pxTimer,
  374. TickType_t xExpiredTime,
  375. const TickType_t xTimeNow)
  376. {
  377. /* Insert the timer into the appropriate list for the next expiry time.
  378. * If the next expiry time has already passed, advance the expiry time,
  379. * call the callback function, and try again. */
  380. while(prvInsertTimerInActiveList(pxTimer, (xExpiredTime + pxTimer->xTimerPeriodInTicks), xTimeNow, xExpiredTime) != pdFALSE)
  381. {
  382. /* Advance the expiry time. */
  383. xExpiredTime += pxTimer->xTimerPeriodInTicks;
  384. /* Call the timer callback. */
  385. traceTIMER_EXPIRED(pxTimer);
  386. pxTimer->pxCallbackFunction((TimerHandle_t)pxTimer);
  387. }
  388. }
  389. static void prvProcessExpiredTimer(const TickType_t xNextExpireTime,
  390. const TickType_t xTimeNow)
  391. {
  392. Timer_t * const pxTimer = (Timer_t *)listGET_OWNER_OF_HEAD_ENTRY(pxCurrentTimerList);
  393. /* Remove the timer from the list of active timers. A check has already
  394. * been performed to ensure the list is not empty. */
  395. (void)uxListRemove(&(pxTimer->xTimerListItem));
  396. /* If the timer is an auto-reload timer then calculate the next
  397. * expiry time and re-insert the timer in the list of active timers. */
  398. if ((pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD) != 0)
  399. {
  400. /* 周期性定时器 */
  401. prvReloadTimer(pxTimer, xNextExpireTime, xTimeNow);
  402. }
  403. else
  404. {
  405. /* oneshot类型定时器 */
  406. pxTimer->ucStatus &= ((uint8_t) ~tmrSTATUS_IS_ACTIVE);
  407. }
  408. /* Call the timer callback. */
  409. traceTIMER_EXPIRED(pxTimer);
  410. /* 调用定时器超时函数 */
  411. pxTimer->pxCallbackFunction((TimerHandle_t)pxTimer);
  412. }
  413. /**
  414. * 软件定时器任务处理入口
  415. */
  416. static portTASK_FUNCTION(prvTimerTask, pvParameters)
  417. {
  418. TickType_t xNextExpireTime;
  419. BaseType_t xListWasEmpty;
  420. /* Just to avoid compiler warnings. */
  421. (void) pvParameters;
  422. #if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1)
  423. {
  424. extern void vApplicationDaemonTaskStartupHook( void );
  425. /* Allow the application writer to execute some code in the context of
  426. * this task at the point the task starts executing. This is useful if the
  427. * application includes initialisation code that would benefit from
  428. * executing after the scheduler has been started. */
  429. vApplicationDaemonTaskStartupHook();
  430. }
  431. #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
  432. for( ; ; )
  433. {
  434. /**
  435. * Query the timers list to see if it contains any timers, and if so,
  436. * obtain the time at which the next timer will expire.
  437. * 获取下一个超时的定时器节点
  438. */
  439. xNextExpireTime = prvGetNextExpireTime(&xListWasEmpty);
  440. /**
  441. * If a timer has expired, process it. Otherwise, block this task
  442. * until either a timer does expire, or a command is received.
  443. */
  444. prvProcessTimerOrBlockTask(xNextExpireTime, xListWasEmpty);
  445. /* Empty the command queue. */
  446. prvProcessReceivedCommands();
  447. }
  448. }
  449. static void prvProcessTimerOrBlockTask(const TickType_t xNextExpireTime,
  450. BaseType_t xListWasEmpty)
  451. {
  452. TickType_t xTimeNow;
  453. BaseType_t xTimerListsWereSwitched;
  454. vTaskSuspendAll();
  455. {
  456. /* Obtain the time now to make an assessment as to whether the timer
  457. * has expired or not. If obtaining the time causes the lists to switch
  458. * then don't process this timer as any timers that remained in the list
  459. * when the lists were switched will have been processed within the
  460. * prvSampleTimeNow() function. */
  461. xTimeNow = prvSampleTimeNow(&xTimerListsWereSwitched);
  462. if (xTimerListsWereSwitched == pdFALSE)
  463. {
  464. /* The tick count has not overflowed, has the timer expired? */
  465. if ((xListWasEmpty == pdFALSE) && (xNextExpireTime <= xTimeNow))
  466. {
  467. (void)xTaskResumeAll();
  468. prvProcessExpiredTimer(xNextExpireTime, xTimeNow);
  469. }
  470. else
  471. {
  472. /* The tick count has not overflowed, and the next expire
  473. * time has not been reached yet. This task should therefore
  474. * block to wait for the next expire time or a command to be
  475. * received - whichever comes first. The following line cannot
  476. * be reached unless xNextExpireTime > xTimeNow, except in the
  477. * case when the current timer list is empty. */
  478. if (xListWasEmpty != pdFALSE)
  479. {
  480. /* The current timer list is empty - is the overflow list
  481. * also empty? */
  482. xListWasEmpty = listLIST_IS_EMPTY(pxOverflowTimerList);
  483. }
  484. vQueueWaitForMessageRestricted(xTimerQueue, (xNextExpireTime - xTimeNow), xListWasEmpty);
  485. if (xTaskResumeAll() == pdFALSE)
  486. {
  487. /* Yield to wait for either a command to arrive, or the
  488. * block time to expire. If a command arrived between the
  489. * critical section being exited and this yield then the yield
  490. * will not cause the task to block. */
  491. portYIELD_WITHIN_API();
  492. }
  493. }
  494. }
  495. else
  496. {
  497. (void)xTaskResumeAll();
  498. }
  499. }
  500. }
  501. static TickType_t prvGetNextExpireTime(BaseType_t * const pxListWasEmpty)
  502. {
  503. TickType_t xNextExpireTime;
  504. /* Timers are listed in expiry time order, with the head of the list
  505. * referencing the task that will expire first. Obtain the time at which
  506. * the timer with the nearest expiry time will expire. If there are no
  507. * active timers then just set the next expire time to 0. That will cause
  508. * this task to unblock when the tick count overflows, at which point the
  509. * timer lists will be switched and the next expiry time can be
  510. * re-assessed.
  511. */
  512. *pxListWasEmpty = listLIST_IS_EMPTY(pxCurrentTimerList);
  513. /* pxCurrentTimerList队列不为空 */
  514. if (*pxListWasEmpty == pdFALSE)
  515. {
  516. /* 获取pxCurrentTimerList的头结点 */
  517. xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxCurrentTimerList);
  518. }
  519. else
  520. {
  521. /**
  522. * Ensure the task unblocks when the tick count rolls over.
  523. * 队列为空,超时为0
  524. */
  525. xNextExpireTime = ( TickType_t ) 0U;
  526. }
  527. return xNextExpireTime;
  528. }
  529. static TickType_t prvSampleTimeNow(BaseType_t * const pxTimerListsWereSwitched)
  530. {
  531. TickType_t xTimeNow;
  532. PRIVILEGED_DATA static TickType_t xLastTime = (TickType_t)0U;
  533. xTimeNow = xTaskGetTickCount();
  534. if (xTimeNow < xLastTime)
  535. {
  536. prvSwitchTimerLists();
  537. *pxTimerListsWereSwitched = pdTRUE;
  538. }
  539. else
  540. {
  541. *pxTimerListsWereSwitched = pdFALSE;
  542. }
  543. xLastTime = xTimeNow;
  544. return xTimeNow;
  545. }
  546. /**
  547. * 定时器节点插入到定时队列中
  548. * @pxTimer
  549. */
  550. static BaseType_t prvInsertTimerInActiveList(Timer_t * const pxTimer,
  551. const TickType_t xNextExpiryTime,
  552. const TickType_t xTimeNow,
  553. const TickType_t xCommandTime)
  554. {
  555. BaseType_t xProcessTimerNow = pdFALSE;
  556. listSET_LIST_ITEM_VALUE(&(pxTimer->xTimerListItem ), xNextExpiryTime );
  557. listSET_LIST_ITEM_OWNER(&(pxTimer->xTimerListItem ), pxTimer );
  558. if (xNextExpiryTime <= xTimeNow)
  559. {
  560. /* Has the expiry time elapsed between the command to start/reset a
  561. * timer was issued, and the time the command was processed? */
  562. if (((TickType_t) (xTimeNow - xCommandTime)) >= pxTimer->xTimerPeriodInTicks)
  563. {
  564. /* The time between a command being issued and the command being
  565. * processed actually exceeds the timers period. */
  566. xProcessTimerNow = pdTRUE;
  567. }
  568. else
  569. {
  570. vListInsert(pxOverflowTimerList, &(pxTimer->xTimerListItem));
  571. }
  572. }
  573. else
  574. {
  575. if ((xTimeNow < xCommandTime) && (xNextExpiryTime >= xCommandTime))
  576. {
  577. /* If, since the command was issued, the tick count has overflowed
  578. * but the expiry time has not, then the timer must have already passed
  579. * its expiry time and should be processed immediately. */
  580. xProcessTimerNow = pdTRUE;
  581. }
  582. else
  583. {
  584. vListInsert(pxCurrentTimerList, &(pxTimer->xTimerListItem));
  585. }
  586. }
  587. return xProcessTimerNow;
  588. }
  589. /* 处理定时器发送的消息 */
  590. static void prvProcessReceivedCommands(void)
  591. {
  592. DaemonTaskMessage_t xMessage;
  593. Timer_t * pxTimer;
  594. BaseType_t xTimerListsWereSwitched;
  595. TickType_t xTimeNow;
  596. while(xQueueReceive(xTimerQueue, &xMessage, tmrNO_DELAY) != pdFAIL)
  597. {
  598. #if (INCLUDE_xTimerPendFunctionCall == 1)
  599. {
  600. /* Negative commands are pended function calls rather than timer
  601. * commands. */
  602. if (xMessage.xMessageID < (BaseType_t)0)
  603. {
  604. const CallbackParameters_t * const pxCallback = &(xMessage.u.xCallbackParameters);
  605. /* The timer uses the xCallbackParameters member to request a
  606. * callback be executed. Check the callback is not NULL. */
  607. configASSERT(pxCallback);
  608. /* Call the function. */
  609. pxCallback->pxCallbackFunction(pxCallback->pvParameter1, pxCallback->ulParameter2);
  610. }
  611. }
  612. #endif /* INCLUDE_xTimerPendFunctionCall */
  613. /* Commands that are positive are timer commands rather than pended
  614. * function calls. */
  615. if (xMessage.xMessageID >= (BaseType_t)0)
  616. {
  617. /* The messages uses the xTimerParameters member to work on a
  618. * software timer.
  619. * 获得发送消息的定时器
  620. */
  621. pxTimer = xMessage.u.xTimerParameters.pxTimer;
  622. if (listIS_CONTAINED_WITHIN(NULL, &(pxTimer->xTimerListItem)) == pdFALSE)
  623. {
  624. /* The timer is in a list, remove it. */
  625. (void) uxListRemove(&(pxTimer->xTimerListItem));
  626. }
  627. traceTIMER_COMMAND_RECEIVED(pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue);
  628. /* In this case the xTimerListsWereSwitched parameter is not used, but
  629. * it must be present in the function call. prvSampleTimeNow() must be
  630. * called after the message is received from xTimerQueue so there is no
  631. * possibility of a higher priority task adding a message to the message
  632. * queue with a time that is ahead of the timer daemon task (because it
  633. * pre-empted the timer daemon task after the xTimeNow value was set). */
  634. xTimeNow = prvSampleTimeNow(&xTimerListsWereSwitched);
  635. switch(xMessage.xMessageID)
  636. {
  637. case tmrCOMMAND_START:
  638. case tmrCOMMAND_START_FROM_ISR:
  639. case tmrCOMMAND_RESET:
  640. case tmrCOMMAND_RESET_FROM_ISR:
  641. /**
  642. * Start or restart a timer.
  643. * 启动定时器
  644. */
  645. pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
  646. if (prvInsertTimerInActiveList(pxTimer,
  647. xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks,
  648. xTimeNow,
  649. xMessage.u.xTimerParameters.xMessageValue) != pdFALSE)
  650. {
  651. /* The timer expired before it was added to the active
  652. * timer list. Process it now. */
  653. if ((pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD) != 0)
  654. {
  655. prvReloadTimer(pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow);
  656. }
  657. else
  658. {
  659. pxTimer->ucStatus &= ((uint8_t ) ~tmrSTATUS_IS_ACTIVE);
  660. }
  661. /* Call the timer callback. */
  662. traceTIMER_EXPIRED(pxTimer);
  663. pxTimer->pxCallbackFunction((TimerHandle_t)pxTimer);
  664. }
  665. break;
  666. case tmrCOMMAND_STOP:
  667. case tmrCOMMAND_STOP_FROM_ISR:
  668. /* The timer has already been removed from the active list. */
  669. pxTimer->ucStatus &= ((uint8_t ) ~tmrSTATUS_IS_ACTIVE);
  670. break;
  671. case tmrCOMMAND_CHANGE_PERIOD:
  672. case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR:
  673. pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
  674. pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
  675. configASSERT((pxTimer->xTimerPeriodInTicks > 0));
  676. /* The new period does not really have a reference, and can
  677. * be longer or shorter than the old one. The command time is
  678. * therefore set to the current time, and as the period cannot
  679. * be zero the next expiry time can only be in the future,
  680. * meaning (unlike for the xTimerStart() case above) there is
  681. * no fail case that needs to be handled here. */
  682. (void) prvInsertTimerInActiveList(pxTimer, (xTimeNow + pxTimer->xTimerPeriodInTicks), xTimeNow, xTimeNow);
  683. break;
  684. case tmrCOMMAND_DELETE:
  685. /* The timer has already been removed from the active list,
  686. * just free up the memory if the memory was dynamically
  687. * allocated. */
  688. if ((pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED) == (uint8_t)0)
  689. {
  690. vPortFree(pxTimer);
  691. }
  692. else
  693. {
  694. pxTimer->ucStatus &= ((uint8_t) ~tmrSTATUS_IS_ACTIVE);
  695. }
  696. break;
  697. default:
  698. /* Don't expect to get here. */
  699. break;
  700. }
  701. }
  702. }
  703. }
  704. /**
  705. * 交换两个定时器队列
  706. */
  707. static void prvSwitchTimerLists(void)
  708. {
  709. TickType_t xNextExpireTime;
  710. List_t * pxTemp;
  711. /* The tick count has overflowed. The timer lists must be switched.
  712. * If there are any timers still referenced from the current timer list
  713. * then they must have expired and should be processed before the lists
  714. * are switched. */
  715. while(listLIST_IS_EMPTY(pxCurrentTimerList) == pdFALSE)
  716. {
  717. xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxCurrentTimerList);
  718. /* Process the expired timer. For auto-reload timers, be careful to
  719. * process only expirations that occur on the current list. Further
  720. * expirations must wait until after the lists are switched. */
  721. prvProcessExpiredTimer(xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW);
  722. }
  723. pxTemp = pxCurrentTimerList;
  724. pxCurrentTimerList = pxOverflowTimerList;
  725. pxOverflowTimerList = pxTemp;
  726. }
  727. static void prvCheckForValidListAndQueue(void)
  728. {
  729. /* Check that the list from which active timers are referenced, and the
  730. * queue used to communicate with the timer service, have been
  731. * initialised.
  732. */
  733. taskENTER_CRITICAL();
  734. {
  735. /* 第一次创建定时器的时候,会创建通信队列 */
  736. if (xTimerQueue == NULL)
  737. {
  738. vListInitialise(&xActiveTimerList1);
  739. vListInitialise(&xActiveTimerList2);
  740. pxCurrentTimerList = &xActiveTimerList1;
  741. pxOverflowTimerList = &xActiveTimerList2;
  742. /* 创建与处理软件定时器任务通信的队列 */
  743. xTimerQueue = xQueueCreate((UBaseType_t)configTIMER_QUEUE_LENGTH, sizeof(DaemonTaskMessage_t));
  744. #if (configQUEUE_REGISTRY_SIZE > 0)
  745. {
  746. if (xTimerQueue != NULL)
  747. {
  748. vQueueAddToRegistry(xTimerQueue, "TmrQ");
  749. }
  750. }
  751. #endif /* configQUEUE_REGISTRY_SIZE */
  752. }
  753. }
  754. taskEXIT_CRITICAL();
  755. }
  756. BaseType_t xTimerIsTimerActive(TimerHandle_t xTimer)
  757. {
  758. BaseType_t xReturn;
  759. Timer_t * pxTimer = xTimer;
  760. configASSERT(xTimer);
  761. /* Is the timer in the list of active timers? */
  762. taskENTER_CRITICAL();
  763. {
  764. if ((pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE) == 0)
  765. {
  766. xReturn = pdFALSE;
  767. }
  768. else
  769. {
  770. xReturn = pdTRUE;
  771. }
  772. }
  773. taskEXIT_CRITICAL();
  774. return xReturn;
  775. }
  776. void * pvTimerGetTimerID(const TimerHandle_t xTimer)
  777. {
  778. Timer_t * const pxTimer = xTimer;
  779. void * pvReturn;
  780. configASSERT(xTimer);
  781. taskENTER_CRITICAL();
  782. {
  783. pvReturn = pxTimer->pvTimerID;
  784. }
  785. taskEXIT_CRITICAL();
  786. return pvReturn;
  787. }
  788. void vTimerSetTimerID(TimerHandle_t xTimer, void * pvNewID)
  789. {
  790. Timer_t * const pxTimer = xTimer;
  791. configASSERT(xTimer);
  792. taskENTER_CRITICAL();
  793. {
  794. pxTimer->pvTimerID = pvNewID;
  795. }
  796. taskEXIT_CRITICAL();
  797. }
  798. #if (INCLUDE_xTimerPendFunctionCall == 1)
  799. BaseType_t xTimerPendFunctionCallFromISR(PendedFunction_t xFunctionToPend,
  800. void * pvParameter1,
  801. uint32_t ulParameter2,
  802. BaseType_t * pxHigherPriorityTaskWoken)
  803. {
  804. DaemonTaskMessage_t xMessage;
  805. BaseType_t xReturn;
  806. /* Complete the message with the function parameters and post it to the
  807. * daemon task. */
  808. xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
  809. xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
  810. xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
  811. xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
  812. xReturn = xQueueSendFromISR(xTimerQueue, &xMessage, pxHigherPriorityTaskWoken);
  813. tracePEND_FUNC_CALL_FROM_ISR(xFunctionToPend, pvParameter1, ulParameter2, xReturn);
  814. return xReturn;
  815. }
  816. BaseType_t xTimerPendFunctionCall(PendedFunction_t xFunctionToPend,
  817. void * pvParameter1,
  818. uint32_t ulParameter2,
  819. TickType_t xTicksToWait)
  820. {
  821. DaemonTaskMessage_t xMessage;
  822. BaseType_t xReturn;
  823. /* This function can only be called after a timer has been created or
  824. * after the scheduler has been started because, until then, the timer
  825. * queue does not exist. */
  826. configASSERT(xTimerQueue);
  827. /* Complete the message with the function parameters and post it to the
  828. * daemon task. */
  829. xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
  830. xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
  831. xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
  832. xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
  833. xReturn = xQueueSendToBack(xTimerQueue, &xMessage, xTicksToWait);
  834. tracePEND_FUNC_CALL(xFunctionToPend, pvParameter1, ulParameter2, xReturn);
  835. return xReturn;
  836. }
  837. #endif
  838. #if (configUSE_TRACE_FACILITY == 1)
  839. UBaseType_t uxTimerGetTimerNumber(TimerHandle_t xTimer)
  840. {
  841. return ((Timer_t *)xTimer)->uxTimerNumber;
  842. }
  843. void vTimerSetTimerNumber(TimerHandle_t xTimer,
  844. UBaseType_t uxTimerNumber)
  845. {
  846. ((Timer_t *)xTimer)->uxTimerNumber = uxTimerNumber;
  847. }
  848. #endif
  849. #endif /* configUSE_TIMERS == 1 */