0

I want to synchronize two tasks in a command/response communication server. One task sends data to a serial port and another task receives data on the serial port. Received data should either be returned to the sender task or do something else with it.

I unsuccessfully tried using volatile bool flags but have now found that won't work with C++ (See When to use volatile with multi threading?)

So trying to use semaphores to do it but can't quite figure out how. Some (bad) psuedo-code using volatile bool is below. How/where to modify for semaphore give/take?

Actual code/platform is C++ 11 running on ESP32 (ESP-IDF). Resources are very limited so no C++ std:: libraries.

volatile bool responsePending = false;
volatile bool     cmdAccepted = false;
char sharedBuffer[100];

// SENDER //
void Task1()
{
    char localBuffer[100];
    
    while (1)
    {
        responsePending = true;
        cmdAccepted     = false;
        
        sendMessage();
        
        while (responsePending)
            sleep();
        
        strcpy(localBuffer, sharedBuffer);
        cmdAccepted = true; // signal Task2
    }
}


// RECEIVER //
void Task2()
{
    char localBuf[100];
    int fd = open();
    
    while (1)
    {
        if (select())
        {
            read(fd, localBuf);
            
            if (responsePending)
            {
                strcpy(sharedBuffer, localBuf);
                responsePending = false; // signal Task1
                
                while (!cmdAccepted)
                    sleep();
            }
            else
            {
                // Do something else with the received data
            }
        }
    }
}
Danny
  • 2,482
  • 3
  • 34
  • 48

1 Answers1

0

Create a queue which holds a struct. One tasks waits for the serial, if it got data it will put the message to the struct and the struct to the queue.

Other task waits for the queue, if there are items in the queue it will process the struct.

Example:

struct queueData{
    char messageBuffer[100];
};
QueueHandle_t queueHandle;

void taskOne(){
    while(){
        // Task one checks if it got serial data.
        if( gotSerialMsg() ){
            // create a struct
            queueData data;
            // copy the data to the struct
            strcpy( getSerialMSG(), data.messageBuffer );
            // send struct to queue ( waits indefinietly )
            xQueueSend(queueHandle, &data, portMAX_DELAY);
        }
        vTaskDelay(1); // Must feed other tasks
    }
}

void taskTwo(){
    while(){
        // Check if a structs has an item
        if( uxQueueMessagesWaiting(queueHandle) > 0 ){
            // create a holding struct
            queueData data;
            // Receive the whole struct
            if (xQueueReceive(queueHandle, &data, 0) == pdTRUE) {
                // Struct holds message like: data.messageBuffer
            }
        }
        vTaskDelay(1); // Must feed other tasks
    }
}

The good thing in passing structs to queues is that you can always put more data into it. booleans or ints or any other thing.

Dr.Random
  • 430
  • 3
  • 16