python 2.7 - converting float to bytes and looping through the bytes - python

I'm trying to send a float as a series of 4 bytes over serial.
I have code that looks like this which works:
ser.write(b'\xcd') #sending the byte representation of 0.1
ser.write(b'\xcc')
ser.write(b'\xcc')
ser.write(b'\x3d')
but I want to be able to send an arbitary float.
I also want to be able to go through each byte individually so this won't do for example:
bytes = struct.pack('f',float(0.1))
ser.write(bytes)
because I want to check each byte.
I'm using python 2.7
How can I do this?

You can use the struct module to pack the float as binary data. Then loop through each byte of the bytearray and write them to your output.
import struct
value = 13.37 # arbitrary float
bin = struct.pack('f', value)
for b in bin:
ser.write(b)

Related

How do I hash integers and strings inputs using murmurhash3

I'm looking to get a hash value for string and integer inputs.
Using murmurhash3, I'm able to do it for strings but not integers:
pip install murmurhash3
import mmh3
mmh3.hash(34)
Returns the following error:
TypeError: a bytes-like object is required, not 'int'
I could convert it to bytes like this:
mmh3.hash(bytes(34))
But then I'll get an error message if the input is string
How do I overcome this without converting the integer to string?
How do I overcome this without converting the integer to string?
You can't. Or more precisely, you need to convert it to bytes or str in some way, but it needn't be a human-readable text form like b'34'/'34'. A common approach on Python 3 would be:
my_int = 34 # Or some other value
my_int_as_bytes = my_int.to_bytes((my_int.bit_length() + 7) // 8, 'little')
which makes a minimalist raw bytes representation of the original int (regardless of length); for 34, you'd get b'"' (because it only takes one byte to store it, so you're basically getting a bytes object with its ordinal value), but for larger ints it still works (unlike mucking about with chr), and it's always as small as possible (getting 8 bits of data per byte, rather than a titch over 3 bits per byte as you'd get converting to a text string).
If you're on Python 2 (WHY?!? It's been end-of-life for nearly a year), int.to_bytes doesn't exist, but you can fake it with moderate efficiency in various ways, e.g. (only handling non-negative values, unlike to_bytes which handles signed values with a simple flag):
from binascii import unhexlify
my_int_as_bytes = unhexlify('%x' % (my_int,))

casting byte array to signed short in python

I want to convert a bytearray type or a list of binary strings in python to a signed short list. In fact, I am getting a byte stream from Ethernet and I want to convert them in signed short; however, the only way I found in Python is using struct.unpack which seems to be slow since it requires a format string to determine the type of each byte.
This format requirement slows in two steps:
1) Required to make a long string for a long array of bytes
2) Required to search one-by-one in the array.
In C++, the following simple code does the job on the entire memory block contained by InBuf:
OutBuf = short int[len]
InBuf = char[len*2]
memcpy(&OutBuf, &InBuf, len*2)
This skips doing the format search within the byte array as well as the format string construction. Does anyone know a better way to do so in Python?
If you're using Python > 3.2 you could use int.from_bytes:
int.from_bytes(b, byteorder='little', signed=True)

Python struct.unpack errors with TypeError: a bytes-like object is required, not 'str'

Can someone please help with the following line of code and Error? I am unfamiliar with python value conversions.
The specific line that generates the error is:
value = struct.unpack("<h",chr(b)+chr(a))[0]
TypeError: a bytes-like object is required, not 'str'
The code fragment is:
if packet_code ==0x80: # raw value
row_length = yield
a = yield
b = yield
value = struct.unpack("<h",chr(b)+chr(a))[0]
The input data is:
b'\x04\x80\x02\x00\xb2\xcb\xaa\xaa\x04\x80\x02\x00p\r\xaa\xaa\x04\x80\x02\x00]
\xaa\xaa\x04\x80\x02\x00#=\xaa\xaa\x04\x80\x02\x007F\xaa\xaa\x04\x80\x02\x00\!\xaa\xaa\x04\x80\x02\x00=#\xaa\xaa\x04\x80\x02\x00=#\xaa\xaa\x04\x80\x02\x00i\x14\xaa\xaa\x04\x80\x02\x00]
\xaa\xaa\x04\x80\x02\x00p\r\xaa\xaa\x04\x80\x02\x00\x80\xfd\xaa\xaa
I am using python 3.5. This code seems to work in the older versions.
Here is the link to similar parser code where it may have worked with previous versions of Python:
Parser Code Link
Here is the link to the description of how the data is sent from the device
RAW Wave Value (16-bit)
This Data Value consists of two bytes, and represents a single raw wave sample. Its value is a signed 16-bit integer that ranges from -32768 to 32767. The first byte of the Value represents the high-order bits of the twos-compliment value, while the second byte represents the low-order bits. To reconstruct the full raw wave value, simply shift the first byte left by 8 bits, and bitwise-or with the second byte:
short raw = (Value[0]<<8) | Value[2];
where Value[0] is the high-order byte, and Value1 is the low-order byte.
In systems or languages where bit operations are inconvenient, the following arithmetic operations may be substituted instead:
raw = Value[0]*256 + Value[1];
if( raw >= 32768 ) raw = raw - 65536;
Really appreciate any help as I am currently stuck.
When you are using Python 2.x str is a byte array. For Python 3, you must use bytes like this:
struct.unpack("<h", bytes([b, a]))[0]
if you use python3 you can use the following lines for the received data and convert it to a short data type.
struct.unpack('<h', data)
struct.unpack('<h', data[0:4])
struct.unpack('<h', b''.join(…))
If it receives the data as a list, it uses converts the array to bytes:
struct.unpack('<h', bytes(data))
Remember you must convert your information to bytes and not send as str, in order to use unpack and decompress the information in the data type you require.

Writing hex value into file Python

What I am really doing is creating a BMP file from JPEG using python and it's got some header data which contains info like size, height or width of the image, so basically I want to read a JPEG file, gets it width and height, calculate the new size of a BMP file and store it in the header.
Let's say the new size of the BMP file is 40000 bytes whose hex value is 0x9c40, now as there is 4 byte space to save this in the header, we can write it as 0x00009c40. In BMP header data, LSB is written first and then MSB so I have to write, 0x409c0000 in the file.
My Problems:-
I was able to do this in C but I am totally lost how to do so in Python.
For example, if I have i=40000, and by using str=hex(i)[2:] I got the hex value, now by some coding I was able to add the extra zeros and then reverse the code. Now how to write this '409c0000' data in the file as hex?
The header size is 54 bytes for BMP file, so is there is another way to just store the data in a string like str='00ffcf4f...'(upto 54 bytes) and just convert the whole str at once as hex and write it to file?
My friend told me to use unhexlify from binascii,
by doing unhexlify('fffcff') I get '\xff\xfc\xff' which is what I want but when I try unhexlify('3000') I get '0\x00'` which is not what I want. It is same for any value containing 3, 4, 5, 6 or 7. Is it the right way to do this?
You are not writing hex, you are writing binary data. Hexadecimal is a helpful notation when dealing with binary data, but don't confuse the notation with the value.
Use the struct module to pack integer data into binary structures, the same way C would.
binascii.unhexlify also is a good choice, provided you already have the data in a string using hex notation. The output is correct, but the binary representation only uses hex escapes for bytes outside the printable ASCII range.
Thus fffcff does correctly becomes \xff\xfc\xff, representing 3 bytes in hex escape notation, and 3000 is \x30\x00, but \x30 is the '0' character in ASCII, so the Python representation for that byte simply uses that ASCII character, as that is the most common way to interpret bytes.
Packing the integer value 40000 using struct.pack() as an unsigned integer (little endian) then becomes:
>>> import struct
>>> struct.pack('<I', 40000)
'#\x9c\x00\x00'
where the 40 byte is represented by the ASCII character for that byte, the # glyph.
If this is confusing, you can always create a new hex representation by going the other way and use 0binascii.hexlify() function](https://docs.python.org/2/library/binascii.html#binascii.hexlify) to create a hexadecimal representation for yourself, just to debug the output:
>>> import binascii
>>> binascii.hexlify(struct.pack('<I', 40000))
'409c0000'
and you'll see that the # byte is still the right hex value.

Binary data with pyserial(python serial port)

serial.write() method in pyserial seems to only send string data. I have arrays like [0xc0,0x04,0x00] and want to be able to send/receive them via the serial port? Are there any separate methods for raw I/O?
I think I might need to change the arrays to ['\xc0','\x04','\x00'], still, null character might pose a problem.
An alternative method, without using the array module:
def a2s(arr):
""" Array of integer byte values --> binary string
"""
return ''.join(chr(b) for b in arr)
You need to convert your data to a string
"\xc0\x04\x00"
Null characters are not a problem in Python -- strings are not null-terminated the zero byte behaves just like another byte "\x00".
One way to do this:
>>> import array
>>> array.array('B', [0xc0, 0x04, 0x00]).tostring()
'\xc0\x04\x00'
I faced a similar (but arguably worse) issue, having to send control bits through a UART from a python script to test an embedded device. My data definition was "field1: 8 bits , field2: 3 bits, field3 7 bits", etc. It turns out you can build a robust and clean interface for this using the BitArray library. Here's a snippet (minus the serial set-up)
from bitstring import BitArray
cmdbuf = BitArray(length = 50) # 50 byte BitArray
cmdbuf.overwrite('0xAA', 0) # Init the marker byte at the head
Here's where it gets flexible. The command below replaces the 4 bits at
bit position 23 with the 4 bits passed. Note that it took a binary
bit value, given in string form. I can set/clear any bits at any location
in the buffer this way, without having to worry about stepping on
values in adjacent bytes or bits.
cmdbuf.overwrite('0b0110', 23)
# To send on the (previously opened) serial port
ser.write( cmdbuf )

Categories