Search code examples
pythonserializationembeddedpyserialhardware

What's the best way to handle multi byte data fields with variable length that also need to have endianness flipped?


I'm currently working on a program that interfaces with a device by reading and writing to addresses in memory. I believe my serial-to-USB adapter is swapping the endianness of what I'm sending to the device, but I'm not entirely sure that's it. I will be trying another one soon, but I'm still very curious how I would go about solving this problem.

This alone is no problem on short single data field commands. For example:

Source_Address = 0x01
Dest_Address = 0x02
Command_Code = 0x04
Datafield_1 = 0x12345678

In this case I send

Source_Address + Dest_Address + Command_Code + reverse byte order Datafield_1

and get

0x01 0x02 0x04 0x78563412

Great! But what if I have many, many Datafield subsections of varying length that need to maintain their order in the overall Command but have their bytes reversed? For example:

Source_Address = 0x01
Dest_Address = 0x02
Command_Code = 0x05
Datafield_1 = 0x11239041
Datafield_2 = 0x12345876
Datafield_long = 0x1298764536724819
Datafield_longer = 0x783498237859812132125465
...
Datafield_1million = 0x1234567898...

TL;DR The order the variables are initialized are the order they need to be concatenated but every data field needs to be byte reversed. Also data fields are variable length, some are over 1000 bytes long. If they were uniform I could keep slicing chunks and flipping, but with the amount of variance in number of data field subsections and lengths how could this be handled in a dynamic way?


Solution

  • I suspect what you are looking for is the Python struct library.

    I'm assuming that the longer datafields are created by a structure repeating.

    Taking your data, I've created the following example:

    import struct
    import binascii
    
    Source_Address = 0x01
    Dest_Address = 0x02
    Command_Code = 0x05
    Datafields = [0x11239041, 0x12345876]
    data_stream = bytearray()
    data_stream.extend(struct.pack('<BBB', Source_Address, Dest_Address, Command_Code))
    for data in Datafields:
        data_stream.extend(struct.pack('<I', data))
    # data_stream is packed data in little endian format which you could send.
    print(data_stream)
    # bytearray(b'\x01\x02\x05A\x90#\x11vX4\x12')
    
    # Hexlify the output for human readability:
    print(binascii.hexlify(data_stream))
    # b'0102054190231176583412'