FIFO and Dereferencing struct

I can't seem to get the FIFO to work and I think it is because I'm not dereferencing the consumer thread properly. I have reviewed the nRF Connect SDK Intermediate, data passing and exercise2 FIFO already.

Within the data_item_t struct I am adding another struct. The data seems to go into the structure ok (checked via LOG_INF), but I can't get it out properly... Assuming I did all the FIFO stuff correctly. Any advice on how to dereference, or if I setup FIFO wrong, would be appreciated.

My producer thread creates:

LOG_INF("dcheck: producer thread: cmd: %d uuid: %s d0: %d", tx_data->MYGATE.cmd, tx_data->MYGATE.uuid, tx_data->MYGATE.d0);

[00:00:51.509,948] <inf> esb_child_event_handler: dcheck: producer thread: cmd: 7 uuid: 3BD5142E4BA09B49 d0: 9696110 (this is correct)

My consumer thread:

LOG_INF("dcheck: consumer thread: cmd: %d uuid: %s d0: %d\n", command, rx_data->MYGATE.uuid, rx_data->MYGATE.d0);

//[00:00:44.177,856] <inf> esb_child_event_handler: dcheck: consumer thread: cmd: 181 uuid: d0: 0 (not correct!)

I didn't show it, but I added data to MYGATE which is why the producer LOG_INF has the correct data.

For clarification and testing the data is produced and consumed immediately, so I expect the data to be the same.

typedef struct{
	uint8_t cmd; //command
	uint8_t chan; //channel number
	uint8_t prod; //product: Gate, Wearable, etc
	uint8_t isParent; //parent or child
	char uuid[HW_ID_LEN]; //processor uuid (char array)
	uint32_t d0; //data (integer)
	uint32_t d1; //data (integer)
	uint32_t d2; //data (integer)
	uint32_t d3; //data (integer)
	uint32_t d4; //data (integer)
	uint32_t d5; //data (integer)
	uint32_t d6; //data (integer)
} Device_t;

struct data_item_t {
    void *fifo_reserved;   /* 1st word reserved for use by FIFO */
    Device_t MYGATE;
};

void producer_thread(Device_t *_mygate)
{
    /* create data item to send */
    struct data_item_t *tx_data = k_malloc(sizeof(struct data_item_t));

    tx_data->MYGATE = *_mygate;

    LOG_INF("dcheck: producer thread: cmd: %d uuid: %s d0: %d", tx_data->MYGATE.cmd, tx_data->MYGATE.uuid, tx_data->MYGATE.d0);

//[00:00:51.509,948] <inf> esb_child_event_handler: dcheck: producer thread: cmd: 7 uuid: 3BD5142E4BA09B49 d0: 9696110 (this is correct)

    /* send data to consumers */
    k_fifo_alloc_put(&my_fifo, &tx_data);
    
    //k_free(tx_data); I don't think this can be freed before reading from consumer thread?
    //or can it because I used: k_fifo_alloc_put??
}

void consumer_thread()
{
    struct data_item_t  *rx_data;

    if(k_fifo_is_empty(&my_fifo) == 0){
        LOG_ERR("FIFO1 Queue is Empty");
    }
    else{
        rx_data = k_fifo_get(&my_fifo, K_NO_WAIT);

        /* process FIFO data item */
        Device_t temp = rx_data->MYGATE;

        LOG_INF("dcheck: consumer thread: cmd: %d uuid: %s d0: %d\n", command, rx_data->MYGATE.uuid, rx_data->MYGATE.d0);

//[00:00:44.177,856] <inf> esb_child_event_handler: dcheck: consumer thread: cmd: 181 uuid:    d0: 0 (not correct!)

        k_free(rx_data);
    }
}

void send_child_data2()
{
	COMMON_CHILD_TX_DATA_TO_SEND_FLAG = true;

	int duration = MYGATE.d1 - MYGATE.d0;

	MYGATE.d0 = MYGATE.d0 + PARENT_TIMESTAMP_OFFSET;
	MYGATE.d1 = MYGATE.d1 + PARENT_TIMESTAMP_OFFSET;
    MYGATE.cmd = cmd_data;

	if(!MYGATE.isParent)
	{		
		// esb_child_ptx_send_Tx2();
        producer_thread(&MYGATE);
        consumer_thread();

		LOG_WRN("CHILD(%s) d0: %d, d1: %d (%d) (P_TS_OFFSET: %d )", MYGATE.uuid, MYGATE.d0, MYGATE.d1, duration, PARENT_TIMESTAMP_OFFSET);
	}
}

  • The if() statement around the k_fifo_empty() call has its logic inversed. Check the rx_data pointer directly, it should be NULL with your code.

    The other clue would be that the consumer prints out before the producer, which is obviously wrong. Look at the time stamps in logs above.

  • Thanks! I probably copied the consumer print from my serial window out of order.

    I made progress and got the output I expected. And, I get both the queue has member and queue is empty messages. Thanks for your reply!

    void producer_thread(Device_t *_mygate)
    {
        /* create data item to send */
        struct data_item_t *buf = k_malloc(sizeof(struct data_item_t));
        if (buf == NULL){
            LOG_INF("Unable to locate memory from the heap");
            return ;
        }
    
        /* Populate the data item. This is usually done using memcpy() */
        memcpy(&buf->MYGATE, _mygate, sizeof(*_mygate));
    
        LOG_INF("dcheck: producer thread: cmd: %d uuid: %s d0: %d", buf->MYGATE.cmd, buf->MYGATE.uuid, buf->MYGATE.d0);
    
        /* send data to consumers */
        int err = k_fifo_alloc_put(&my_fifo, buf);
        if(err){
            LOG_ERR("ERROR, fifo alloc put failed: %d", err);
        }
    
        // k_free(buf); data access violation
    }
    
    void consumer_thread()
    {
        struct data_item_t  *rx_data;
    
        if(k_fifo_is_empty(&my_fifo)){
            LOG_ERR("FIFO1 Queue is Empty");
        }
        else{
            LOG_DBG("FIFO1 Queue has member");
        }
        
        rx_data = k_fifo_get(&my_fifo, K_NO_WAIT);
    
        /* process FIFO data item */
        Device_t temp = rx_data->MYGATE;
    
        LOG_INF("dcheck: consumer thread: cmd: %d uuid: %s d0: %d", temp.cmd, temp.uuid, rx_data->MYGATE.d0);
    
        k_free(rx_data);
    
        /*
            Returns Non-zero if the FIFO queue is empty.
            Returns 0 if data is available.
        */
    
        if(k_fifo_is_empty(&my_fifo)){
            LOG_ERR("FIFO2 Queue is Empty\n");
            k_sleep(K_MSEC(100));
            return;
        }
    }

Related