Libcanard and DSDL on Teensy4.1

Hello Everyone

I am working on Teensy 4.1 trying to send and receive UAVCAN packets, I use Libcanard, and referring to the documentation in GitHub - OpenCyphal/libcanard: A compact implementation of the Cyphal/CAN protocol in C for high-integrity real-time embedded systems I could generate can frames, actually I am still new with this protocol and I have some doubts regarding the output frames, as mentioned in the documentation the first two bytes of the first frame generated supposed to be the CRC but I do not see that, I am using canardTxPush, canardTxPeek, and canardTxPop to parse the packet and split it (if needed) to a set of frames.
Hint: I am using the “malloc()” and the “free()” functions to allocate and deallocate the memory because the o1heap library does not work on Teensy and I do not know why.
I print the input and output of my program as the following:

program start...
Input packet:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
number of frames enqueued: 4

Generated frames>>>>
0 1 2 3 4 5 6 160 
7 8 9 10 11 12 13 0 
14 15 16 17 18 19 20 32 
221 10 64 134 169 14 0 0  
program finish......

the following is the simple code I use:


#include <Arduino.h>
#include <FlexCAN_T4.h>
#include "LIBCAN.h"

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;

CAN_message_t can_msg;

static void* my_all;
static void* mal(CanardInstance* const canard, const size_t amount){
  my_all = (void*)malloc(amount);
  return my_all;
}
static void fre(CanardInstance* const canard, void* const pointer){
  free(pointer);
}

void setup()
{
  Serial.begin(9600);
  can1.begin();
  Serial.println("program start...");

  CanardInstance canard2 = canardInit(&mal, &fre);
  canard2.node_id = 42; 
  CanardTxQueue queue = canardTxInit(10, CANARD_MTU_CAN_CLASSIC);
  
  uint64_t addr2 = (uint64_t)canard2.memory_allocate;
  
  static uint8_t my_message_transfer_id;
  
  const CanardTransferMetadata transfer_metadata = {
    .priority       = CanardPriorityNominal,
    .transfer_kind  = CanardTransferKindMessage,
    .port_id        = 1234,                       // This is the subject-ID.
    .remote_node_id = CANARD_NODE_ID_UNSET,       // Messages cannot be unicast, so use UNSET.
    .transfer_id    = my_message_transfer_id,
  };

  uint64_t tx_deadline_usec = 0xEE;

  uint8_t paylo[60];
  Serial.println("Input packet:");
  for(int y=0; y<21; y++){
    paylo[y] = y;
    Serial.print(y);
    Serial.print(" ");
  }
  Serial.println();

  ++my_message_transfer_id;  // The transfer-ID shall be incremented after every transmission on this subject.
  int32_t result = canardTxPush(&queue,               // Call this once per redundant CAN interface (queue).
                                &canard2,
                                tx_deadline_usec,     // Zero if transmission deadline is not limited.
                                &transfer_metadata,
                                21,                   // Size of the message payload (see Nunavut transpiler).
                                paylo);
  
  if (result < 0)
  {
    Serial.println("Error!!!!!!");
  }

  Serial.print("number of frames enqueued: ");
  Serial.println(result);
  
  const CanardTxQueueItem* data;

  uint8_t* payload_array;

  Serial.println();
  Serial.println("Generated frames>>>>");

  for(int c=0; c<result; c++){
    delay(1000);
    data = canardTxPeek(&queue);
    payload_array = (uint8_t*)data->frame.payload;
    for(int i=0; i<CANARD_MTU_CAN_CLASSIC; i++){
      can_msg.buf[i] = payload_array[i]; 
      Serial.print(payload_array[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    canard2.memory_free(&canard2, canardTxPop(&queue, data));
  }

  CanardRxSubscription heartbeat_subscription;

}

void loop() 
{
  Serial.println("program finish......");
  while(true);
}

My questions are as the following:

  1. why I can not see the CRC bytes at the beginning of the first frame?
  2. As shown that there are some additional bytes at last frame generated, what do they mean and from where they come?
  3. where can I find the standard DSDL definition and how to use it?

Thanks in advance

The old layout with the CRC at the beginning was used by an experimental version of the protocol, which is now called DroneCAN. Cyphal/CAN appends the CRC at the end of the transfer. See Cyphal vs. DroneCAN.

The additional bytes are the transfer CRC.

1 Like

You could port 107-Arduino-Cyphal to Teensy :person_shrugging: .

1 Like

Thank you Mr Pavel for supporting

everything is working as it should be, I have some questions regarding Cyphal and DroneCAN, I read the differences between these two protocols but I am still wondering about the possibility of using these two protocol together, the following questions summarize my doubts:

1- it seems that the only difference between the two protocols in term of the data field format is the CRC bytes location, is that right?
referring to:
“https://opencyphal.org/specification/Cyphal_Specification.pdf”
“4. CAN bus transport layer - DroneCAN”

2- if the answer of the first question is YES, then I think I can receive DroneCAN packets, manipulate and reorder it, then pass it again to Cyphal functions (such as canardRxAccept()) and vice versa, am I right or I missed something?

generally, as I mentioned previously that I am working on Teensy unit and I have a Pixhawk autopilot which sends a customized DroneCAN messages through CAN1, so, I am trying to integrate these two unit to work together (transmitting and receiving), is that possible?

Almost. The toggle bit is also inverted in Cyphal/CAN; this is done to enable automatic protocol detection.

The first question is not “yes” but you’re almost correct, although I don’t immediately see much utility in this, as the protocols are too different for such unification to be sensible. I could be wrong, though. Remember that DroneCAN not only encodes the CRC differently but also computes it differently – the CRC register is pre-seeded with the data type signature. There is no such concept in Cyphal/CAN.

It is probably possible, but I would rather start using Cyphal/CAN properly on your Pixhawk.

You are right, I forgot to mention this difference as well.

Yes, I just found that there are “Singnature” bytes that are used in CRC calculations, so it seems that it is better to unify the protocol used in both units (teensy and pixhawk), and surely I prefer to use Cyphal since I found it more robust and compatible with DCPS architecture.

I really appreciate your continuous help and support Mr Pavel.
Thank you

1 Like