Does my project idea sound OK in terms of implementation? Any suggestions are welcome

So I came up with this simple flow of the program that could be done without RTOS but I’m using it for the sake of learning.

The generic idea is to get the user input over UART, and if it’s something regarding data query, the data query task wakes up, reads the sensor data, wakes up the other task to transfer the data over to RX module.

In other words, I have ulTaskNotifyTake() in, say, a Data Task which waits on a notification from a UART task. Upon receiving an input over the UART regarding the query of this data, the UART task would call xTaskNotifyFromISR() from the UART’s ISR waking up the Data Task, which would query the sensor data…and so on.

Does the generic flow sound OK? I’m still going through a bunch of FreeRTOS docs on APIs but that’s a raw image that I thought of. Any suggestions are appreciated.

enter image description here

This would work, but seems over complex. You are using three tasks where, depending on what the rest of your system was doing, a single task may suffice. It would depend on many factors, such as what else is the UART used for? What is the length of the data? How long does it take to read from the sensor? Does the system have any real time requirements, or does reading and responding to the query message have real time requirements itself, etc.

True. I thought about it and I think I don’t quite need all these queues for each task. Perhaps a simple idea may include using task notification inside Data Query task (ulTaskNotifyTake) which gets notified from within UART’s ISR once we have received a proper request from the user (xTaskNotifyFromISR). And the same relation exists between Data Query Task and Xfer data over to RX task? thoughts?

I think the simplest design would be to have two queues and then each task blocks indefinitely on a receive on its respective queue. Then you do not need to get notifications involved at all, and you can set the priorities
If you have a UART interrupt you could even just place the data in the UART queue straight from there.

But with two queues, how are you notifying the other task that’s waiting on the UART data? I think the idea of notifying the blocked task (query data task) from the UART task sounds simpler; the moment I receive the desired data in the UART’s ISR, I notify the data queue which then does its thing.

Something like:

  void vDataQueryTask(void *params) {
      while (1) {
         ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
         // do something useful

   }

uint8_t buffer[10];
void UART_Callback(USART_Handle_t *pUSART) {
   parseUsartData(pUSART, buffer);
   if (!strcmp(buffer, "something")) {
       	xTaskNotifyFromISR(xTaskDataQuery, 0, eNoAction, &xHigherPriorityTaskWoken);
   }
}

By queue I mean the FreeRTOS queue or message buffer, not a global shared variable buffer like this. The query task is “notified” when its receive operation on the queue or buffer unblocks.

Something like:

void vDataQueryTask(void* params) {
    uint8_t ucRxData[ 20 ];
    size_t xReceivedBytes;
    while (1) {
        xReceivedBytes = xMessageBufferReceive( xMessageBuffer,
                                            ( void * ) ucRxData,
                                            sizeof( ucRxData ),
                                            portMAX_DELAY );

    if( xReceivedBytes > 0 ) {
        // Do something useful
    }
}

uint8_t buffer[10];
void UART_Callback(USART_Handle_t *pUSART) {
   parseUsartData(pUSART, buffer);
   if (!strcmp(buffer, "something")) {
       	xMessageBufferSendFromISR( xMessageBuffer,
                                        ( void * )buffer,
                                        strlen( buffer ),
                                        &xHigherPriorityTaskWoken );
   }
}

Right, but then the ISR would be writing to the same queue that data query task is waiting on i.e same queue as opposed to two different queues, no?

I’m not sure I understand this question, but see my edit above for an example.

that’s what I was referring to in my previous comment.

And just saw your edit. I meant the same thing except I used xQueueSend() and xQueueReceive(). Haven’t looking into xMessageBufferSendFromISR() but I think it pretty much means the same - you post to a queue in the ISR, and then in the blocked queue you read from it, right?

Yeah, for the second queue I was referring to the same thing but sending data from the data processing task to the UART transmission task. May or may not be required, depending on your system design…

yeah that’s fair. We were referring to the same thing then. But why this approach over merely notifications where you wouldn’t have to post to a queue?

Because it’s a simple way to share data from the ISR to a task or between tasks. Otherwise how do you keep the ISR from overwriting the buffer contents if more data is received?

we would notify every time a data is received. Or you’re saying in case we receive data faster than we were able to notify?

after I’ve read the data, I don’t quite care about it so the incoming data could override without any problem I guess

So you notify and then what? The task starts processing data directly from buffer ? or copies it to a local version first? What if in the time you are doing that new data starts arriving over the UART?

actually the UART data is just acting as an “indication” as to what needs to be serviced. So it’s useful till the if condition and once that’s done, the rest is a matter of “executing” what the user requested. So if the user wanted sensor A data, the condition would unblock the desired task that would query the data from sensor A…

also, would like to know if you have any other idea around using RTOS. What I’m able to achieve here seems too simple for RTOS

Yes you could probably achieve what you want with a simple main loop and an ISR. The benefit of designing it with an RTOS up front is if you want to add more functionality later it may be easier to manage.

any suggestions on making good use of RTOS? i’m just starting and initial thought of expanding my existing bare metal project came first to my mind which seems to be trivial now

If you are doing this as a learning experience I would suggest trying out various techniques on this project and see how they work.

Another way is to use a StreamBuffer where you send each character to the task and do all the deciding there. That way you avoid any kind of string comparisons or other operations within the ISR.

isn’t streambuffer similar to writing to a queue and reading off of it? Is having an if condition in an ISR bad?