0

I am writing code which create messages to be sent over a CANBUS using a particular protocol. An example format for a data field of such a message is:

[from_address (1 byte)][control_byte (1 byte)][identifier (3 bytes)][length (3 bytes)]

The data field needs to be formatted as a list or bytearray. My code currently does the following:

 data = dataFormat((from_address << 56)|(control_byte << 48)|(identifier << 24)|(length))

where dataFormat is defined as follows:

 def dataFormat(num):
     intermediary = BitArray(bin(num))
     return bytearray(intermediary.bytes)

This does exactly what I want it to, except for when from_address is a number that can be described in less than 8 bits. In these cases bin() returns a binary of character length not divisible by 8 (extraneous zeroes are discarded), and so intermediary.bytes complains that the conversion is ambiguous:

 InterpretError: Cannot interpret as bytes unambiguously - not multiple of 8 bits.

I am not tied to anything in the above code - any method to take a sequence of integers and convert it to a bytearray (with correct sizing in terms of bytes) would be greatly appreciated.

oirectine
  • 139
  • 8
  • What does this need the tag [tag:can] for? – Jongware Jan 30 '17 at 22:24
  • @RadLexus it's part of a can message. not particularly relevant to the problem at hand, i suppose. – oirectine Jan 30 '17 at 22:29
  • Why not use the message structure of your CAN controller's registers? Identifier and length are dedicated fields of the CAN frame, whereas those other things have to be stored in the data field. – Lundin Feb 07 '17 at 10:48

1 Answers1

2

If it's a bytearray that you'd like, then the simple option would be to jump straight there and build it up directly. Something like this:

# Define some values:
from_address = 14
control_byte = 10
identifier = 80
length = 109

# Create a bytearray with 8 spaces:
message = bytearray(8)

# Add from and control:
message[0] = from_address
message[1] = control_byte

# Little endian dropping in of the identifier:
message[2] = identifier & 255
message[3] = (identifier >> 8) & 255
message[4] = (identifier >> 16) & 255

# Little endian dropping in of the length:
message[5] = length & 255
message[6] = (length >> 8) & 255
message[7] = (length >> 16) & 255

# Display bytes:
for value in message:
    print(value)

Here's a working example of that.

Health warning

The above assumes that the message is expected to be little endian. There may also be built in ways of doing this in Python, but it's not a language I use often.

Luke Briggs
  • 3,745
  • 1
  • 14
  • 26