Packing byte fields and an array object into struct

Discussion in 'Python' started by krishna2prasad@gmail.com, Nov 13, 2013.

  1. Guest

    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!
    , Nov 13, 2013
    #1
    1. Advertising

  2. On Wednesday, November 13, 2013 1:31:49 PM UTC-5, wrote:
    > 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.
    Ned Batchelder, Nov 13, 2013
    #2
    1. Advertising

  3. Guest

    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]:
    , Nov 13, 2013
    #3
  4. Guest

    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]:
    , Nov 13, 2013
    #4
  5. On Wednesday, November 13, 2013 3:41:03 PM UTC-5, 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.
    Ned Batchelder, Nov 13, 2013
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kirby
    Replies:
    3
    Views:
    637
    Kirby
    Oct 8, 2004
  2. DaBeef
    Replies:
    1
    Views:
    614
    Matt Humphrey
    Jul 21, 2006
  3. Jonathan Fine
    Replies:
    9
    Views:
    358
    Jonathan Fine
    Jun 23, 2007
  4. Shashank R Khanvilkar

    Packing/Unpacking bit fields from a byte.

    Shashank R Khanvilkar, Sep 25, 2005, in forum: Perl Misc
    Replies:
    6
    Views:
    405
    Anno Siegel
    Sep 26, 2005
  5. Replies:
    13
    Views:
    351
    glen herrmannsfeldt
    May 5, 2013
Loading...

Share This Page