1

I have a CAN bus message that is composed from 3 parts. What is the best way to decode it ?

My thinking is to use 3 FIFOs when the first part is decompsed, I store it in the FIFO, and the same for the other 2 parts.

Then I combine those 3 Fifos togethers into one message.

The total message length is 64bytes PDU Lenght

I'm using the following function to get can bus data

HAL_CAN_GetRxMessage

can bus

andreahmed
  • 29
  • 5
  • Decode it into what? Why a fifo and not an array or string? FIFOs seem like a lot of data structure for a holding area where you don't need any actual FIFO functionality. – Dave Newton Jun 25 '19 at 12:07
  • You're correct, so I would use an Array or string. But how would I combine those 64 bytes PDU messages into one message. Those 8 messages contains a hashed string which is length of 64 bytes, so I need to combine those 8 messages together to reconstruct the hash value – andreahmed Jun 25 '19 at 12:10
  • You know how long you need, and computers are pretty good at math: store each message into the allocated space at the appropriate offset. It's not really clear to me what the problem is. – Dave Newton Jun 25 '19 at 12:18
  • @andreahmed Can you show the `PDU` layout? Basically how many signals and length of the each signals. – kiran Biradar Jun 25 '19 at 12:18
  • Considering your edit (the description of what you are trying to decode) I think your question is too broad : do you want us to give you some code that can retreive the payload accordingly to your protocol or do you want us to give you some code to rebuild the ASCII chain that you are receiving? In both case, we cannot see what you already tried and it looks like to me (considering your others recent posts this time) that you are trying to get some code without even trying to write some. – Benoît Jun 25 '19 at 14:11

2 Answers2

0

Considering the standard CAN message is of size 8bytes length, you can declare message as uin64_t and combine the respective signals into message using |.

Example:

uint64_t message = 0;
uint8_t incomingBytes[8] = {0};

for(int i=0; i<8; i++)
{
    message = message <<8;
    message |= incomingBytes[i];
}

If you want to interpret VIN data as string then,

 char vindata [9];
 memcpy(vindata, incomingBytes, 8);
 vindata[8] = '\0';
kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
  • I added the image of the CAN bus message, please take a look at it – andreahmed Jun 25 '19 at 12:33
  • @andreahmed You are good to go with above suggestion unless if you ant interpret `VIN` as string Also you can ignore `1st byte` as it is header. – kiran Biradar Jun 25 '19 at 12:38
  • 1
    Bad idea because of endianess. – Lundin Jun 25 '19 at 12:53
  • @Lundin Endianess can be handled by properly indexing the `incomingBytes` before to that he should know what endianess he has on his platform. – kiran Biradar Jun 25 '19 at 12:59
  • @Lundin You always come to rescue, do you know a solution with ignoring endianess and agnostic to it – andreahmed Jun 25 '19 at 13:04
  • @kiranBiradar The problem is that `incomingBytes` will have protocol endianess and the CPU will have a different endianess. If you store everything as a raw array of bytes instead, you will have it in the order demanded by the protocol, without the need to serialize/de-serialize. And as a bonus, the code will be portable to cores with another endianess too. – Lundin Jun 25 '19 at 13:08
  • @Lundin I agree with you, but only pain is accessing the stored raw bytes. My point is if message comprises of multiple signals varying with size 1bit to 64bits, it is really pain to access individual signals out of raw bytes. If I store it as `uint64_t` you can mask it according to message layout to extract certain signals as needed. – kiran Biradar Jun 25 '19 at 13:10
  • @kiranBiradar It wouldn't be very sensible of the person designing the CAN protocol to place things like that. For example CANopen uses 16 bit analog channels, even though you are most often not likely to use 16 bit resolution - they could have made it 12 bits and that would have covered most applications. However, 16 bits make it easier to write programs decoding/encoding the frames. – Lundin Jun 25 '19 at 13:17
  • But endianess on the other hand, is a very common and painful problem when working with CAN specifically. You can have a CPU with little endian, an external CAN controller with big endian, the actual CAN frame with big endian identifiers and big endian CRC, then the payload which could for example be CANopen, which always uses little endian. To deal with such a mess, the only sensible approach is an array of bytes. – Lundin Jun 25 '19 at 13:18
  • @kiranBiradar Thanks for your answers. Actually there is 3 Messages that has one stdid, so how would I combine those three messages of the same stdid ? they have the same header too – andreahmed Jun 26 '19 at 06:53
0

Using the answer to your previous question from here, you can use that bitfield in combination with a plain uint8_t [64]. For example

typedef struct
{
  uint8_t data[64];
  can_received_t received;
} msg_t;

Fill up with data as you receive it, writing it to the corresponding data bytes, then set the bit to indicate that the message has been partially received. The struct isn't regarded as complete until you have received all parts.

A queue/FIFO only fills one purpose, and that is to delay execution of something until later, when there's more time. There's no reason to do that here. Your CAN message decoding could look something like:

msg_t msg;

switch(received_can_id)
{
  ...
  case CANID_FOO:  
    memcpy(&msg.data[FOO_INDEX], rec_data, FOO_SIZE);
    msg.received |= RECEIVED_FOO;
    break;

  case CANID_BAR:
    memcpy(&msg.data[BAR_INDEX], rec_data, BAR_SIZE);
    msg.received |= RECEIVED_BAR;
    break;
  ...
}

if(msg.received == RECEIVED_ALL)
{
  use(&msg); // do something
  memset(&msg, 0, sizeof msg); // reset everything
}

This is fairly quick code, no need to queue anything.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thanks, but it's only one message id as shown in the excel, why did you separate it in multiple messages ? – andreahmed Jun 25 '19 at 13:10
  • @andreahmed No one defines `CAN` network to handle only one message, This is the usual way of decoding the `CAN` data. i:e decode the data as per message ID(PUD ID). – kiran Biradar Jun 25 '19 at 13:15
  • @kiranBiradar He could be implementing something like CAN-TP, which allows to transmit a payload of more than 8 bytes using a single ID. Then the proposed solution doesn't really fit (in the current state) – Benoît Jun 25 '19 at 13:20
  • @kiranBiradar There is only one message ID, why there are many CANID_FOO,.. CANID_Bar ther e? – andreahmed Jun 25 '19 at 13:21
  • @Benoît That's really true – andreahmed Jun 25 '19 at 13:21
  • @andreahmed I have no idea what your actual protocol looks like, I only answered the question "decoding multiple message of CAN bus". This is how you'd typically do it when decoding fragmented messages with data scattered over several frames. They don't necessarily need to have different CAN identifiers, they could have some high-level label to separate them, or different DLC etc etc. It won't make much of a difference to the algorithm that puzzles everything back together. – Lundin Jun 25 '19 at 13:24
  • @Lundin Hello, Thanks for your answers. Actually there is 3 Messages that has one stdid, so how would I combine those three messages of the same stdid ? they have the same header too – andreahmed Jun 26 '19 at 06:52
  • @andreahmed That would entirely depend on what part of the application layer rotocol that's used to indicate a difference between message types. I don't know anything about whatever application layer you are using. – Lundin Jun 26 '19 at 10:54