Various questions about libcanard

What does this code to do at canardRxAccept in canard.c

         while ((sub != NULL) && (sub->_port_id != model.port_id))
                {
                	
                    sub = sub->_next;
                 
                }

Thank you very,very, very much!

      // There are two possible reasons why the session may not exist: 1. OOM; 2. SOT-miss.
        if (subscription->_sessions[frame->source_node_id] != NULL)
        {  
            CANARD_ASSERT(out == 0);
            out = rxSessionUpdate(ins,
                                  subscription->_sessions[frame->source_node_id],
                                  frame,
                                  redundant_transport_index,
                                  subscription->_transfer_id_timeout_usec,
                                  subscription->_payload_size_max,
                                  out_transfer);
        }

What does “SOT-miss.” mean?

Start of transfer?

   out->payload_size = frame->payload_size- 1U;  // Cut off the tail byte.

I found that this line of code caused me to miss one byte of data that I received. Could you please give me some guidance?

You don’t need this byte because it contains the transport metadata that is consumed by the library.

When I continuously send the heartbeat node and the custom node information, after being processed by canardRxAccept, I can only receive each node once, from which canardRxAccept will not return 1. Why?

Is it because it’s the first frame of a transfer?

And. When i send 8 bytes,canardRxAccept return 0 , how to send multi frame ? :sob:

Re first question: you probably forgot to make the transfer-ID variable static. If that’s the case, then you’re sending multiple transfers under the same transfer-ID, which are then rejected by the receiving node as duplicates.

Re second question: sending a multi-frame transfer is no different from sending a single-frame transfer.

I’m confused about tranfer-ID.
I made "static uint8_t my_message_transfer_id;"And “+ + my_message_transfer_id;”
However, when I sent the transfer-ID, I did not send it to the receiver, but only transmitted the data(.payload) to the receiver. So how to set the tail byte of the data I sent?

                       uint8_t my_msg[10] = {0};
			canardDSDLSetUxx(&my_msg[0], 	0,          		10,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	8,          		110,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	16,          		120,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	24,          		87,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	32,          		12,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	40,          		99,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	48,          		0xDEADAA,  		24); 
// ----------------------------------- how to set the tail byte ---------------------------------------------------------------------------------   
canardDSDLSetUxx(&my_msg[0], 	72,          		?????,  		8);   // how to set the tail byte ?

						
			static uint8_t mymsg_transfer_id;				
			const CanardTransfer mytransfer = {
				.timestamp_usec = 0,      
				.priority       = CanardPriorityNominal,
				.transfer_kind  = CanardTransferKindMessage,
				.port_id        = 32080,                       // This is the subject-ID.
				.remote_node_id = CANARD_NODE_ID_UNSET,      // Messages cannot be unicast, so use UNSET.
				.transfer_id    = mymsg_transfer_id,
				.payload_size   = 10,   
				.payload        = &my_msg[0], 
			};
			++mymsg_transfer_id;  
			int32_t myresult = canardTxPush(&ins, &mytransfer); 
                        ……………………(omit)
                        	
		uint8_t fail_count;
		FDCAN_TxHeaderTypeDef *txmsg = NULL;

		for (const CanardFrame* txf = NULL; (txf = canardTxPeek(&ins)) != NULL;)  // Look at the top of the TX queue.
		{
			printf("enter txmsg:\n");
			uint8_t sendbuf[64] = {0};

			txmsg->Identifier = txf->extended_can_id;  //32085txf->extended_can_id
	txmsg->DataLength = (txf->payload_size-1) << 16 &  0x000F0000U; //to set the stm32 FDCAN_TxHeaderTypeDef
			txmsg->IdType = FDCAN_EXTENDED_ID;
			txmsg->FDFormat = FDCAN_FD_CAN;
			txmsg->TxFrameType = FDCAN_DATA_FRAME;
			txmsg->BitRateSwitch = FDCAN_BRS_OFF;
			txmsg->TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
			txmsg->ErrorStateIndicator = FDCAN_ESI_ACTIVE;
			txmsg->MessageMarker = 0x01;



			memcpy(sendbuf,txf->payload,(txf->payload_size-1)); 

//-------------use stm32 fdcan send to the receiver ,only send buf, do not send transfer-id to receiver------------------------------
HAL_StatusTypeDef ret = HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, txmsg, sendbuf); 
		HAL_FDCAN_Start(&hfdcan1); /

Replace this:

txmsg->DataLength = (txf->payload_size-1) << 16 &  0x000F0000U;

With this:

txmsg->DataLength = convertDataLengthToFDCANDLC(txf->payload_size);

Where convertDataLengthToFDCANDLC is defined as:

uint32_t convertDataLengthToFDCANDLC(const size_t length)
{
    static const uint32_t Lookup[65] = {  // TODO Please carefully check these.
        // 0-8
        FDCAN_DLC_BYTES_0,
        FDCAN_DLC_BYTES_1,
        FDCAN_DLC_BYTES_2,
        FDCAN_DLC_BYTES_3,
        FDCAN_DLC_BYTES_4,
        FDCAN_DLC_BYTES_5,
        FDCAN_DLC_BYTES_6,
        FDCAN_DLC_BYTES_7,
        FDCAN_DLC_BYTES_8,
        // 9-12
        FDCAN_DLC_BYTES_12,
        FDCAN_DLC_BYTES_12,
        FDCAN_DLC_BYTES_12,
        FDCAN_DLC_BYTES_12,
        // 13-16
        FDCAN_DLC_BYTES_16,
        FDCAN_DLC_BYTES_16,
        FDCAN_DLC_BYTES_16,
        FDCAN_DLC_BYTES_16,
        // 17-20
        FDCAN_DLC_BYTES_20,
        FDCAN_DLC_BYTES_20,
        FDCAN_DLC_BYTES_20,
        FDCAN_DLC_BYTES_20,
        // 21-24
        FDCAN_DLC_BYTES_24,
        FDCAN_DLC_BYTES_24,
        FDCAN_DLC_BYTES_24,
        FDCAN_DLC_BYTES_24,
        // 25-32
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        FDCAN_DLC_BYTES_32,
        // 33-48
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        FDCAN_DLC_BYTES_48,
        // 49-64
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
        FDCAN_DLC_BYTES_64,
    };
    // TODO Check the array bounds.
    return Lookup[length];
}

You are not supposed to do anything with the tail byte yourself. The library does it automatically, just let it do its job.

Note that I did not test any of this.

Does that mean I can just write my data?Don’t I have to deliberately modify the last byte in the data?

            uint8_t my_msg[10] = {0};
			canardDSDLSetUxx(&my_msg[0], 	0,          		10,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	8,          		110,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	16,          		120,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	24,          		87,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	32,          		12,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	40,          		99,  		8);   
			canardDSDLSetUxx(&my_msg[0], 	48,          		0xDEADAA,  		24); 
// ----------------------------------- how to set the tail byte ---------------------------------------------------------------------------------   
canardDSDLSetUxx(&my_msg[0], 	72,          		?????,  		8);   // how to set the tail byte ?

Of course, that’s what the library is for.

But i found i do that , i can not receive anything . :sob:

When i send single frame, make the last data “0xff” , i can receive once . If do not do that ,i can not receive anything. :expressionless:

			uint8_t my_msg[4] = {0};
			canardDSDLSetUxx(&my_msg[0], 	0,          		10,  		8);   // msg1
			canardDSDLSetUxx(&my_msg[0], 	8,          		110,  		8);   // msg2
			canardDSDLSetUxx(&my_msg[0], 	16,          		120,  		8);   // msg1
			canardDSDLSetUxx(&my_msg[0], 	24,          		0xff,  		8);   // msg2

This is because you are truncating the tail byte in your txmsg->DataLength = (txf->payload_size-1) << 16 & 0x000F0000U;.

OK, thank you very much. I try it again.

When i receive data , the receive data length is set to "received_frame.payload_size = RxHeader.DataLength >> 16 ;
If the data i send is 10 bytes , it can not receive anything. How can i set the received_frame.payload_size correctly?
Thanks.


				FDCAN_RxHeaderTypeDef RxHeader={0};

				uint8_t recdata[64] = {0};  
				uint8_t payload_recdata[64] = {0}; 
				CanardFrame received_frame = {0};
			   	received_frame.payload = &payload_recdata;




				 if(HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &RxHeader, recdata) == HAL_OK) 
				{
					 
				CanardTransfer receive={0}; 
				received_frame.extended_can_id = RxHeader.Identifier ;
				received_frame.payload_size = RxHeader.DataLength ; 

				memcpy(payload_recdata,recdata,received_frame.payload_size)


				uint8_t result = canardRxAccept(&ins,
										&received_frame,            // The CAN frame received from the bus.
										0,  						// If the transport is not redundant, use 0.
										&receive);
				if (result < 0)
				{
					// An error has occurred: either an argument is invalid or we've ran out of memory.
					// It is possible to statically prove that an out-of-memory will never occur for a given application if
					// the heap is sized correctly; for background, refer to the Robson's Proof and the documentation for O1Heap.
					// Reception of an invalid frame is NOT an error.
					printf("RxAccept failure\n");
					printf("An error has occurred: either an argument is invalid or we've ran out of memory.\n");
					abort();
				}
				else if (result == 1) 
				{
					uint8_t final_data[64] = {0};
					memcpy( final_data,receive.payload,receive.payload_size);
					uint8_t  mode   = canardDSDLGetU8(final_data,  receive.payload_size, 34,  3);
					uint32_t uptime = canardDSDLGetU32(final_data, receive.payload_size,  0, 32);
					uint32_t vssc   = canardDSDLGetU32(final_data, receive.payload_size, 37, 19);
					uint8_t  health = canardDSDLGetU8(final_data,  receive.payload_size, 32,  2);

					printf("mode = %d\n",mode);
					printf("health = %d\n",health);
					printf("uptime = 0x%x\n",uptime);
					printf("vssc =   0x%x\n",vssc);

					ins.memory_free(&ins, (void*)receive.payload);  // Deallocate the dynamic memory afterwards.
				}
				else
				{

					// Nothing to do.
					// The received frame is either invalid or it's a non-last frame of a multi-frame transfer.
					// Reception of an invalid frame is NOT reported as an error because it is not an error.
					printf("nothing to do \n");

				}