8

I am currently using an Arduino that's outputting some integers (int) through Serial (using pySerial) to a Python script that I'm writing for the Arduino to communicate with X-Plane, a flight simulation program.

I managed to separate the original into two bytes so that I could send it over to the script, but I'm having a little trouble reconstructing the original integer.

I tried using basic bitwise operators (<<, >> etc.) as I would have done in a C++like program, but it does not seem to be working.

I suspect it has to do with data types. I may be using integers with bytes in the same operations, but I can't really tell which type each variable holds, since you don't really declare variables in Python, as far as I know (I'm very new to Python).

self.pot=self.myline[2]<<8
self.pot|=self.myline[3]
dsolimano
  • 8,870
  • 3
  • 48
  • 63
Gepapado
  • 333
  • 2
  • 5
  • 11

5 Answers5

9

You can use the struct module to convert between integers and representation as bytes. In your case, to convert from a Python integer to two bytes and back, you'd use:

>>> import struct
>>> struct.pack('>H', 12345)
'09'
>>> struct.unpack('>H', '09')
(12345,)

The first argument to struct.pack and struct.unpack represent how you want you data to be formatted. Here, I ask for it to be in big-ending mode by using the > prefix (you can use < for little-endian, or = for native) and then I say there is a single unsigned short (16-bits integer) represented by the H.

Other possibilities are b for a signed byte, B for an unsigned byte, h for a signed short (16-bits), i for a signed 32-bits integer, I for an unsigned 32-bits integer. You can get the complete list by looking at the documentation of the struct module.

Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
3

What you have seems basically like it should work, assuming the data stored in myline has the high byte first:

myline = [0, 1, 2, 3]
pot = myline[2]<<8 | myline[3]

print 'pot: {:d}, 0x{:04x}'.format(pot, pot)  # outputs "pot: 515, 0x0203"

Otherwise, if it's low-byte first you'd need to do the opposite way:

myline = [0, 1, 2, 3]
pot = myline[3]<<8 | myline[2]

print 'pot: {:d}, 0x{:04x}'.format(pot, pot)  # outputs "pot: 770, 0x0302"
martineau
  • 119,623
  • 25
  • 170
  • 301
  • It's high-byte-first. Still, it's trange that it doesn't work. I'm using a function that outputs numbers to the X-Plane terminal that expects an int, float or double (any will do). However, when I pass self.pot as an argument (I hope that's the correct term), it doesn't show anything, whereas it outputs any other number. – Gepapado Feb 15 '13 at 22:33
  • What format do you send the data to the terminal in, ASCII? If so, how are you converting the value (an integer) in `pot` to that format before sending it? – martineau Feb 15 '13 at 22:53
3

For example, using Big Endian encoding:

int.from_bytes(my_bytes, byteorder='big')
Turtles Are Cute
  • 3,200
  • 6
  • 30
  • 38
0

This totally works:

long = 500
first = long & 0xff  #244
second = long >> 8  #1
result = (second << 8) + first #500

If you are not sure of types in 'myline' please check Stack Overflow question How to determine the variable type in Python?.

Community
  • 1
  • 1
fsw
  • 3,595
  • 3
  • 20
  • 34
-1

To convert a byte or char to the number it represents, use ord(). Here's a simple round trip from an int to bytes and back:

>>> number = 3**9
>>> hibyte = chr(number / 256)
>>> lobyte = chr(number % 256)
>>> hibyte, lobyte
('L', '\xe3')
>>> print number == (ord(hibyte) << 8) + ord(lobyte)
True

If your myline variable is string or bytestring, you can use the formula in the last line above. If it somehow is a list of integers, then of course you don't need ord.

alexis
  • 48,685
  • 16
  • 101
  • 161