xQueueReceive Issue

hillridge wrote on Tuesday, August 27, 2019:

I am attempting to pass a pointer to a struct via queue, but something odd is happening on the receiving end that has me stumped. I’m pretty confident it’s something dumb (and probably obvious) that I’m doing, I just don’t know what.

I create the queue:

xQueue_myQueue = xQueueCreate(4,sizeof(my_struct_t*));

Then I send:

my_struct_t new_struct;
xQueueSend(xQueue_myQueue, (void *) &new_struct, 0);

Then I receive:

my_struct_t* pThing;
xQueueReceive(xQueue_myQueue, &(pThing), 0))

The problem is that pThing winds up being set to the value of the first member in new_struct rather than the address of new_struct. I check, and the address of new_struct is correctly getting passed into xQueueSend, so why is pThing being set to new_struct.member1 on the receiving end?

hillridge wrote on Tuesday, August 27, 2019:

I knew it was dumb, I just re-read everything and realized that when passing a pointer via a queue, the xQueueSend call needs to be passed a pointer to the pointer, not the pointer itself!

richard_damon wrote on Tuesday, August 27, 2019:

Your send is passing the address of the struct, but you should be passing a point that points to the address of the struct. The parameter is a pointer to the data, not the data itself.

Your send shoud be more like:

my_struct_t new_struct;
my_struct_t* strucrtPtr = &new_struct;

xQueueSend(xQueue_myQueue, &struct_ptr, 0);

One other thing to watch out, If you are passing a struct created on the stack of the first task (by declaring it in the body of a function) then you need to be careful that the struct keeps living until the receiving task is done with it.

hillridge wrote on Tuesday, August 27, 2019:

I figured this out as you were posting your response, but glad I finally realized what was going on.

Thanks for the warning, I have that exact situation and had set up the sending function to yield (via a vTaskDelay) until a status byte in the struct changes to indicate that it had been serviced. I feel like there is probably a less clumsy way to do that though.

richard_damon wrote on Tuesday, August 27, 2019:

One comment, I find that often the program structure of Task A sending message to Task B, and then having to wait for a response from Task B works better by just having the code from Task B be part of Task A (perhaps a function call). There can be cases where it makes sense (typically if Task B does more after it returns the answer), but often things can be simplified by not having B be a seperate task.

hillridge wrote on Tuesday, August 27, 2019:

I agree. In this case TaskA is a task requesting an input, and TaskB is the main GUI task. The problem I had was that allowing the GUI to continuously update while still waiting for user input became complicated if I kept them in the same task.

So now, a function in some other task sends a request to the GUI task, then waits until it detects that the request has been completed before returning the result. Is there a cleaner/better way to do this instead of inserting a small vTaskDelay? I didn’t want to use a Yield call because I can’t be sure of the calling task’s priority level relative to the GUI.

richard_damon wrote on Tuesday, August 27, 2019:

Yes, the GUI should be a seperate task, and not called by pieces of other tasks, That falls into the doing more after returning an answer.

FIrst, I suspect in this case the struct being sent is small, and it may be better to send the struct itself and not a pointer (or maybe even use a MessageBuffer). I would not have the ‘calling’ task wait with a vTaskDelay, but use a semaphore/Queue/MessageBuffer to return the results (or presence of it being in a mailbox for a semaphore).