Homepage GitHub

Various questions about libcanard

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");

				}

Because you are converting DLC to length incorrectly. You need a mapping function similar to what I posted above, but inverse.

Is the actual length of the data being sent, or can only be the following value
0
1
2
3
4
5
6
7
8
12
16
20
24
32
48
64

What you listed are the only valid payload lengths of a CAN FD data frame. For example, one can’t send a CAN FD data frame with 35 bytes of payload; one would have to pad it out to 48 bytes. In your specific case, the library does the padding for you, so you don’t have to bother.

I found that when I transmitted more than eight bytes(7bytes data + 1 tail byte) of data, I could not receive it successfully.
I have done this:

received_frame.payload_size = CanardCANLengthToDLC[RxHeader.DataLength >> 16];
// --------------------------------------------- PUBLIC API---------------------------------------------

const uint8_t CanardCANDLCToLength[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
const uint8_t CanardCANLengthToDLC[65] = {
    0,  1,  2,  3,  4,  5,  6,  7,  8,                               // 0-8
    9,  9,  9,  9,                                                   // 9-12
    10, 10, 10, 10,                                                  // 13-16
    11, 11, 11, 11,                                                  // 17-20
    12, 12, 12, 12,                                                  // 21-24
    13, 13, 13, 13, 13, 13, 13, 13,                                  // 25-32
    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  // 33-48
    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  // 49-64
};

The conversion between DLC and length is incorrect. Please do it as I suggested above.

Thanks a lot ,but I still don’t know what parameter to pass in. :confounded:

received_frame.payload_size =xxxxx;

xxxxx: I don’t konw what is this length going to be?
RxHeader.DataLength >> 16 or CanardCANLengthToDLC[RxHeader.DataLength >> 16] or the size of the data i send ,for example :the flowing , 4 ?

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);   // msg3
	canardDSDLSetUxx(&my_msg[0], 	24,          		0xff,  		8);   // msg4

The last option is correct. As the name of the field suggests (payload_size), it is the size of the payload, in bytes. Not DLC.

Thank you very much. I will try it again.

Still can not receive success :expressionless:
Didn’t I set the FDCAN for Uavcan

Maybe this example can help you?

ok,thanks a lot