Logo Questions Linux Laravel Mysql Ubuntu Git Menu

Python 3 - on converting from ints to 'bytes' and then concatenating them (for serial transmission)

After much fruitless searching... I am having a very specific issue understanding the way 'bytes' and hexadecimal content is handled in Python 3.2. I KNOW I'm misunderstanding, but can't seem to find the correct path.

My ultimate goal is to use the python serial module to transmit a sequence of bytes. Some bytes are static and won't change. Others are supposed to vary from 0-255 in value. These all need to be smushed together and transmitted at once. (These are instructions to a programmable display. The code contains fixed instructions to set BG colour, followed by a byte each for R, G and B values. I am trying to cycle through colour intensities in a loop to test, but later I'll want to be able to do this for practical functions on the display).

A complete static transmission, tested working successfully, might be as follows:

ser.write(b'\xAA\x11\x05\x00\x00\x00\xc3')  #this works great

Similarly, I can smush them together, i.e:

ser.write(b'\xAA\x11\x05' + b'\x00\x00\x00\xc3')  #also works great

Now if I want to take one of those three zero-value bytes, and replace it with a variable, it all goes pear-shaped. After much experimentation I ended up with something which allegedly converted the integer variable of a For loop into a type compatible with concatenation to the above series of bytes:

SET_BG_COLOR = b'\xAA\x03\x03'
for r in range(0,255):
            red = hex(r).encode('utf-8')
            blue = hex(255-r).encode('utf-8')
            ser.write(SET_BG_COLOR + blue + b'\x00' + red + b'\xC3') #BGR format

The hex(integer).encode('utf-8') was the only method so far which didn't just throw an error about being unable to concatenate to the other stuff I'm trying to shove down the serial connection. But it doesn't work, and when looking at the results:

>>> x = b'\05'
>>> x
>>> y = hex(5).encode('utf-8')
>>> y
>>> type(x)
<class 'bytes'>
>>> type(y)
<class 'bytes'>
>>> x + y
b'\x050x5'   #(this is what I get)
>>> z = b'\05'
>>> x + z
b'\x05\x05'  #(this is what I want)

Looks like, although it lets me concatenate... it's a binary representation of string data, or somesuch? So will let me concatenate but it's not true hex values? Have I missed a blindingly obvious way to go from x=255 to x= b'\FF'? Or is my whole approach just the wrong way to do this? -_- thanks for your time.

like image 883
r00x Avatar asked Mar 23 '23 12:03


1 Answers

You are confusing Python byte literal syntax here; you do not need to generate the literal syntax, just the byte value; the bytes() type accepts a sequence of integers too:

>>> bytes([255])

Applied to your code:

SET_BG_COLOR = b'\xAA\x03\x03'
for r in range(0,255):
    red = bytes([r])
    blue = bytes([255 - r])
    ser.write(SET_BG_COLOR + blue + b'\x00' + red + b'\xC3') #BGR format

or, simpler still:

SET_BG_COLOR = [0xAA, 0x03, 0x03]
for r in range(0,255):
    ser.write(bytes(SET_BG_COLOR + [r, 0x00, 255 - r, 0xC3])) #BGR format

using literal hex integer notation.

Demo for r = 10:

>>> SET_BG_COLOR = [0xAA, 0x03, 0x03]
>>> r = 10
>>> bytes(SET_BG_COLOR + [r, 0x00, 255 - r, 0xC3])

The hex() function outputs 4 characters per byte; starting with a literal 0x followed by the hex representation of the integer number. Encoded to UTF8 that's still 4 bytes, b'\x30\x78\x30\x31' for the integer value 10, for example, versus b'\x10' for the actual byte you wanted.

like image 153
Martijn Pieters Avatar answered Apr 06 '23 18:04

Martijn Pieters