Message Queue Data

groger57 wrote on Friday, November 18, 2016:

Hello:
I’m trying to get a message queue functioning in a particular way but having a bit of trouble, so hoping that someone could provide some help. First, I need to send data to a UART using a single-point queue. So I have created that queue and it works with no issues.

However, I have 2 structure types I need to get to the queue. The first has 12 different data members. The size of the struct is 41 bytes - call this “sType”
Some of the messages I need to send to the UART are strings only, used to control the touchscreen. So I have defined another structure that contains just 2 data members, an int and an array of 40 chars. Also 41 chars. Call this “uType”.

Since the queue task handler was created for “sType”: uint16_t QUEUE_ITEM_SIZE = sizeof( *sType );

How can I possibly send an instance of the other data structure to the queue? In short, I need to send one of 2 types to the queue.

Thank you for any help on this.

rtel wrote on Friday, November 18, 2016:

As in both cases you are sending quite a lot of date it might be best to
send a pointer to the data, rather than the data itself. Then you have
two options:

  1. Have the first member of both structures identify the structure type.
    So when you receive a pointer from the queue you de-reference the
    first byte or word (depending) to see what the structure is (the first
    byte or word identifying the structure). Then when you know what the
    structure is you can cast the pointer to whichever structure it was
    determined to be.

  2. Create the queue to hold structures that have two members. The first
    member identifies what the second member points to. So you receive the
    structure from the queue, check the first member to determine what the
    second member is pointing to, then cast the second member to whichever
    structure it was determined to be.

Of course, when queuing pointers to structures, rather than queuing the
structures themselves, you have to be careful that the sender does not
access the structure again until the receiver has finished with it.
That can be done by having the receiver return the structure to a pool
of structures when it is finished with it, or have the sender
dynamically allocate the structure and the receiver free the structure
again (not always a good solution, but it depends on your scenario).

groger57 wrote on Friday, November 18, 2016:

Hi,
Thanks for the explanation.
I tried both methods, and they both work. In the sending task I have 2 (test) assignments where I assign the structure “type”, format the appropriate string buffer and then use the function xQueueSendToBack to send the structure pointer. The sending task (for testing) is called at 1000ms.

However: if I do not put “vTaskDelay(x)” between those 2 calls in the sending task, the queue handler always identifies the structure as the first one I sent. The delay can be 1 millisecond, and it works fine.

Again - this occurs with either method you described.

rtel wrote on Friday, November 18, 2016:

Are you 100% sure you are not accidentally using, sending, or checking
the same buffer (that is, the buffer being pointed to) twice? Also,
only the buffer that contains the data should be pointed to - the
structure that contains the pointer to the data should still be copied
to the queue in the normal way.

groger57 wrote on Friday, November 18, 2016:

Yes, I think everything is correct. From the sending task:

vTaskDelayUntil( &xLastCheckTime, TEST_SEND_RATE );

memzero( scrObj->str, 20 );        
strType->type = iTOOL;     
sprintf( scrObj->str, "%s", "Here is data for #1\r" );
xQueueSendToBack(screenUpdatesQueue, strType, portMAX_DELAY ); 
        
vTaskDelay(1);   //need this here to work...     
        
memzero( uartObj->str, 43 );        
sprintf( uartObj->str, "%s", "Here is bigger data for #2\r" );
strType->type = iUART;
xQueueSendToBack(screenUpdatesQueue, strType, portMAX_DELAY );

Then, from the queue handler:

QueueHandle_t taskQueue = (QueueHandle_t) pvParameters;

if( xQueueReceive  ( taskQueue, strType, portMAX_DELAY ) == pdPASS)
{
    if( strType->type == iUART )
    {
         uartObj = (uOBJ *) strType;
         printf("UART TYPE: Handle = %i, str = %s\n", uartObj->handle, uartObj->str );
    }
   else
   {
      scrObj = (sOBJ *) strType;
      printf("NOT UART TYPE: Handle = %i, str = %s\n", scrObj->handle, scrObj->str );   
   }

Also, something strange. When I allocate memory for the strType pointer struct, I also cast it to one of the types so it’s pointing at something:

strType = malloc(sizeof(sPTR));
strType->pType = (uOBJ*)uartObj;
strType->type = iUART;

In spite of this, on the first pass, both strings are junked out.

What am I missing, that it works with the vTaskDelay() in between, and does not if it’s not there? In either case, with or without the delay, the first pass prints junk from the string buffer (although the type is correctly identified)

Thanks again for your assistance.

rtel wrote on Friday, November 18, 2016:

It’s not clear to me what this code is doing. I have tried to annotate it with comments below:

/* Does scrObj->str point to a buffer, or is it an array? */
memzero( scrObj->str, 20 );

/* Setting the type of the object being pointed to to iTOOL, and
writing text to the buffer pointed to by scrObj->str. */
strType->type = iTOOL;     
sprintf( scrObj->str, "%s", "Here is data for #1\r" );

/* Writing the value of the strType pointer to the queue. So this
will post the address held in the strType variable to the queue.
Is strType pointing to scrObj at this point? */
xQueueSendToBack(screenUpdatesQueue, strType, portMAX_DELAY ); 

vTaskDelay(1);   //need this here to work...     

/* Do the same for uartOjb. */
memzero( uartObj->str, 43 );        
sprintf( uartObj->str, "%s", "Here is bigger data for #2\r" );
strType->type = iUART;

/* strType has not been updated since the last call to
xQueueSendToBack(), so it is still pointing to the same
thing.  So the receiving task will receive the same pointer
value twice - so would expect to receive the same thing twice.
What is strType pointing to?  If the receiving task has an
equal or lower priority I expect this to go wrong because what
is being pointed to is overwritten by the sending task before
the receiving task has accessed it (also explains why adding
the vTaskDelay(1) fixes the issue, as that would allow the
receiving task to run and process the first message before the
sending task overwrites it). */
xQueueSendToBack(screenUpdatesQueue, strType, portMAX_DELAY );