Search code examples
ctimeresp32freertosesp-idf

Queue giving the full data array instead of sending byte by byte in ESP32


I'm trying to send the array that we get through UART and passing the array to the "hex_to_bin" function. The data received is perfect and this is also passed to the queue. I want only one byte at a time so that I can extract bit from it in the "turn_on_off" task and perform the timer functions. I used binary semaphore thinking that queue will wait and send the data, bit extraction is done successfully but I can't process timer functions. Please help me in this regard.

#include "main.h"

QueueHandle_t data_queue;

void turn_on_off(void *pvParameters)
{
  uint8_t bit;
  int data_index = 0;
  timer_start(TIMER_GROUP, TIMER_INDEX);
  gpio_set_level(GPIO_NUM_2, true);
  int bit_check = 0;
  int prev_bit_check;

  UartDataStruct UartDataStruct_Onewire;

  timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0);
  while (true)
  {
    if ((xQueueReceive(data_queue, &UartDataStruct_Onewire, portMAX_DELAY) == pdPASS))
    {
      // printf("Received data is : %s | len : %d\r\n",&UartDataStruct_Onewire.UartDataBuffer[0],UartDataStruct_Onewire.len);
      timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0);

      while (true)
      {
        timer_get_counter_value(TIMER_GROUP, TIMER_INDEX, &task_counter_value);
        // printf("Task counter value: %lld",task_counter_value);
        if (bit_check == 0)
        {
          if (task_counter_value > 200000) // 1000 count per ms
          {
            gpio_set_level(GPIO_NUM_2, false);
            if (task_counter_value > 256000)
            {
              gpio_set_level(GPIO_NUM_2, true);
              bit_check++;
              timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0);
            }
          }
        }
        else
        {
          for (data_index = 0; data_index < UartDataStruct_Onewire.len - 1; data_index++)
          {
            for (int itr = 7; itr >= 0; itr--)
            {
              bit = (UartDataStruct_Onewire.UartDataBuffer[data_index] >> itr) & 0x01;
              // ESP_LOGI("Onewire","Bit extracted: %d", bit);
              if (bit == 1)
              {
                for (prev_bit_check = bit_check; bit_check > prev_bit_check;)
                {
                  if (task_counter_value > 30000) // 1000 COUNT PER ms
                  {
                    gpio_set_level(GPIO_NUM_2, false);
                    if (task_counter_value > 38000)
                    {
                      gpio_set_level(GPIO_NUM_2, true);
                      bit_check++;
                      timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0);
                    }
                  }
                }
              }
              else
              {
                for (prev_bit_check = bit_check; bit_check > prev_bit_check;)
                {
                  if (task_counter_value > 6000) // 1000 COUNT PER ms
                  {
                    gpio_set_level(GPIO_NUM_2, false);
                    if (task_counter_value > 26000)
                    {
                      gpio_set_level(GPIO_NUM_2, true);
                      bit_check++;
                      timer_set_counter_value(TIMER_GROUP, TIMER_INDEX, 0);
                    }
                  }
                }
              }
            }
            printf("---------------\r\n");
          }
        }
        if (data_index == UartDataStruct_Onewire.len - 1)
        {
          bit_check = 0;
          break;
        }
      }
    }
  }
}

Solution

  • Considering the information from the comments vTaskDelay is your friend here (you finally can drop the timer entirely):

    xSemaphoreTake(data_semaphore, portMAX_DELAY);
    // side note: you do not handle the case of the semaphore NOT having been taken! 
    
    // assuming setting to low switches the LED on – if not, invert the values!
    
    gpio_set_level(GPIO_NUM_2, false);
    vTaskDelay(200 / portTICK_PERIOD_MS); // see documentation
    gpio_set_level(GPIO_NUM_2, true);
    vTaskDelay(56 / portTICK_PERIOD_MS);
    for(bits...)
    {
        if(bit == 1)
        {
            onTime = 30;
            offTime = 8;
        }
        else
        {
            onTime = 6;
            offTime = 20;
        }
        gpio_set_level(GPIO_NUM_2, false);
        vTaskDelay(onTime / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_NUM_2, true);
        vTaskDelay(offTime / portTICK_PERIOD_MS);
    }
    xSemaphoreGive(data_semaphore);
    

    Note: Totally untested code, if you find a bug please fix yourself.