Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Packing byte fields and an array object into struct

33 views
Skip to first unread message

krishna...@gmail.com

unread,
Nov 13, 2013, 6:31:49 PM11/13/13
to
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!

Ned Batchelder

unread,
Nov 13, 2013, 6:44:38 PM11/13/13
to
To make a 512-byte field in struct, use '512s' with a data value of ''. It will 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 enough for the ioctl call, no need to use bytearray.

--Ned.

krishna...@gmail.com

unread,
Nov 13, 2013, 8:41:03 PM11/13/13
to
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]:


krishna...@gmail.com

unread,
Nov 13, 2013, 8:43:52 PM11/13/13
to

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]:

Ned Batchelder

unread,
Nov 13, 2013, 8:47:25 PM11/13/13
to
On Wednesday, November 13, 2013 3:41:03 PM UTC-5, krishna...@gmail.com wrote:
> 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.
0 new messages