text: /*
   Unit tests for FreeRTOS preemption
  */
  
  #include <esp_types.h>
  #include <stdio.h>
  
  #include "freertos/FreeRTOS.h"
  #include "freertos/task.h"
  #include "freertos/semphr.h"
  #include "freertos/queue.h"
  #include "unity.h"
  #include "hal/cpu_hal.h"
  #include "test_utils.h"
  #include "sdkconfig.h"
  
  static volatile bool trigger;
  static volatile bool flag;
  
  /* Task:
     - Waits for 'trigger' variable to be set
     - Reads the cycle count on this CPU
     - Pushes it into a queue supplied as a param
     - Busy-waits until the main task terminates it
  */
  static void task_send_to_queue(void *param)
  {
      QueueHandle_t queue = (QueueHandle_t) param;
      uint32_t ccount;
  
      while(!trigger) {}
  
      ccount = cpu_hal_get_cycle_count();
      flag = true;
      xQueueSendToBack(queue, &ccount, 0);
      /* This is to ensure that higher priority task
         won't wake anyhow, due to this task terminating.
  
         The task runs until terminated by the main task.
      */
      while(1) {}
  }
  
  TEST_CASE("Yield from lower priority task, same CPU", "[freertos]")
  {
      /* Do this 3 times, mostly for the benchmark value - the first
         run includes a cache miss so uses more cycles than it should. */
      for (int i = 0; i < 3; i++) {
          TaskHandle_t sender_task;
          QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
          flag = false;
          trigger = false;
  
          /* "yield" task sits on our CPU, lower priority to us */
          xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1, &sender_task, UNITY_FREERTOS_CPU);
  
          vTaskDelay(1); /* make sure everything is set up */
          trigger = true;
  
          uint32_t yield_ccount, now_ccount, delta;
          TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
          now_ccount = cpu_hal_get_cycle_count();
          TEST_ASSERT( flag );
  
          delta = now_ccount - yield_ccount;
          printf("Yielding from lower priority task took %u cycles\n", delta);
          TEST_ASSERT(delta < 10000);
  
          vTaskDelete(sender_task);
          vQueueDelete(queue);
      }
  }
  
  
  #if (portNUM_PROCESSORS == 2) && !CONFIG_FREERTOS_TASK_FUNCTIONS_INTO_FLASH
  TEST_CASE("Yield from lower priority task, other CPU", "[freertos]")
  {
      uint32_t trigger_ccount, yield_ccount, now_ccount, delta;
  
      /* Do this 3 times, mostly for the benchmark value - the first
         run includes a cache miss so uses more cycles than it should. */
      for (int i = 0; i < 3; i++) {
          TaskHandle_t sender_task;
          QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
          trigger = false;
          flag = false;
  
          /* "send_to_queue" task sits on the other CPU, lower priority to us */
          xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1,
                                  &sender_task, !UNITY_FREERTOS_CPU);
  
          vTaskDelay(2); /* make sure everything is set up */
          trigger = true;
          trigger_ccount = cpu_hal_get_cycle_count();
  
          // yield_ccount is not useful in this test as it's the other core's CCOUNT
          // so we use trigger_ccount instead
          TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
          now_ccount = cpu_hal_get_cycle_count();
          TEST_ASSERT( flag );
  
          delta = now_ccount - trigger_ccount;
          printf("Yielding from task on other core took %u cycles\n", delta);
          TEST_ASSERT(delta < 10000);
  
          vQueueDelete(queue);
          vTaskDelete(sender_task);
      }
  }
  #endif
  