Converting a series of numbers into a 64 bit binary frame..?

Hi all!

I'm trying to create a CAN bus message which is a 64 bit binary frame held in a uint64_t variable.

I have 8 variables which I want to send, one per byte

In this case I have:
SideLights = 1 or 0
MainLights = 1 or 0
HighLights = 1 or 0
HazLights = 1 or 0
IndLLights = 1 or 0
IndRLights = 1 or 0
RFogLights = 1 or 0
FFogLights = 1 or 0

If they were all set to 1, then the message I'd want to send is: 00010001000100010001000100010001

How do I make this conversion? There will be other frames I need to send where the variable may be a number rather than a 1 or a 0 so I need something that works fairly universally. The number of variables per frame will always be 8 however (1 per byte).

How would I go about this?

Didn't we cover this basic concept to death in another of your threads? It's a matter of setting bits in a variable, which is a mundane and ages old non-problem.

May I ask (actually anybody would ask) why you can't just place the bits consecutively, like
......000000000000000000011111111

How does this topic differ from Adding Bytes Together into a long long int...? - #13 by MartinL

Because CAN device at the other end assigns a variable to each byte in the frame. So it will read the whole 64 bit frame then split it into 8 bytes before reading the value of each as a decimal variable.

My thought was to use bitshifting, so I have built this:

  PDU_Frame1 = 0;
  PDU_Frame1 <<= 8; PDU_Frame1 |= SideLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= MainLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= HighLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= HazLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= IndLLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= IndRLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= RFogLights;
  PDU_Frame1 <<= 8; PDU_Frame1 |= FFogLights;

It doesn't seem to work as intended though and I'm getting "f8ff022099010000" in the serial monitor..??

That's because... oh wait I'm being scooped again... :slight_smile:

If that is supposed to be hexadecimal, you have too many zeroes:
0x0101010101010101

if that is supposed to be binary, you have too few:
0b0000000100000001000000010000000100000001000000010000000100000001

There is no need to pack them into a 64-bit number. I would just keep them in a byte array:

byte array[8];
array[0] = SideLights;
array[1] = MainLights;
array[2] = HighLights;
array[3] = HazLights;
array[4] = IndLLights;
array[5] = IndRLights;
array[6] = RFogLights;
array[7] = FFogLights;

Oh yes you are right! My mistake, thanks John. The CAN_SEND routine that I am using accepts a 64-bit number as I call it a few different times. In order to not modify this routine it would be helpful to pre-process the data packet into the format you show above. If I were doing this, would bitshifting be the right way to do it as I've attempted to do?

Oh? The CAN library does the frame packing?

Can you share? Notwithstanding that the packet assembly was beaten to death in the other thread...

If you need to present it as a 64-bit int I would use a union to overlay the two.

union
{
   byte array[8];
   uint64_t uint64; 
} u;

u.array[0] = SideLights;
u.array[1] = MainLights;
u.array[2] = HighLights;
u.array[3] = HazLights;
u.array[4] = IndLLights;
u.array[5] = IndRLights;
u.array[6] = RFogLights;
u.array[7] = FFogLights;

Hmmm. I can't recall if you participated in the same discussion in the other thread. In that one, and others, unions have been identified as producing undefined behavior when used this way, and non-portable due to undefined implementation details.

But the whole horse was beaten to a pulp already over there.

I remember that discussion and was admonished for suggesting using for that purpose

It's all a matter of use case. If you want to just make something work today on today's Arduino, why not? I did that a few times. I wouldn't use it for anything that I would publish or push forward into other projects...

I'm pretty sure that bit shifting is optimized by the compiler. Especially, a shift by 8 bits. That would translate into a fairly efficient series of byte moves for the case that is presented here.

Again, horse so dead, the flies are buzzing. Should have left it alone...

Ok sorry for flogging the horse... I've worked on it and I now have it working - slowly getting this bitshifting business :slight_smile:

Please don't start duplicate threads again, thanks...

I have not read through the other discussion, but instead of a union, using memcpy to copy an 8-byte array into a uint64_t should work.

memcpy was discussed there, so it's worth a look. The question is not, does it work, it's can you depend on it to always work. That includes, can you implement it safely in all circumstances, including those you can't anticipate?

The mechanism of a raw memory move, vs. a raw conversion by pointer or union, only differs in method. Neither offers the assurance of data alignment that is offered by bit shifting. That is because it's (for better or worse) the only thing that is guaranteed by the language specification.

I would probably avoid the whole byte to uint64_t conversion, and just set the specific bit within the uint64_t directly for each of the lights.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.