There is a generator task task_gen
that fills some buf
with data. buffer is filled character-by-character, so at single moment of time, buf
may be in incomplete state.
For simplification, this is 9-char buffer which is filled with 9 equal letters. buffer complete
state occurs when all characters (except trailing \0
) are same. Other states are incomplete:
AAA AAA AAA \0 // Complete state
BAA AAA AAA \0 // Incomplete state
BBA AAA AAA \0 // Incomplete state
BBB AAA AAA \0 // Incomplete state
...
BBB BBB BBA \0 // Incomplete state
BBB BBB BBB \0 // Complete state
...
ZZZ ZZZ ZZZ \0 // Complete state
AZZ ZZZ ZZZ \0 // Incomplete state
...
AAA AAA AAZ \0 // Incomplete state
(loop)
Code of `task_gen`
uint8_t buf[10]; // shared buffer
/// @brief Periodically fills global "buf" with equal characters, one by one.
/// "buf" is considered to be correct when all characters are equal
/// @param pvParams must be NULL
void task_gen(void *pvParams)
{
uint8_t start_val = 'A', end_val = 'Z', val = start_val;
for(;;)
{
vTaskDelay(pdMS_TO_TICKS(esp_random() % 1000));
Serial.printf("%s Generating new line\n", pcTaskGetName(NULL));
for(int i = 0; i < (sizeof(buf) - 1); i++)
{
buf[i] = val;
vTaskDelay(pdMS_TO_TICKS(esp_random() % 50));
}
// !!! THIS PLACE is where "buffer complete".
Serial.printf("Line generated: %s\n", buf);
val++;
if (val > end_val) val = start_val;
}
}
There are two identical receive tasks: task_rcv1
and task_rcv2
implemented using function task_rcv
. task_rcv
sleeps for some time and when wakes, it must read exact number of consecutive buffers when they are in complete
state and loop.
Code for `task_rcv`
SemaphoreHandle_t gen_rcv_mtx;
/// @brief periodically receives few _consecutive_ values from "buf"
/// @param pvParams pointer to int with number of consecutive correct buffers must be read.
void task_rcv(void *pvParams)
{
int count = *((int*)pvParams);
Serial.printf("task with count %d started\n", count);
for(;;)
{
vTaskDelay(pdMS_TO_TICKS(esp_random() % 10 * 500));
if (xSemaphoreTake(gen_rcv_mtx, portMAX_DELAY) == pdTRUE)
{
for (int i = 1; i <= count; i++)
{
// !!! Here wait for buffer complete state and suspend task_gen
Serial.printf("%s %d/%d : %s\n", pcTaskGetName(NULL), count, i, buf);
vTaskDelay(pdMS_TO_TICKS(esp_random() % 100));
// !!! Here wake task_gen
}
xSemaphoreGive(gen_rcv_mtx);
}
}
}
Question is: How should I implement logic: task_rcv
waits until buf is complete and suspends task_gen
while processing buf
?
Current output:
Line generated: JJJJJJJJJ
task_gen Generating new line
Line generated: KKKKKKKKK
task_gen Generating new line
task_rcv1 5/1 : LLLKKKKKK
task_rcv1 5/2 : LLLLKKKKK
task_rcv1 5/3 : LLLLLKKKK
task_rcv1 5/4 : LLLLLKKKK
task_rcv1 5/5 : LLLLLLLLK
Line generated: LLLLLLLLL
task_gen Generating new line
task_rcv2 3/1 : LLLLLLLLL
task_rcv2 3/2 : MMLLLLLLL
task_rcv2 3/3 : MMMMLLLLL
Line generated: MMMMMMMMM
Wanted output:
Line generated: KKKKKKKKK
task_rcv1 5/1 : KKKKKKKKK
task_gen Generating new line
Line generated: LLLLLLLLL
task_rcv1 5/2 : LLLLLLLLL
task_gen Generating new line
Line generated: MMMMMMMMM
task_rcv1 5/3 : MMMMMMMMM
task_gen Generating new line
Line generated: NNNNNNNNN
task_rcv1 5/4 : NNNNNNNNN
task_gen Generating new line
Line generated: OOOOOOOOO
task_rcv1 5/5 : OOOOOOOOO
task_gen Generating new line
Line generated: PPPPPPPPP
task_gen Generating new line
Line generated: QQQQQQQQQ
task_rcv1 3/1 : QQQQQQQQQ
task_gen Generating new line
Line generated: RRRRRRRRR
task_rcv1 3/2 : RRRRRRRRR
task_gen Generating new line
Line generated: SSSSSSSSS
task_rcv1 3/3 : SSSSSSSSS
task_gen Generating new line
Line generated: TTTTTTTTT
task_gen Generating new line
Line generated: UUUUUUUUU
Rest of the code:
TaskHandle_t task_gen_handler, task_rcv1, task_rcv2;
int count_task1 = 5;
int count_task2 = 3;
void setup() {
Serial.begin(115200);
gen_rvc_mtx = xSemaphoreCreateMutex();
buf[63] = '\0';
memset(buf, 'Z', sizeof(buf) - 1);
xTaskCreate(task_gen, "task_gen", 4096, NULL, tskIDLE_PRIORITY + 1, &task_gen_handler);
xTaskCreate(task_rcv, "task_rcv1", 4096, &count_task1, tskIDLE_PRIORITY + 1, &task_rcv1);
xTaskCreate(task_rcv, "task_rcv2", 4096, &count_task2, tskIDLE_PRIORITY + 1, &task_rcv2);
Serial.println("Started");
vTaskDelay(pdMS_TO_TICKS(1000));
}
void loop() {
vTaskDelete(NULL);
}