Re: Sending USB commands with Python

Discussion in 'Python' started by Dennis Lee Bieber, Aug 29, 2012.

  1. On Thu, 30 Aug 2012 08:29:32 +1000, Cameron Simpson <>
    declaimed the following in gmane.comp.python.general:

    > On 29Aug2012 17:57, Dennis Lee Bieber <> wrote:
    > | On Wed, 29 Aug 2012 14:21:30 -0700 (PDT), "Adam W."
    > | <> declaimed the following in
    > | gmane.comp.python.general:
    > | > You are correct about the 2 being the number of bytes written. However when I issue a read command I get:
    > | >
    > | > >>> ep.write('\x1BA')
    > | > 4
    > |
    > | That's interesting -- as if each byte you send is expanding into a
    > | pair of bytes.
    >
    > UTF-16? ISTR that Windows often uses big endian UTF-16 for filenames and
    > text data; could there be some default encoding in ep.write getting in
    > your way?
    >
    > Disclaimer: I'm really not a Windows guy.


    I know W9x has both "normal" and "wide" entry points in the system,
    and I think WinXP and later default to the "wide" points, but I'd expect
    any third party DLL would document what it expects to receive for a
    device write operation.

    BUT you do give a possible clue. Is the OP using a 3.x Python where
    strings are Unicode -- in which case the above may need to be explicitly
    declared as a "byte string" rather than text (unicode) string.

    I've only recently upgraded my desktop to Python 2.7 (and had to
    make sure that copying the old "CherryTemplate" from 2.5 was still
    functional -- I don't have time to rework a program that builds a set of
    static web pages from database information), so can't really check on
    sizes.
    --
    Wulfraed Dennis Lee Bieber AF6VN
    HTTP://wlfraed.home.netcom.com/
     
    Dennis Lee Bieber, Aug 29, 2012
    #1
    1. Advertising

  2. Dennis Lee Bieber

    Adam W. Guest

    On Wednesday, August 29, 2012 6:56:16 PM UTC-4, Dennis Lee Bieber wrote:
    >
    > BUT you do give a possible clue. Is the OP using a 3.x Python where
    >
    > strings are Unicode -- in which case the above may need to be explicitly
    >
    > declared as a "byte string" rather than text (unicode) string.
    >


    Huzzah! I am indeed using 3.x, and slapping on an .encode('utf-8') made my printer try to spit paper at me! Progress.

    Also, astute observation about the endpoint needing to be an input, with the following modification I get:

    >>> ep.write('\x1BA'.encode('utf-8'))

    2
    >>> ep = usb.util.find_descriptor(

    intf,
    custom_match = \
    lambda e: \
    usb.util.endpoint_direction(e.bEndpointAddress) == \
    usb.util.ENDPOINT_IN
    )
    >>> ep.read(1)

    array('B', [163])
    >>>


    Anyone want to venture a guess on how I should interpret that? It seems the [163] is the byte data the manual is talking about, but why is there a 'B' there? If I put paper in it and try again I get: array('B', [3])

    Thanks for all your help guys, just about ready to stared coding the fun part!
     
    Adam W., Aug 30, 2012
    #2
    1. Advertising

  3. Dennis Lee Bieber

    MRAB Guest

    On 30/08/2012 00:45, Adam W. wrote:
    > On Wednesday, August 29, 2012 6:56:16 PM UTC-4, Dennis Lee Bieber wrote:
    >>
    >> BUT you do give a possible clue. Is the OP using a 3.x Python where
    >>
    >> strings are Unicode -- in which case the above may need to be explicitly
    >>
    >> declared as a "byte string" rather than text (unicode) string.
    >>

    >
    > Huzzah! I am indeed using 3.x, and slapping on an .encode('utf-8') made my printer try to spit paper at me! Progress.
    >
    > Also, astute observation about the endpoint needing to be an input, with the following modification I get:
    >
    >>>> ep.write('\x1BA'.encode('utf-8'))

    > 2
    >>>> ep = usb.util.find_descriptor(

    > intf,
    > custom_match = \
    > lambda e: \
    > usb.util.endpoint_direction(e.bEndpointAddress) == \
    > usb.util.ENDPOINT_IN
    > )
    >>>> ep.read(1)

    > array('B', [163])
    >>>>

    >
    > Anyone want to venture a guess on how I should interpret that? It seems the [163] is the byte data the manual is talking about, but why is there a 'B' there? If I put paper in it and try again I get: array('B', [3])
    >
    > Thanks for all your help guys, just about ready to stared coding the fun part!
    >

    The result is an array of bytes ('B'). I think the value means:

    0b10100011
    ^Ready
    ^Top of form
    ^No paper
    ^Printer error

    The error is that it's out of paper.
     
    MRAB, Aug 30, 2012
    #3
  4. On Wed, 29 Aug 2012 16:45:10 -0700 (PDT), "Adam W."
    <> declaimed the following in
    gmane.comp.python.general:

    >
    > Huzzah! I am indeed using 3.x, and slapping on an .encode('utf-8') made my printer try to spit paper at me! Progress.
    >
    > Also, astute observation about the endpoint needing to be an input, with the following modification I get:
    >
    > >>> ep.write('\x1BA'.encode('utf-8'))

    > 2


    I'm a tad curious if using the notation

    b'\x1bA'

    without the .encode() would work.

    My concern is that you may encounter some "string" of data for
    printing which the .encode() ends up /changing/ (don't UTF-8 strings use
    a high-bit to signal a multi-byte encoding of what had been a single
    character?). A pure byte string shouldn't have that problem.

    > >>> ep = usb.util.find_descriptor(

    > intf,
    > custom_match = \
    > lambda e: \
    > usb.util.endpoint_direction(e.bEndpointAddress) == \
    > usb.util.ENDPOINT_IN
    > )


    Seems tedious to keep swapping -- does USB support bidirectional
    connections?

    > >>> ep.read(1)

    > array('B', [163])
    > >>>

    >
    > Anyone want to venture a guess on how I should interpret that? It seems the [163] is the byte data the manual is talking about, but why is there a 'B' there? If I put paper in it and try again I get: array('B', [3])


    Per documentation (section 8.6 in Python 2.7.2 library) of "array"
    module:

    'b' signed char int 1
    'B' unsigned char int 1


    >>> import array
    >>> array.array("B", "\x1bB")

    array('B', [27, 66])
    >>>

    --
    Wulfraed Dennis Lee Bieber AF6VN
    HTTP://wlfraed.home.netcom.com/
     
    Dennis Lee Bieber, Aug 30, 2012
    #4
  5. Dennis Lee Bieber

    Adam W. Guest

    On Wednesday, August 29, 2012 10:07:54 PM UTC-4, Dennis Lee Bieber wrote:
    > On Wed, 29 Aug 2012 16:45:10 -0700 (PDT), "Adam W."
    >
    > I'm a tad curious if using the notation
    >
    >
    >
    > b'\x1bA'
    >
    >
    >
    > without the .encode() would work.
    >
    >
    >
    > My concern is that you may encounter some "string" of data for
    >
    > printing which the .encode() ends up /changing/ (don't UTF-8 strings use
    >
    > a high-bit to signal a multi-byte encoding of what had been a single
    >
    > character?). A pure byte string shouldn't have that problem.
    >


    Your notation does work, and I was just coming around to reevaluating the use of the encode because I am getting really odd results when trying to print lines.

    For example I set the byte length to 10 and sent this 500 times or so expecting to get a solid black bar:
    ep.write('\x16FFFFFFFFFF'.encode('utf-8'))

    But what I got was a weird stripped pattern... I feel like a lot of my commands are working by chance, I can't explain to myself why the A in \x1bA isn't being treated as part of the hex. This stuff always confuses me.


    >
    > > >>> ep = usb.util.find_descriptor(

    >
    > > intf,

    >
    > > custom_match = \

    >
    > > lambda e: \

    >
    > > usb.util.endpoint_direction(e.bEndpointAddress) == \

    >
    > > usb.util.ENDPOINT_IN

    >
    > > )

    >
    >
    >
    > Seems tedious to keep swapping -- does USB support bidirectional
    >
    > connections?
    >


    I assigned the input to ep2 to resolve the switching issue.
     
    Adam W., Aug 30, 2012
    #5
  6. On Wed, 29 Aug 2012 20:53:48 -0700 (PDT), "Adam W."
    <> declaimed the following in
    gmane.comp.python.general:

    > Your notation does work, and I was just coming around to reevaluating the use of the encode because I am getting really odd results when trying to print lines.
    >
    > For example I set the byte length to 10 and sent this 500 times or so expecting to get a solid black bar:
    > ep.write('\x16FFFFFFFFFF'.encode('utf-8'))


    How many bytes did it claim to send?
    >
    > But what I got was a weird stripped pattern... I feel like a lot of my commands are working by chance, I can't explain to myself why the A in \x1bA isn't being treated as part of the hex. This stuff always confuses me.
    >

    That's the easy one -- \x in a string introduces an 8-bit byte value
    -- so only two hex digits well be read. The "A" is interpreted as
    regular text.
    --
    Wulfraed Dennis Lee Bieber AF6VN
    HTTP://wlfraed.home.netcom.com/
     
    Dennis Lee Bieber, Aug 30, 2012
    #6
  7. Dennis Lee Bieber

    Adam W. Guest

    On Thursday, August 30, 2012 12:55:14 AM UTC-4, Dennis Lee Bieber wrote:
    >
    > How many bytes did it claim to send?
    >

    11, which is what I expected. But I changed the byte value to 16 (because I was having trouble getting single digit hex values working in the command) and sent this command:
    >>> for x in range(0,500):

    ep.write(b'\x16\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')

    it respond with 500 17's and prints a black bar! So it looks like whatever concern you had with using encode was coming to fruition.

    >
    > That's the easy one -- \x in a string introduces an 8-bit byte value
    >
    > -- so only two hex digits well be read. The "A" is interpreted as
    >
    > regular text.


    Interesting, so what if I only wanted to send 4bits as a hex value? Also can I somehow throw in some binary alongside of hex? At some point in my program I'm going to need to send some commands preferably in hex along with the binary image data.
     
    Adam W., Aug 30, 2012
    #7
  8. On Thu, 30 Aug 2012 05:51:56 -0700 (PDT), "Adam W."
    <> declaimed the following in
    gmane.comp.python.general:


    >
    > Interesting, so what if I only wanted to send 4bits as a hex value? Also can I somehow throw in some binary alongside of hex? At some point in my program I'm going to need to send some commands preferably in hex along with the binary image data.


    You will never be able to send something less than 8-bits. I suspect
    the printer treats each byte as one column of dots, so you'd probably be
    sending \xF0 or \x0F depending on which bit is "top" or "bottom" -- this
    would give a half column of ink and the other half would be blank.

    \x?? is the Python notation to represent a binary value in a
    string/byte LITERAL.

    Your previous attempt with the "F" was sending ASCII F characters,
    hex value 46 (01000110) [was your striped layout one skinny stripe, and
    three widths lower a double-width stripe?].

    As long as your image data is in on/off (B/W) bytes (unsigned, or to
    simplify, integers in the range 0..255), it should be no problem.

    >>> import random
    >>> data = [random.randint(0, 255) for i in range(32)]
    >>> data

    [25, 134, 166, 159, 253, 121, 114, 110, 18, 122, 197, 233, 127, 216,
    188, 89, 10, 201, 250, 32, 231, 32, 99, 7, 227, 122, 166, 172, 21, 78,
    17, 166]
    >>> bar = bytearray(data)
    >>> bar

    bytearray(b'\x19\x86\xa6\x9f\xfdyrn\x12z\xc5\xe9\x7f\xd8\xbcY\n\xc9\xfa
    \xe7 c\x07\xe3z\xa6\xac\x15N\x11\xa6')
    >>> bytes(bar)

    '\x19\x86\xa6\x9f\xfdyrn\x12z\xc5\xe9\x7f\xd8\xbcY\n\xc9\xfa \xe7
    c\x07\xe3z\xa6\xac\x15N\x11\xa6'
    >>>
    >>> bbar = bytes(bar)
    >>> for b in bbar:

    .... print "Decimal: %4.4s:\tHex: \\x%2.2X\t%s" % (ord(b), ord(b), b)
    ....
    Decimal: 25: Hex: \x19 
    Decimal: 134: Hex: \x86 ?
    Decimal: 166: Hex: \xA6 ?
    Decimal: 159: Hex: \x9F ?
    Decimal: 253: Hex: \xFD ??
    Decimal: 121: Hex: \x79 y
    Decimal: 114: Hex: \x72 r
    Decimal: 110: Hex: \x6E n
    Decimal: 18: Hex: \x12 
    Decimal: 122: Hex: \x7A z
    Decimal: 197: Hex: \xC5 ?
    Decimal: 233: Hex: \xE9 ?
    Decimal: 127: Hex: \x7F 
    Decimal: 216: Hex: \xD8 ?
    Decimal: 188: Hex: \xBC ?
    Decimal: 89: Hex: \x59 Y
    Decimal: 10: Hex: \x0A

    Decimal: 201: Hex: \xC9 ?
    Decimal: 250: Hex: \xFA ??
    Decimal: 32: Hex: \x20
    Decimal: 231: Hex: \xE7 ?
    Decimal: 32: Hex: \x20
    Decimal: 99: Hex: \x63 c
    Decimal: 7: Hex: \x07 
    Decimal: 227: Hex: \xE3 ?
    Decimal: 122: Hex: \x7A z
    Decimal: 166: Hex: \xA6 ?
    Decimal: 172: Hex: \xAC °
    Decimal: 21: Hex: \x15 
    Decimal: 78: Hex: \x4E N
    Decimal: 17: Hex: \x11 
    Decimal: 166: Hex: \xA6 ?
    >>>


    You might be able to go directly:

    bbar = bytes(data)

    based on the documentation for Python 3.2.3. I can't even find bytes()
    in the 2.7 documentation.

    I suspect your biggest problem will be in converting your image
    format (at the minimum, it may be row oriented and you need to generate
    columns of 8-rows at a time)


    Try:

    data = [ 22,
    0, 1, 3, 7, 15, 31, 63, 127, 255,
    127, 63, 31, 15, 7, 3, 1, 0 ]
    bbar = bytes(data)

    Set data length to 17, and send bbar...

    If my guess is right, this should put up an equilateral triangle.


    --
    Wulfraed Dennis Lee Bieber AF6VN
    HTTP://wlfraed.home.netcom.com/
     
    Dennis Lee Bieber, Aug 30, 2012
    #8
  9. On 30Aug2012 05:51, Adam W. <> wrote:
    | On Thursday, August 30, 2012 12:55:14 AM UTC-4, Dennis Lee Bieber wrote:
    | > How many bytes did it claim to send?
    |
    | 11, which is what I expected. But I changed the byte value to 16
    | (because I was having trouble getting single digit hex values working
    | in the command) and sent this command:
    |
    | >>> for x in range(0,500):
    | ep.write(b'\x16\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
    |
    | it respond with 500 17's and prints a black bar! So it looks like whatever concern you had with using encode was coming to fruition.

    Yeah. Try 'iso8859-1' instead of 'utf-8'. You want to be not translating
    the byte values at all. UTF-8 encodes character values over 127 as multibyte
    sequences. ISO8859-1 is a 256 code set that does no translation -
    character codes in go directly to byte values out.

    You're speaking a binary protocol, not text, so you want a one to one
    mapping. Better still would be to be using a bytes I/O layer instead of
    one with a text->byte translation; I do not know if the USB library
    you're using offers such. So try 'iso8859-1'; at least the translation
    is a no-op.

    Cheers,
    --
    Cameron Simpson <>

    B1FF is an archetype, and all you're showing us is one of the more amusing of
    his many instantiations. - Howard E. Motteler <>
    Ah, perhaps Arthur Clarke anticipated this in his celebrated short story,
    "The Nine Million Names Of B1FF"? - Nosy <>
     
    Cameron Simpson, Aug 30, 2012
    #9
    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. Adam W.

    Sending USB commands with Python

    Adam W., Aug 29, 2012, in forum: Python
    Replies:
    8
    Views:
    1,421
    Dennis Lee Bieber
    Aug 29, 2012
  2. Cameron Simpson

    Re: Sending USB commands with Python

    Cameron Simpson, Aug 29, 2012, in forum: Python
    Replies:
    0
    Views:
    212
    Cameron Simpson
    Aug 29, 2012
  3. Cameron Simpson

    Re: Sending USB commands with Python

    Cameron Simpson, Aug 30, 2012, in forum: Python
    Replies:
    0
    Views:
    196
    Cameron Simpson
    Aug 30, 2012
  4. Replies:
    8
    Views:
    256
  5. Setia Budi

    Send commands to USB device in Python

    Setia Budi, Feb 11, 2014, in forum: Python
    Replies:
    1
    Views:
    121
Loading...

Share This Page