Steve Trigero
Steve Trigero

Reputation: 11

How to create a bytearray with non-printable ASCII chars

I'm using python v3.10.4. I'm trying build an array comprised of printable and non-printable chars and failing miserably. I've searched through Stackoverflow, I have multiple browser tabs open with python docs, and an O'Reilly Python pocket reference. And I still can't figure out how to do it.

I'm trying to make a function that takes a string argument that contains printable ascii chars. The function is suppose to format that string into a message packet by wrapping it with non-printable chars:

Format: <STX><ADDR><1-20 ASCII Chars><ETX><Checksum>

stx = b'\x02'
etx = b'\x03'
adr = b'A'

def format_msg(m):
    count = len(m) + 4
    msg = bytearray(count)
    msg[0] = stx     # Doesn't work. 
    msg[0] = b'\x02' # Doesn't work. 
    msg[0] = int('00000010', 2)   # No errors, but wrong value is displayed.

    msg[1] = b'A'  # Doesn't work. Assigning a byte to a byte doesn't work?
    msg[1] = 'A'   # Doesn't work
    msg[1] = int(b'A')  # Doesn't work
    msg[1] = ord('A')  # No errors, but wrong value is displayed

    msg[2:2]= bytearray(m,"ascii")

    msg[len(m)+2] = int('00000011', 2) #etx Doesn't work like above.
    # Calculate checksum
    cs = 0
    i = 0
    while i < count-1):
        cs ^= msg[i]
        i+=1
    print(msg)
    msg[count-1] = cs
    return msg

cmd_ba = format_msg("00")
print(list(cmd_ba))

This works, but is impractical, plus I can't figure out how to add a checksum to the end of cmd_ba.

cmd_ba = stx + bytes('A00',"ascii") + etx
print(list(cmd_ba))
cs = cmd_ba[0] ^ cmd_ba[1] ^ cmd_ba[2] ^ cmd_ba[3] ^ cmd_ba[4]
cmd_ba.append(cs)  <-- Error: No 'append' attribute.

Output:

bytearray(b'00\x00\x00\x11\x00')  <-- This is incorrect
[48,48,0,0,17,17]  <-- This is incorrect
[2,65,48,48,3]     <-- This is correct, but it's missing the checksum. The checksum would be 64 (@).

Update:

There are a couple of errors I discovered in my original post. The int object should have number base of 2 not 16. And "msg[:2]" should be "msg[2:2]", I think. I say that because, after the change I get the 2-chars of 'm' into msg at the right location, but the length of msg changes from 6 to 8. With these changes the final print statement output is: [2,65,48,48,3,64,0,0] The trailing two zeros should not be there.

Upvotes: 0

Views: 608

Answers (1)

rikyeah
rikyeah

Reputation: 2013

From this question, looks like you're appending bytes in the wrong way. Following your examples, you can either do:

def format_msg(m):
    count = len(m) + 4
    
    msg = bytearray()
    msg += bytearray(stx)
    msg += bytearray(adr)
    msg += bytearray(m, "ascii")
    msg += bytearray(etx)
    
    cs = 0
    i = 0
    while i < count-1:
        cs ^= msg[i]
        i += 1

    msg += bytearray(cs)
    return msg

or

cmd_ba = stx + bytes('A00',"ascii") + etx
cs = cmd_ba[0] ^ cmd_ba[1] ^ cmd_ba[2] ^ cmd_ba[3] ^ cmd_ba[4]
cmd_ba += bytes(cs)

and the output would be

[2, 65, 48, 48, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

in both cases, as you meant to have.

Upvotes: 1

Related Questions