Packing byte fields and an array object into struct

K

krishna2prasad

Hello,

I am trying to build a structure to be passed down to an I2C device driver.The driver expects a struct that has a data array of size 512 bytes among other things. This is my code -

rd_wr = 0x0 # Read operation
i2c_addr = addr
mux = mux_sel
multi_len = count
cmd = 0x0
i2c_inst_type = CHEL_I2C_AUTO_RD_TYPE_5
flag = CHEL_I2C_AUTO_VALID
status = 0x0
data = array.array('B', (0 for x in range(0,512)))

os_inst_bytes = (struct.pack('B', rd_wr) +
struct.pack('B', i2c_addr) +
struct.pack('B', mux) +
struct.pack('B', multi_len) +
struct.pack('B', cmd) +
struct.pack('B', i2c_inst_type) +
struct.pack('B', flag) +
struct.pack('I', status) +
struct.pack('512B', data))

#Convert to byte array
os_inst = bytearray(os_inst_bytes)

ret = fcntl.ioctl(self._dev_fd,
self.__IOWR(FXCB_FPGAIO_I2C_AUTO_OS_INST),
os_inst, 1)

I get an error like this -

591 struct.pack('B', flag) +
592 struct.pack('I', status) +

--> 593 struct.pack('512B', data))

error: pack requires exactly 512 arguments

In [1]:

Even though data is a 512 element array, it is not treat as such in this struct.pack. The data field is used to return data from the driver. I should be able to unpack the struct os_inst and read the data buffer after the IOCTL call. How can I achieve this ?

Thanks in advance!
 
N

Ned Batchelder

Hello,

I am trying to build a structure to be passed down to an I2C device driver. The driver expects a struct that has a data array of size 512 bytes among other things. This is my code -

rd_wr = 0x0 # Read operation
i2c_addr = addr
mux = mux_sel
multi_len = count
cmd = 0x0
i2c_inst_type = CHEL_I2C_AUTO_RD_TYPE_5
flag = CHEL_I2C_AUTO_VALID
status = 0x0
data = array.array('B', (0 for x in range(0,512)))

os_inst_bytes = (struct.pack('B', rd_wr) +
struct.pack('B', i2c_addr) +
struct.pack('B', mux) +
struct.pack('B', multi_len) +
struct.pack('B', cmd) +
struct.pack('B', i2c_inst_type) +
struct.pack('B', flag) +
struct.pack('I', status) +
struct.pack('512B', data))

#Convert to byte array
os_inst = bytearray(os_inst_bytes)

ret = fcntl.ioctl(self._dev_fd,
self.__IOWR(FXCB_FPGAIO_I2C_AUTO_OS_INST),
os_inst, 1)

I get an error like this -

591 struct.pack('B', flag) +
592 struct.pack('I', status) +

--> 593 struct.pack('512B', data))

error: pack requires exactly 512 arguments

In [1]:

Even though data is a 512 element array, it is not treat as such in this struct.pack. The data field is used to return data from the driver. I should be able to unpack the struct os_inst and read the data buffer after the IOCTL call. How can I achieve this ?

Thanks in advance!

To make a 512-byte field in struct, use '512s' with a data value of ''. Itwill zero-pad the result and give you 512 zero bytes. Also, you can use multiple format specifiers in one struct.pack call:

os_inst_bytes = struct.pack('7BI512s', rd_wr, i2c_addr, muc, multi_len, cmd, i2c_inst_type, flag, status, '')

Lastly, I suspect the value returned from struct.pack is byte-string enoughfor the ioctl call, no need to use bytearray.

--Ned.
 
K

krishna2prasad

Thanks for your reply Ned!

I tried this your suggestion and this is what it complains...

os_inst_bytes = struct.pack('7BI512s', 0, 0x51, 0x10, 5, 0, 0xD, 0x80, 0, '')

---------------------------------------------------------------------------
error
Traceback (most recent call last)
<ipython-input-6-d36f45a8d3e6> in <module>()
----> 1 os_inst_bytes = struct.pack('7BI512s', 0, 0x51, 0x10, 5, 0, 0xD, 0x80, 0, "")

error: argument for 's' must be a bytes object

In [7]:


And about the bytearray() call, I want to pass a mutable object to the IOCTL to be able to get the data back from the driver. Without bytearray(), the ioctl with mutable flag set to 1 would complain.

I tried to use the p format specifier with pack after converting the array object to byte stream. Packing seems fine. However, I cant seem to unpack.

In [1]: import array

In [2]: import struct

In [3]: data = array.array('B', (1 for x in range(5)))

In [4]: data_bytes = data.tobytes()

In [5]: os_inst_bytes = struct.pack('7BIp', 0, 0x51, 0x10, 5, 0, 0xD, 0x80, 0, data_bytes)

In [6]:

In [6]: os_inst = bytearray(os_inst_bytes)

In [7]: result = struct.unpack('7B', os_inst[0:7])

In [8]: print(result)
(0, 81, 16, 5, 0, 13, 128)

In [9]: result = struct.unpack('I', os_inst[7:11])

In [10]: print(result)
(0,)

In [11]: result = struct.unpack('5s', os_inst[11:16])
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-11-da14a6693435> in <module>()
----> 1 result = struct.unpack('5s', os_inst[11:16])

error: unpack requires a bytes object of length 5

In [12]:
 
K

krishna2prasad

Correction in the last input line...

In [16]: result = struct.unpack('5p', os_inst[11:16])
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-16-42b59e00d5af> in <module>()
----> 1 result = struct.unpack('5p', os_inst[11:16])

error: unpack requires a bytes object of length 5

In [17]:
 
N

Ned Batchelder

Thanks for your reply Ned!

I tried this your suggestion and this is what it complains...

os_inst_bytes = struct.pack('7BI512s', 0, 0x51, 0x10, 5, 0, 0xD, 0x80, 0, '')

---------------------------------------------------------------------------
error
Traceback (most recent call last)
<ipython-input-6-d36f45a8d3e6> in <module>()
----> 1 os_inst_bytes = struct.pack('7BI512s', 0, 0x51, 0x10, 5, 0, 0xD, 0x80, 0, "")

error: argument for 's' must be a bytes object

OK, looks like you are using Python 3 (it helps to specify these things up-front). Use b"" to get an empty byte-string.

In [7]:


And about the bytearray() call, I want to pass a mutable object to the IOCTL to be able to get the data back from the driver. Without bytearray(), the ioctl with mutable flag set to 1 would complain.

OK, keep the bytearray call if it helps.

--Ned.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top