0

I want to create a function with a delay for each instance of a class. If some condition occur a task will be created and a delay will happen only to this instance.

 /* Task to be created. */
void vTaskCode( void * pvParameters ){
   const TickType_t xDelay = 1000 / portTICK_PERIOD_MS;
   //Do some logic...       
   vTaskDelay(xDelay);

   //indicate the task has finished
   configASSERT(1);
}
BaseType_t xReturned;
TaskHandle_t xHandle = NULL;

class foo {
void afunc(){
  //Create a task of vTaskCode if it doesnt exist
  if (xHandle == NULL){
  xReturned = xTaskCreate(
                    vTaskCode,       /* Function that implements the task. */
                    "Auxiliary",          /* Text name for the task. */
                    STACK_SIZE,      /* Stack size in words, not bytes. */
                    NULL,    /* Parameter passed into the task. */
                    tskIDLE_PRIORITY,/* Priority at which the task is created. */
                    &xHandle );


}}

 //Should be called after the task is complete.    
 if( xReturned == pdPASS )
 {
     vTaskDelete( xHandle );
 }


}

//main loop
  void MainLOOP( void * pvParameters ){
  for (;;){
     const TickType_t xDelay = 5 / portTICK_PERIOD_MS;
     for (std::list<foo>::iterator itr = foolist.begin(); itr != foolist.end(); ++itr)
     {
         itr->afunc();
     }
   }}


void setup(){
std::list<foo> foolist;

///...SOME CODE TO POPULATE FOOLIST

xTaskCreate(
                    MainLOOP,       /* Function that implements the task. */
                    "MAIN",          /* Text name for the task. */
                    STACK_SIZE,      /* Stack size in words, not bytes. */
                    NULL,    /* Parameter passed into the task. */
                    tskIDLE_PRIORITY,/* Priority at which the task is created. */
                    NULL);


}

Will each delay work? Or at each iteration a new task will run? Will the for loop be blocked so each iteration stops or it will work async?

The whole idea is to avoid using millis() function and not blocking each iteraction of the list. Another restrain is speed as this loop work at 5ms and i would like to use the core 0.

EDIT: @HS2 raised that a better approach should be using a FreeRTOS timer

  • Although I don't really get what you want to achieve, dynamically creating/deleting tasks is almost never the best idea. Especially if you just want to delay something. For time triggered actions FreeRTOS timers could be used or roll your delay-something task acting on conditions/events signaled to it. – HS2 Jul 22 '21 at 16:08
  • With your comment i edited the question. How would you make this delay using FreeRTOS timers without blocking the main loop? – Carlos Moraes Jul 22 '21 at 16:30
  • FreeRTOS timers are managed by a separate timer task and provide single-shot and periodic modes. See https://www.freertos.org/RTOS-software-timer.html You could send an event (via queue or notification) from the timer callback to main/another task and act on the elapsed timer. – HS2 Jul 22 '21 at 16:47

1 Answers1

0

As HS2 have said, dynamically create tasks is not a good aproach. Using FreeRTOS timers does not work well if your timed action has to run many functions and objects because of the timer queue. The solution was to make a task for each object inside the list, instead a major task for the list:

TASK of each object of the list

void Djtri::analisa(void *pvParameters) {
    //Serial.printf("\n ABT: %x FCH: %x BI: %x", totAbt, totFch, *bi);
Djtri *djpnt = (Djtri*) pvParameters;
const TickType_t tmpAb = djpnt->tmpAbt / portTICK_PERIOD_MS;
const TickType_t tmpFc = djpnt->tmpFch / portTICK_PERIOD_MS;
const TickType_t looptime = 5 / portTICK_PERIOD_MS;
for (;;){
    if ((djpnt->biAbt & io[0]) && (djpnt->estado != ABERTO)) {
        Serial.printf("\nOrdem de abertura do DJ %X ", djpnt->id);

        vTaskDelay(tmpAb);
        djpnt->abrir();

    } else if ((djpnt->biFch & io[0]) && (djpnt->estado != FECHADO)) {
        Serial.printf("\nOrdem de fechamento do DJ %X", djpnt->id);
        vTaskDelay(tmpFc);
        djpnt->fechar();
    }
    vTaskDelay(looptime);
}
}

Create a task for each item on setup of ESP32

    for (auto itr = djtrilst.begin(); itr != djtrilst.end(); ++itr){
    Serial.printf("\n Criando task para DJ tri: %x", itr->id);
    xTaskCreatePinnedToCore(
            Djtri::analisa,   /* Function to implement the task */
            "Djtri", /* Name of the task */
            8000,      /* Stack size in words */
            (void*) &*itr,       /* Task input parameter */
            0,          /* Priority of the task */
            nullptr,       /* Task handle. */
            0);  /* Core where the task should run */
}

Observe that I used the task input parameter to pass the pointer of the object, as a task function must be static.