This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2640, TIRTOS: Queue entry gets lost

Other Parts Discussed in Thread: SYSBIOS

Hy there,

based on the OAD example from Sensor Tag I try to use a TI Sysbios Queue to buffer BLE messages until the application can process them.

I have the following code:

in main.c: function WriteCB() which is called as callback from my service (WriteAttrCB)

oadTargetWrite_t *oadWriteEvt = ICall_malloc( sizeof(oadTargetWrite_t));
Queue_enqueue(hOadQ, (Queue_Elem *)oadWriteEvt);
QueueCounter++;

in main.c, function taskFxn

    while (!Queue_empty(hOadQ))
    {
      oadTargetWrite_t *oadWriteEvt = Queue_dequeue(hOadQ);
      DeQueueCounter++;
    }

Ever once in a while (approx every 2000th time), the DeQueueCounter is one less than the QueueCounter, so apparently, the data gets queued but not unqueued.

The function Queue_enqueue has no return value. Is it possible, that the call is not successful?

Best regards

Harald

  • Hi Harald,

    It's difficult to see how Queue_en/dequeue could fail as it just manipulates memory. When the anomaly occurs, did you try inspecting the RAM contents of the Queue to see if there were any discrepancies? Do you see any NULL pointers in the Queue? Is everything contiguous? That's where I would start.

    Best wishes
  • Hi Harald,

    In addition 's suggestion you can also look into doing a check that the _malloc was successful (though that would have the opposite effect of what you are seeing I think).

    What contexts are the write callback called from? According to the TI RTOS API the _enqueue and _dequeue are not atomic (the _put and _get API's can be used for atomic access).

    .:svend
  • Hy,

    thanks for your quick response

    > Do you see any NULL pointers in the Queue?

    No, the prev/next pointer show always a decent address. It seems, that it toggles between two addresses, though. Obviously the ICall_malloc returns always the same two address ranges. That is kind of expected, because the dequeue/free code is probably called much more frequent than the enqueue/alloc part.

    > a check that the _malloc was successful

    Of course I do that already, I only left out this code in the post for shortness.

    >What contexts are the write callback called from

    oadWriteAttrCB is registered in GATTServApp_RegisterService. It is called, as soon as a new message arrives. Within oadWriteAttrCB I call processOadWriteCB, so it is in the same context as the callback of the incoming message. This is where I ICall_malloc and enqueue.

    My taskFxn is created with Task_construct from main.c. Within the taskFxn there is a while(1). In this while(1) I call the     while (!Queue_empty(hOadQ))

    The complete code looks like this:

    static void ProofOfConcept_processOadWriteCB(uint8_t event, uint16_t connHandle,
                                               uint8_t *pData, uint16_t len)
    {
    	oadTargetWrite_t *oadWriteEvt = ICall_malloc( sizeof(oadTargetWrite_t));
    
    	if ( oadWriteEvt != NULL )
    	{
    		oadWriteEvt->event = event;
    		oadWriteEvt->connHandle = connHandle;
    		oadWriteEvt->len = len;
    
    		memcpy(oadWriteEvt->pData, pData, MIN(OAD_PACKET_SIZE, len));
    
    		Queue_enqueue(hOadQ, (Queue_Elem *)oadWriteEvt);
    		OADQueueCounter++;
    		// Post the application's semaphore.
    		Semaphore_post(sem);
    	}
    	else
    	{
    		// Fail silently.
    		addEntryToSysRingBuf(ICALL_ALLOC_FAILED);
    	}
    }

    while(1)  // main loop within taskFxn
    {
        ....
        while (!Queue_empty(hOadQ))
        {
          oadTargetWrite_t *oadWriteEvt = Queue_dequeue(hOadQ);
          OADDeQueueCounter++;
          // Identify new image.
          if (oadWriteEvt->event == OAD_WRITE_CONTROL_REQ)
          {
            OAD_imgControlWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
          }
          // Write a next block request.
          else if (oadWriteEvt->event == OAD_WRITE_DATA_REQ)
          {
            OAD_imgDataWrite(oadWriteEvt->connHandle, oadWriteEvt->pData, oadWriteEvt->len);
          }
    
          // Free buffer.
          ICall_free(oadWriteEvt);
        }
        ....
    }

    As a workaround that seems to work I don't use ICall_malloc but malloc and not ICall_free but free. I needed to increase my heap in appBLE.cfg but now it works. Is there any reason why I should not use a normal malloc to copy data from a service callback to the applications task?

    Regards

    Harald

  • You can just as well use the built-in malloc/free instead. The TI RTOS kernel will use the HeapMem memory manager for those calls, effectively calling Memory_alloc and Memory_free behind the scenes.

    In case the issues with ICall malloc is caused by a memory leak somewhere you can trace that by defining HEAPMGR_METRICS as a compiler preprocessor symbol and check the value of a few variables as described in SWRU393 chapter 9.6 (http://www.ti.com/lit/ug/swru393/swru393.pdf)

    BR,
    Svend