California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Conversion

Sat Nov 09, 2019 6:34 am

Hello, I am facing with mooving some code from python 2 to python 3. Code below works just ok in python 2 but not in python 3.
So your help would be very appreciated.

Code: Select all

import struct

def convert_long_to_bytes(i):
    i = i % 4294967296
    n4 = i % 256
    i = i / 256
    n3 = i % 256
    i = i / 256
    n2 = i % 256
    n1 = i / 256
    return (n1, n2, n3, n4)

def convert_float_to_MICROCHIP_32bit(x):
    print ("x", x)
    x_IEEE = struct.pack(">f", x).encode("hex")
    print ("x_IEEE", x_IEEE)
    bits = bin(int(x_IEEE, 16))[2:].zfill(len(x_IEEE) * 4)
    i = 0
    val = list("                                ")
    b_s = bytearray(val)
    for char in bits:
        current_bit = int(char)
        if current_bit == 1:
            if (i > 0) and (i < 9):
                b_s[i - 1] = "1"
            elif i == 0:
                b_s[8] = "1"
            else:
                b_s[i] = "1"
        else:
            if (i > 0) and (i < 9):
                b_s[i - 1] = "0"
            elif i == 0:
                b_s[8] = "0"
            else:
                b_s[i] = "0"
        i = i + 1
    bin_val = str(b_s)
    print ("bin_val", bin_val)
    hex_val = int(bin_val, 2)
    print ("hex_val", hex_val)
    bytes_val = convert_long_to_bytes(hex_val)
    print ("bytes_val", bytes_val)
    return bytes_val

a = 987654321.123456789  #-987654321.123456789  #0.0  #-5.1  #5.1
b = convert_float_to_MICROCHIP_32bit(a)
print b
Thanks in advance,

Regards, Vlado

jahboater
Posts: 4766
Joined: Wed Feb 04, 2015 6:38 pm

Re: Conversion

Sat Nov 09, 2019 7:31 am

You may need // instead of / for integer division.

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sat Nov 09, 2019 8:18 am

the first error is:

Code: Select all

Traceback (most recent call last):
  File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py27.py", line 47, in <module>
    b = convert_float_to_MICROCHIP_32bit(a)
  File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py27.py", line 15, in convert_float_to_MICROCHIP_32bit
    x_IEEE = struct.pack(">f", x).encode("hex")
AttributeError: 'bytes' object has no attribute 'encode'

billio
Posts: 70
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Conversion

Sat Nov 09, 2019 10:33 am

I think you need

Code: Select all

struct.pack(">f", x).hex()
as described here https://docs.python.org/3/library/stdtypes.html
The type 'bytes' does not have an encode() function in python3.

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sat Nov 09, 2019 12:24 pm

Thanks for your answer, it alows me to go forward through the code execution - almost to the end.
Code looks now:

Code: Select all

import struct

def convert_long_to_bytes(i):
    i = i % 4294967296
    n4 = i % 256
    i = i / 256
    n3 = i % 256
    i = i / 256
    n2 = i % 256
    n1 = i / 256
    return (n1, n2, n3, n4)

def convert_float_to_MICROCHIP_32bit(x):
    x_IEEE = struct.pack(">f", x).hex()
    bits = bin(int(x_IEEE, 16))[2:].zfill(len(x_IEEE) * 4)
    i = 0
    val = "                                ".encode()
    b_s = list(val)
    for char in bits:
        current_bit = int(char)
        if current_bit == 1:
            if (i > 0) and (i < 9):
                b_s[i - 1] = "1"
            elif i == 0:
                b_s[8] = "1"
            else:
                b_s[i] = "1"
        else:
            if (i > 0) and (i < 9):
                b_s[i - 1] = "0"
            elif i == 0:
                b_s[8] = "0"
            else:
                b_s[i] = "0"
        i = i + 1
    bin_val = [int(i) for i in b_s]
    out = 0
    for bit in bin_val:
        out = (out << 1) | bit
    hex_val = hex(out)    
    bytes_val = convert_long_to_bytes(hex_val)
    return bytes_val

a = 5.1 #987654321.123456789  #-987654321.123456789  #0.0  #-5.1  
b = convert_float_to_MICROCHIP_32bit(a)
print (b)
and the last error message:

Code: Select all

Traceback (most recent call last):
  File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py34.py", line 45, in <module>
    b = convert_float_to_MICROCHIP_32bit(a)
  File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py34.py", line 41, in convert_float_to_MICROCHIP_32bit
    bytes_val = convert_long_to_bytes(hex_val)
  File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py34.py", line 4, in convert_long_to_bytes
    i = i % 4294967296
TypeError: not all arguments converted during string formatting

User avatar
B.Goode
Posts: 8862
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Conversion

Sat Nov 09, 2019 1:54 pm

I can't solve it, but can refer you to the likely cause:

In addition to performing the modulo operation on numbers, the % operator is also overloaded by string and unicode objects to perform string formatting (also known as interpolation). The syntax for string formatting is described in the Python Library Reference, section String Formatting Operations.
Ref: https://docs.python.org/2/reference/expressions.html

(Similar text for the Python3 version of the documentation.)

So it looks as though the argument being passed into your convert_long_to_bytes() function is being treated as a string, or a unicode object, by Python3?

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sat Nov 09, 2019 4:10 pm

Well, it's strange for me. Code below works ok, but together with the rest of the code lines error is shown.
BTW, result is correct.

Code: Select all

def convert_long_to_bytes(i):
    i = i % 4294967296
    n4 = i % 256
    i = i / 256
    n3 = i % 256
    i = i / 256
    n2 = i % 256
    n1 = i / 256

    n1 = int(round(n1))
    n2 = int(round(n2))
    n3 = int(round(n3))
    n4 = int(round(n4))
    return (n1, n2, n3, n4)


a = 0x81233333   # 5.1
b = convert_long_to_bytes(a)

print (b)        # result: (129L, 35L, 51L, 51L)

jahboater
Posts: 4766
Joined: Wed Feb 04, 2015 6:38 pm

Re: Conversion

Sat Nov 09, 2019 5:26 pm

You should use python3 integer division.

Code: Select all

def convert_long_to_bytes(i):
    i %= 4294967296
    n4 = i % 256
    i //= 256
    n3 = i % 256
    i //= 256
    return (i // 256, i % 256, n3, n4)
I'm pretty sure its vastly more efficient, and simpler, than converting it all to floating-point, then rounding it, and finally truncating it back to an integer! Also I think the "round" call was unnecessary and probably wrong.

User avatar
rpiMike
Posts: 957
Joined: Fri Aug 10, 2012 12:38 pm
Location: Cumbria, UK

Re: Conversion

Sat Nov 09, 2019 6:19 pm

What about using the bitstring library?

Code: Select all

pip3 install bitstring

Code: Select all

import bitstring
f1 = bitstring.BitArray(float=5.1, length=32)
print(f1.bin)
01000000101000110011001100110011

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sat Nov 09, 2019 6:43 pm

@jahboater:
your lines of the code works ok, but not with the rest of the code lines.
The very same error as before:

Code: Select all

...
i %= 4294967296
TypeError: not all arguments converted during string formatting
@rpiMike:
described part of the code works ok, but yes, your solution looks much better than my... I'll try to use it

User avatar
B.Goode
Posts: 8862
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Conversion

Sat Nov 09, 2019 6:54 pm

California wrote:
Sat Nov 09, 2019 6:43 pm
@jahboater:
your lines of the code works ok, but not with the rest of the code lines.
The very same error as before:

Code: Select all

...
i %= 4294967296
TypeError: not all arguments converted during string formatting
@rpiMike:
described part of the code works ok, but yes, your solution looks much better than my... I'll try to use it
Not really the same error, because the two lines of source code are different.

What does Python think is the type of the argument 'i' when you use it in your production code?

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sat Nov 09, 2019 7:47 pm

In python 2 result is: (129L, 35L, 51L, 51L)
In python 3 result is: (129, 35, 51, 51)

As you can see, diference is in the letter L. Maybe this is what error message say.
So, how to get the letter L into result?

billio
Posts: 70
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Conversion

Sun Nov 10, 2019 12:13 am

Python 2 has normal length integers and long integers, the latter being represented with a trailing L.

Code: Select all

>>> type(666L)
<type 'long'>
>>> type(666)
<type 'int'>
I believe that is where the L comes from. But can I ask what the purpose of the function "def convert_long_to_bytes" is. If it is to convert python2 long integers to bytes then this doesn't seem necessary as python3 doesn't have long integers, just integers. Python3 has a function to convert integers to bytes ( https://docs.python.org/3/library/stdty ... ger-types ):

Code: Select all

>>> a = 666
>>> a.to_bytes(4,"big")
b'\x00\x00\x02\x9a'
However, your example is confusing me as it uses a floating point number ' # 5.1 ' .

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sun Nov 10, 2019 7:13 am

First of all, I want to thank all of you for your help here.
The purpose of this part of the code is converting temperature setpoint (float) into bytes on the Rpi3 which represents master in RS485 network.
Floating point number 5.1 is just an example, could be used any other positive or negative number.
This form of setpoint is thantransmitted over network to the slave (Microchip's PIC18F458), where is written into EEPROM ...

So, is there any other way to convert in python3 (for example) 0x81233333 into form (129, 35, 51, 51)

billio
Posts: 70
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Conversion

Sun Nov 10, 2019 9:21 am

There may be a better way than this but :

Code: Select all

>>> a = 0x81233333
>>> b = a.to_bytes(4,"big",signed=False)
>>> c = [int(i) for i in b]
>>> c
[129, 35, 51, 51]

User avatar
rpiMike
Posts: 957
Joined: Fri Aug 10, 2012 12:38 pm
Location: Cumbria, UK

Re: Conversion

Sun Nov 10, 2019 10:28 am

Combining both gives the following, however I get different values for 5.1 - is your example correct?

Code: Select all

import bitstring
f=5.1
print(f)
ba = bitstring.BitArray(float=f, length=32)
print(ba.hex)
ih = int(ba.hex,16)
b = ih.to_bytes(4,"big",signed=False)
c = [int(i) for i in b]
print(c)
5.1
40a33333
[64, 163, 51, 51]

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sun Nov 10, 2019 12:07 pm

@billio:
so far so god, it looks ok - I have to do more tests

@rpiMike:
your result is also ok, but it is coded in normal float 32 (IEEE) standard, for me it is used Microchip float 32 standard

California
Posts: 169
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Sun Nov 10, 2019 12:56 pm

Thanks to all of you, code works as expected.

With best regards,

Vlado

Return to “Python”