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

Sending USB commands with Python

1,869 views
Skip to first unread message

Adam W.

unread,
Aug 28, 2012, 8:04:49 PM8/28/12
to
So I'm trying to get as low level as I can with my Dymo label printer, and this method described the PDF http://sites.dymo.com/Documents/LW450_Series_Technical_Reference.pdf seems to be it.

I'm unfamiliar with dealing with the USB interface and would greatly appreciate it if someone could tell me how to send and receive these commands with Python. Perhaps if you were feeling generous and wanted to write a bit of sample code, sending the "Get Printer Status" command and receiving the response (page 17 of the PDF) would be perfect to get me on my way.

Thanks,
Adam
Message has been deleted

hamilton

unread,
Aug 28, 2012, 11:03:38 PM8/28/12
to
On 8/28/2012 8:54 PM, Dennis Lee Bieber wrote:
> 2) does the printer appear as a serial port by the OS? Or as a
> printer device?

The OP posted the link to the manual.

If your not going to at least look it over, .........


USB Printer Interface

The LabelWriter 450 series printers all communicate with the host
computer using a full-speed USB 2.0 interface. This interface also
operates with USB Version 1.1 or later. The printers implement the
standard USB Printer Class Device interface for communications (see
http://www.usb.org/developers/devclass/).

hamilton

PS: Page 14

alex23

unread,
Aug 29, 2012, 1:04:50 AM8/29/12
to
On Aug 29, 1:03 pm, hamilton <hamil...@nothere.com> wrote:
> The OP posted the link to the manual.
> If your not going to at least look it over, .........

Speaking for myself, I _don't_ go out of my way to read extra material
to help someone with a problem here. If it's worth mentioning, mention
it in the question.

hamilton

unread,
Aug 29, 2012, 1:18:01 AM8/29/12
to
On 8/28/2012 11:04 PM, alex23 wrote:
> On Aug 29, 1:03 pm, hamilton <hamil...@nothere.com> wrote:
>> The OP posted the link to the manual.
>> If your not going to at least look it over, .........
>
> Speaking for myself, I _don't_ go out of my way to read extra material

But, you will give advice that has no value.


Anything you post here from now on will be suspect.

hamilton

Tim Roberts

unread,
Aug 29, 2012, 2:45:16 AM8/29/12
to
Well, it's more than "a bit of sample code". You would essentially be
writing a device driver.

Which operating system are you using? If you are on Windows, then the
operating system has already loaded a printer driver for this device. You
can't talk to the USB pipes without uninstalling that driver. It would be
just about as easy for you to learn to use GDI to write to the printer like
a normal application, and that way the code would work on the NEXT
generation of printer, too.

The libusb or libusbx libraries can be used to talk to USB devices. There
is a Python binding. On Windows, you still need to have a driver, but the
libusbx instructions can help you find an install one.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Adam W.

unread,
Aug 29, 2012, 8:47:00 AM8/29/12
to
On Wednesday, August 29, 2012 2:45:17 AM UTC-4, Tim Roberts wrote:
> Which operating system are you using? If you are on Windows, then the
>
> operating system has already loaded a printer driver for this device.
>
>
> The libusb or libusbx libraries can be used to talk to USB devices. There
>
> is a Python binding. On Windows, you still need to have a driver, but the
>
> libusbx instructions can help you find an install one.
>

I am on Windows and have installed a driver using libusb-win32. Using http://pyusb.sourceforge.net/docs/1.0/tutorial.html as a template, this is my code so far:

import usb.core
import usb.util

dev = usb.core.find(idVendor=0x0922, idProduct=0x0021)

# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()

# get an endpoint instance
cfg = dev.get_active_configuration()
interface_number = cfg[(0,0)].bInterfaceNumber
alternate_settting = usb.control.get_interface(dev,interface_number)
intf = usb.util.find_descriptor(
cfg, bInterfaceNumber = interface_number,
bAlternateSetting = 0
)

ep = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT
)

assert ep is not None


I had to manually set bAlternateSetting to 0 for it to run and add dev to usb.control.get_interface(dev,interface_number).

Trying to do the status thing mentioned before, in the interpreter I did:

>>> ep.write('A')
2

And the manual says 2 is not a valid option... So something isn't adding up.
Message has been deleted

Adam W.

unread,
Aug 29, 2012, 5:21:30 PM8/29/12
to pytho...@python.org
On Wednesday, August 29, 2012 4:09:49 PM UTC-4, Dennis Lee Bieber wrote:
>
> Don't the commands require an <esc> character? "\x1BA" (or
> "\x1B\x41")
>
> OTOH, if the <esc> is issued behind the scenes,

I'm not sure which esc char it is asking for, I don't think libusb is providing its own, and it seems like the one you suggested isn't what it wants either..

> ... and you do not need to issue some sort of read()
> the "2" you are seeing is the "number of bytes written";
>
> you need to issue a read request to retrieve the returned printer
>
> status.
>

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
>>> ep.read(1)
Traceback (most recent call last):
File "<pyshell#75>", line 1, in <module>
ep.read(1)
File "C:\Python32\lib\site-packages\usb\core.py", line 301, in read
return self.device.read(self.bEndpointAddress, size, self.interface, timeout)
File "C:\Python32\lib\site-packages\usb\core.py", line 654, in read
self.__get_timeout(timeout)
File "C:\Python32\lib\site-packages\usb\backend\libusb01.py", line 483, in bulk_read
timeout)
File "C:\Python32\lib\site-packages\usb\backend\libusb01.py", line 568, in __read
timeout
File "C:\Python32\lib\site-packages\usb\backend\libusb01.py", line 384, in _check
raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] b'libusb0-dll:err [_usb_setup_async] invalid endpoint 0x02\n'

Avoiding the read command all together I should be able to write "<esc> E" and have it feed some paper, which it is not doing, so obviously there is more to uncover. That said I feel this endeavor has evolved and is no longer pertinent to the Python group so I will let you guys off the hook on this (although responses/suggestions are still welcome).

Thanks for all your help!
Message has been deleted
Message has been deleted

Cameron Simpson

unread,
Aug 29, 2012, 6:29:32 PM8/29/12
to Dennis Lee Bieber, pytho...@python.org
On 29Aug2012 17:57, Dennis Lee Bieber <wlf...@ix.netcom.com> wrote:
| On Wed, 29 Aug 2012 14:21:30 -0700 (PDT), "Adam W."
| <AWasi...@gmail.com> 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.
--
Cameron Simpson <c...@zip.com.au>

There are too many people now for everyone to be entitled to his own opinion.
- Dr. Handelman
Message has been deleted

Cameron Simpson

unread,
Aug 29, 2012, 7:25:12 PM8/29/12
to Dennis Lee Bieber, pytho...@python.org
On 30Aug2012 08:29, I wrote:
| UTF-16? ISTR that Windows often uses big endian UTF-16 [...]

Sorry, little-endian. Anyway...
--
Cameron Simpson <c...@zip.com.au>

Ed Campbell's <e...@Tekelex.Com> pointers for long trips:
3. Stop and take a break before you really need it.

Adam W.

unread,
Aug 29, 2012, 7:45:10 PM8/29/12
to pytho...@python.org
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!
Message has been deleted

Adam W.

unread,
Aug 29, 2012, 7:50:51 PM8/29/12
to
On Wednesday, August 29, 2012 7:45:13 PM UTC-4, Adam W. wrote:
>

This is a test to see if the default cc'ing the group is why I am double posting (I'm using Google groups). You can see this without the cc right?

Adam W.

unread,
Aug 29, 2012, 8:06:00 PM8/29/12
to
On Wednesday, August 29, 2012 7:45:10 PM UTC-4, Adam W. wrote:
> 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])
>

Scratch that, that was an embarrassing question to ask. I obviously never used arrays before :)

MRAB

unread,
Aug 29, 2012, 8:53:17 PM8/29/12
to pytho...@python.org
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.
Message has been deleted

Adam W.

unread,
Aug 29, 2012, 11:53:48 PM8/29/12
to
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.
Message has been deleted

Adam W.

unread,
Aug 30, 2012, 8:51:56 AM8/30/12
to
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.
Message has been deleted

Cameron Simpson

unread,
Aug 30, 2012, 6:47:56 PM8/30/12
to Adam W., pytho...@python.org
On 30Aug2012 05:51, Adam W. <AWasi...@gmail.com> 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 <c...@zip.com.au>

B1FF is an archetype, and all you're showing us is one of the more amusing of
his many instantiations. - Howard E. Motteler <mott...@umbc.edu>
Ah, perhaps Arthur Clarke anticipated this in his celebrated short story,
"The Nine Million Names Of B1FF"? - Nosy <ata...@nmsu.edu>

Tim Roberts

unread,
Aug 30, 2012, 11:55:37 PM8/30/12
to
"Adam W." <AWasi...@gmail.com> wrote:
>
>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
>>>> ep.read(1)
>usb.core.USBError: [Errno None] b'libusb0-dll:err [_usb_setup_async] invalid endpoint 0x02\n'

USB endponts only go in one direction. There will be one endpoint for
outoging data, and one endpoint for incoming data.
0 new messages