5 years, 8 months ago.

How to print out a CAN message parameters using printf()?

I know that I can print out some of the separate parameters, like so:

print id

    pc.printf("%s:CAN frame received. ID: %x\n", timeBuffer, CANin.id);                      //where CANin is a CANMessage

But I'm confused about the other parameters of CANMessage class. It is defined as:

CANMessage

   51     /** Creates CAN message with specific content.
   52      *
   53      *  @param _id      Message ID
   54      *  @param _data    Mesaage Data
   55      *  @param _len     Message Data length
   56      *  @param _type    Type of Data: Use enum CANType for valid parameter values
   57      *  @param _format  Data Format: Use enum CANFormat for valid parameter values
   58      */
   59     CANMessage(unsigned _id, const char *_data, char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard)
   60     {
   61         len    = _len & 0xF;
   62         type   = _type;
   63         format = _format;
   64         id     = _id;
   65         memcpy(data, _data, _len);
   66     }

How would I print out CANFormat or CANType or the data of a CAN frame?

Also, for some CAN frames that I have received, when I do CANin.len I get nothing, yet I do use %c per expected type to get the length:

print id

    pc.printf("%s:CAN frame received. len: %c\n", timeBuffer, CANin.len);                      //where CANin is a CANMessage

I worked about a bit more and found how to print out every parameter separately, I think: pc.printf("%s:CAN frame received. len: %d, ID: %x, type: %d, format: %d, data: %x \n", timeBuffer, CANin.len, CANin.id, CANin.type, CANin.format, CANin.data);

Can anyone confirm this is the correct way to do it? I wish I could output whole CANMessage but is it even possible?

posted by L B 13 Mar 2019

1 Answer

5 years, 8 months ago.

Something like this should do it:

void printCanMessage(CANMessage &message) {
  pc.printf("CAN message %s ID 0x%x ", (message.format == CANExtended)?"Extended":"Standard", message.id);
  pc.printf(" message type: %s data length: %u\r\nData: ", (message.type  == CANData)?"Data":"Remote", message.len);
  for (int i=0;i<message.len;i++) {
    pc.printf(" %02X",*(message.data+i));
  }
}

// in your code
printCanMessage(CANin);

This should print out the packet information and then the data contents. I split the initial printf into 2 lines just to keep it easier to read, there is no reason why you couldn't do it all in one line.

length is of type %d not %c because it is a number from 0 to 8 not a text character '0' to '8'. They use of a data type char rather than int is purely to save memory, why use 4 bytes to hold a value that can never be over 8.

type and format you can print as %d and you'll either get 0 or 1 depending on the type. But what that means requires you to make assumptions as to the values used for the enums. While you can do that and in this situation it's fairly safe the more correct thing to do is compare them to the possible enum values and decode the meaning.

In case you're not familiar with it (message.format == CANExtended)?"Extended":"Standard" is just a shorthand way of saying if (message.format == CANExtended) "Extended" else "Standard", it's a handy way of picking between two strings in a printf output.

Accepted Answer