test_freertos_backported_functions.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Test features that are backported from version FreeRTOS 9.0.0.
  3. *
  4. * 1) Test backported timer functions
  5. * - xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
  6. * 2) Test backported queue/semaphore functions
  7. * - xQueueCreateStatic()
  8. * - xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic(), uxSemaphoreGetCount()
  9. * - xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
  10. * 3) Test static allocation of tasks
  11. * - xTaskCreateStaticPinnedToCore()
  12. * 4) Test static allocation of event group
  13. * - xEventGroupCreateStatic()
  14. * 5) Test Thread Local Storage Pointers and Deletion Callbacks
  15. * - vTaskSetThreadLocalStoragePointerAndDelCallback()
  16. * - pvTaskGetThreadLocalStoragePointer()
  17. *
  18. * Note: The *pcQueueGetName() function is also backported, but is not tested in
  19. * the following test cases (see Queue Registry test cases instead)
  20. * For more details please refer the the ESP-IDF FreeRTOS changes documentation
  21. */
  22. #include <stdio.h>
  23. #include "freertos/FreeRTOS.h"
  24. #include "freertos/task.h"
  25. #include "freertos/timers.h"
  26. #include "freertos/queue.h"
  27. #include "freertos/semphr.h"
  28. #include "freertos/event_groups.h"
  29. #include "unity.h"
  30. #include "test_utils.h"
  31. /* ---------------------Test 1: Backported Timer functions-----------------------
  32. * Test xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
  33. *
  34. * This test creates a one-shot static timer, sets/checks the timer's id and period. Then ensures
  35. * the timer cb is executed in a timely fashion.
  36. */
  37. #define TMR_PERIOD_TICKS 10
  38. #define TIMER_ID 0xFF
  39. #define TICK_DELTA 5
  40. static StaticTimer_t timer_buffer;
  41. static TickType_t tmr_ideal_exp;
  42. static void tmr_cb(TimerHandle_t xtimer)
  43. {
  44. //Check cb is called in timely fashion
  45. TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTaskGetTickCount());
  46. }
  47. //No need for smp test as Timer Task always runs on core 0
  48. TEST_CASE("Test FreeRTOS backported timer functions", "[freertos]")
  49. {
  50. //Create one shot static timer with period TMR_PERIOD_TICKS
  51. TimerHandle_t tmr_handle = xTimerCreateStatic("static_tmr", TMR_PERIOD_TICKS, pdFALSE, NULL, tmr_cb, &timer_buffer);
  52. TEST_ASSERT_EQUAL(TMR_PERIOD_TICKS, xTimerGetPeriod(tmr_handle)); //Test xTimerGetPeriod()
  53. vTimerSetTimerID(tmr_handle, (void *)TIMER_ID);
  54. TEST_ASSERT_EQUAL(TIMER_ID, (uint32_t)pvTimerGetTimerID(tmr_handle)); //Test vTimerSetTimerID()
  55. TEST_ASSERT_EQUAL(pdTRUE, xTimerStart(tmr_handle, 1)); //Start Timer
  56. tmr_ideal_exp = xTaskGetTickCount() + TMR_PERIOD_TICKS; //Calculate ideal expiration time
  57. vTaskDelay(2); //Need to yield to allow daemon task to process start command, or else expiration time will be NULL
  58. TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTimerGetExpiryTime(tmr_handle)); //Test xTimerGetExpiryTime()
  59. vTaskDelay(2*TMR_PERIOD_TICKS); //Delay until one shot timer has triggered
  60. TEST_ASSERT_EQUAL(pdPASS, xTimerDelete(tmr_handle, portMAX_DELAY)); //Clean up
  61. }
  62. /* ---------------Test backported queue/semaphore functions-------------------
  63. * xQueueCreateStatic()
  64. * xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic()
  65. * xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
  66. * uxSemaphoreGetCount() is also tested on the static counting semaphore
  67. *
  68. * This test creates various static queue/semphrs listed above and tests them by
  69. * doing a simple send/give and rec/take.
  70. */
  71. #define ITEM_SIZE 3
  72. #define NO_OF_ITEMS 3
  73. #define DELAY_TICKS 2
  74. static StaticQueue_t queue_buffer; //Queues, Semaphores, and Mutex use the same queue structure
  75. static uint8_t queue_storage_area[(ITEM_SIZE*NO_OF_ITEMS)]; //Queue storage provided in separate buffer to queue struct
  76. TEST_CASE("Test FreeRTOS backported Queue and Semphr functions", "[freertos]")
  77. {
  78. //Test static queue
  79. uint8_t queue_item_to_send[ITEM_SIZE];
  80. uint8_t queue_item_received[ITEM_SIZE];
  81. for(int i = 0; i < ITEM_SIZE; i++){
  82. queue_item_to_send[i] = (0xF << i);
  83. }
  84. QueueHandle_t handle = xQueueCreateStatic(NO_OF_ITEMS, ITEM_SIZE,(uint8_t*) &queue_storage_area, &queue_buffer);
  85. TEST_ASSERT_EQUAL(pdTRUE, xQueueSendToBack(handle, &queue_item_to_send, DELAY_TICKS));
  86. vTaskDelay(1);
  87. TEST_ASSERT_EQUAL(pdTRUE, xQueueReceive(handle, queue_item_received, DELAY_TICKS));
  88. vTaskDelay(1);
  89. for(int i = 0; i < ITEM_SIZE; i++){
  90. TEST_ASSERT_EQUAL(queue_item_to_send[i], queue_item_received[i]); //Check received contents are correct
  91. }
  92. vQueueDelete(handle); //Technically not needed as deleting static queue/semphr doesn't clear static memory
  93. //Test static binary semaphore
  94. handle = xSemaphoreCreateBinaryStatic(&queue_buffer); //Queue and Semphr handles are the same
  95. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
  96. vTaskDelay(1);
  97. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
  98. vTaskDelay(1);
  99. vSemaphoreDelete(handle);
  100. //Test static counting semaphore and uxSemaphoreGetCount()
  101. handle = xSemaphoreCreateCountingStatic(NO_OF_ITEMS, 0, &queue_buffer);
  102. for(int i = 0; i < NO_OF_ITEMS; i++){
  103. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
  104. }
  105. vTaskDelay(1);
  106. TEST_ASSERT_EQUAL(NO_OF_ITEMS, uxSemaphoreGetCount(handle)); //Test uxSemaphoreGetCount()
  107. for(int i = 0; i < NO_OF_ITEMS; i++){
  108. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
  109. }
  110. vTaskDelay(1);
  111. TEST_ASSERT_EQUAL(0, uxSemaphoreGetCount(handle));
  112. vSemaphoreDelete(handle);
  113. //Test static mutex
  114. handle = xSemaphoreCreateMutexStatic(&queue_buffer);
  115. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
  116. vTaskDelay(1);
  117. TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should now hold mutex
  118. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
  119. vTaskDelay(1);
  120. TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
  121. vSemaphoreDelete(handle);
  122. //Test static mutex recursive
  123. handle = xSemaphoreCreateRecursiveMutexStatic(&queue_buffer);
  124. for(int i = 0; i < NO_OF_ITEMS; i++){
  125. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTakeRecursive(handle, DELAY_TICKS));
  126. }
  127. vTaskDelay(1);
  128. TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should hold mutex
  129. for(int i = 0; i < NO_OF_ITEMS; i++){
  130. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGiveRecursive(handle));
  131. }
  132. vTaskDelay(1);
  133. TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
  134. vSemaphoreDelete(handle);
  135. }
  136. /* -----------------Test backported static task allocation -------------------
  137. * Test xTaskCreateStaticPinnedToCore() but creating static task on each core
  138. * and checking the task cb has run successfully.
  139. */
  140. #define STACK_SIZE 2048 //Task stack size
  141. static StackType_t task_stack[STACK_SIZE]; //Static buffer for task stack
  142. static StaticTask_t task_buffer; //Static buffer for TCB
  143. static bool has_run[portNUM_PROCESSORS];
  144. static void task(void *arg)
  145. {
  146. has_run[xPortGetCoreID()] = true; //Signify static task cb has run
  147. vTaskDelete(NULL);
  148. }
  149. TEST_CASE("Test FreeRTOS static task allocation", "[freertos]")
  150. {
  151. for(int core = 0; core < portNUM_PROCESSORS; core++){
  152. has_run[core] = false; //Clear has_run flag
  153. TaskHandle_t handle = xTaskCreateStaticPinnedToCore(task, "static task", STACK_SIZE, NULL,
  154. UNITY_FREERTOS_PRIORITY + 1, (StackType_t *)&task_stack,
  155. (StaticTask_t *)&task_buffer, core);
  156. vTaskDelay(5); //Allow for static task to run, delete, and idle to clean up
  157. TEST_ASSERT_NOT_EQUAL(NULL, handle); //Check static task was successfully allocated
  158. TEST_ASSERT_TRUE(has_run[core]) //Check static task has run
  159. }
  160. }
  161. /* ------------- Test backported static event group allocation -------------------
  162. * Test xEventGroupCreateStatic() but creating static event group then waiting
  163. * for an event.
  164. */
  165. #define WAIT_BITS 0x01 //Wait for first bit
  166. static StaticEventGroup_t event_group;
  167. static EventGroupHandle_t eg_handle;
  168. TEST_CASE("Test FreeRTOS backported eventgroup functions", "[freertos]")
  169. {
  170. eg_handle = xEventGroupCreateStatic((StaticEventGroup_t *)&event_group);
  171. xEventGroupSetBits(eg_handle, WAIT_BITS);
  172. TEST_ASSERT_EQUAL(WAIT_BITS, xEventGroupWaitBits(eg_handle, WAIT_BITS, pdTRUE, pdTRUE, portMAX_DELAY));
  173. //Cleanup static event
  174. vEventGroupDelete(eg_handle);
  175. }
  176. /* --------Test backported thread local storage pointer and deletion cb feature----------
  177. * vTaskSetThreadLocalStoragePointerAndDelCallback()
  178. * pvTaskGetThreadLocalStoragePointer(),
  179. *
  180. * This test creates a task and set's the task's TLSPs. The task is then deleted
  181. * which should trigger the deletion cb.
  182. */
  183. #define NO_OF_TLSP configNUM_THREAD_LOCAL_STORAGE_POINTERS
  184. #define TLSP_SET_BASE 0x0F //0b1111 to be bit shifted by index
  185. #define TLSP_DEL_BASE 0x05 //0b0101 to be bit shifted by index
  186. //The variables pointed to by Thread Local Storage Pointer
  187. static uint32_t task_storage[portNUM_PROCESSORS][NO_OF_TLSP] = {0};
  188. /* If static task cleanup is defined, can't set index 0 even if the calling task is not a pthread,
  189. as the cleanup is called for every task.
  190. */
  191. #if defined(CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP)
  192. static const int skip_index = 0; /*PTHREAD_TLS_INDEX*/
  193. #else
  194. static const int skip_index = -1;
  195. #endif
  196. static void del_cb(int index, void *ptr)
  197. {
  198. *((uint32_t *)ptr) = (TLSP_DEL_BASE << index); //Indicate deletion by setting task storage element to a unique value
  199. }
  200. static void task_cb(void *arg)
  201. {
  202. int core = xPortGetCoreID();
  203. for(int i = 0; i < NO_OF_TLSP; i++){
  204. if (i == skip_index) {
  205. continue;
  206. }
  207. task_storage[core][i] = (TLSP_SET_BASE << i); //Give each element of task_storage a unique number
  208. vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, i, (void *)&task_storage[core][i], del_cb); //Set each TLSP to point to a task storage element
  209. }
  210. for(int i = 0; i < NO_OF_TLSP; i++){
  211. if (i == skip_index) {
  212. continue;
  213. }
  214. uint32_t * tlsp = (uint32_t *)pvTaskGetThreadLocalStoragePointer(NULL, i);
  215. TEST_ASSERT_EQUAL(*tlsp, (TLSP_SET_BASE << i)); //Check if TLSP points to the correct task storage element by checking unique value
  216. }
  217. vTaskDelete(NULL); //Delete Task to Trigger TSLP deletion callback
  218. }
  219. TEST_CASE("Test FreeRTOS thread local storage pointers and del cb", "[freertos]")
  220. {
  221. //Create Task
  222. for(int core = 0; core < portNUM_PROCESSORS; core++){
  223. xTaskCreatePinnedToCore(task_cb, "task", 1024, NULL, UNITY_FREERTOS_PRIORITY+1, NULL, core);
  224. }
  225. vTaskDelay(10); //Delay long enough for tasks to run to completion
  226. for(int core = 0; core < portNUM_PROCESSORS; core++){
  227. for(int i = 0; i < NO_OF_TLSP; i++){
  228. if (i == skip_index) {
  229. continue;
  230. }
  231. TEST_ASSERT_EQUAL((TLSP_DEL_BASE << i), task_storage[core][i]); //Check del_cb ran by checking task storage for unique value
  232. }
  233. }
  234. }