ryankurte / rust-ptouch Goto Github PK
View Code? Open in Web Editor NEWRust driver for Brother P-Touch label makers (USB)
Rust driver for Brother P-Touch label makers (USB)
Thank you for sharing such a useful tool!
I'm looking forward to Bluetooth support, but there is one more feature I would like.
Please add the function to write line breaks, catalog format, or both in QR codes.
It would be nice to be able to insert newline characters in the CODE string, or read an external template file for this requirement.
catalog formats knowlage
https://github.com/zxing/zxing/wiki/Barcode-Contents
external template file example
https://github.com/leplusorg/docker-qrcode
best regards.
It appears the tape margins are purely a software concept, and they're super conservative. It would be neat to support software overscan so (if you're feeling dangerous) you can write to more of the tape area.
Is it possible to add the Cargo.lock
file, to ensure consistency? :)
Any plans to add support for the very new PTD-610BT? Thanks!
Hello,
First of all, thank you for this repository. I've been struggling with a few different library to make some Brother printers to print properly, and this one worked quite well.
However, I got stuck for quite some time before I finally managed to print something, and that's why I'm opening an issue here.
It may be a bug, or it may be that the printer I used is broken/misconfigured. I don't really know.
I'm gonna describe my toolchain and the problem I got, and I'm also gonna explain the workaround I made to finally be able to print, in case some people get the same bug than me.
I have a brother pt-e550w printer, and I'm trying to use this program to print things with it, but I get a timeout when the program tries to read the answer of a status request sent to the printer.
Since both the problem and the workaround are complex, this issue is very long. I'm sorry about that, but I guess it is better if I give all the details.
I am working on windows, and I am using WSL2 for almost all my toolchains. I want to be able to plug my pt-e550w to my computer and print something. The command for that would be: cargo run -- --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
.
However, WSL2 does not have natively access to the USB devices plugged to the computer. If I use the lsusb
command while the printer is plugged in, I get the following result:
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Fortunately, there exist a piece of software to forward the USB traffic from windows to WSL over a local network interface (some kind of USB over IP). I found it here: https://devblogs.microsoft.com/commandline/connecting-usb-devices-to-wsl/
I installed the required tools, and listed the devices on windows with the usbipd wsl list
command in a windows terminal. Here's the result:
> usbipd wsl list
BUSID VID:PID DEVICE STATE
2-3 04f9:2060 USB Printing Support Not attached
2-4 1bcf:0005 USB Input Device Not attached
2-8 13d3:56ba Integrated Camera, Integrated IR Camera Not attached
2-9 06cb:00bd Synaptics UWP WBDI Not attached
2-10 8087:0aaa Intel(R) Wireless Bluetooth(R) Not attached
Then, using the usbipd wsl attach --busid 2-3
command in the windows console, I can make the printer visible in wsl:
> usbipd wsl attach --busid 2-3
usbipd: info: Using default distribution 'Ubuntu'.
Then, in wsl console:
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 04f9:2060 Brother Industries, Ltd PT-E550W
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Until then, everything's fine. I should be able to print now.
When trying the cargo run -- --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
command, I got this result:
$ cargo run -- --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
warning: unused borrow that must be used
--> src/commands.rs:138:9
|
138 | &buff[7..11].copy_from_slice(&raster_bytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the borrow produces a value
|
= note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
|
138 | let _ = &buff[7..11].copy_from_slice(&raster_bytes);
| +++++++
warning: `ptouch` (lib) generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 1.90s
Running `target/debug/ptouch-util --log-level debug --device pt-e550w print qr-text hello 'hello friend'`
09:41:54 [DEBUG] (1) ptouch_util: Connecting to PTouch device: Options { device: PtE550W, index: 0, no_reset: false, usb_no_claim: false, usb_no_detach: false }
09:41:54 [DEBUG] (1) ptouch: Found matching devices: [(Bus 001 Device 003: ID 04f9:2060, DeviceDescriptor { bLength: 18, bDescriptorType: 1, bcdUSB: 272, bDeviceClass: 0, bDeviceSubClass: 0, bDeviceProtocol: 0, bMaxPacketSize: 64, idVendor: 1273, idProduct: 8288, bcdDevice: 256, iManufacturer: 1, iProduct: 2, iSerialNumber: 3, bNumConfigurations: 1 })]
09:41:54 [DEBUG] (1) ptouch: Error opening device
Error: Error connecting to PTouch: Usb(Access)
Looks like I need root privileges to access the USB device. Ok, let's adapt the command then: sudo target/debug/ptouch-util --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
:
$ sudo target/debug/ptouch-util --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
09:43:23 [DEBUG] (1) ptouch_util: Connecting to PTouch device: Options { device: PtE550W, index: 0, no_reset: false, usb_no_claim: false, usb_no_detach: false }
09:43:23 [DEBUG] (1) ptouch: Found matching devices: [(Bus 001 Device 003: ID 04f9:2060, DeviceDescriptor { bLength: 18, bDescriptorType: 1, bcdUSB: 272, bDeviceClass: 0, bDeviceSubClass: 0, bDeviceProtocol: 0, bMaxPacketSize: 64, idVendor: 1273, idProduct: 8288, bcdDevice: 256, iManufacturer: 1, iProduct: 2, iSerialNumber: 3, bNumConfigurations: 1 })]
09:43:23 [DEBUG] (1) ptouch: Checking for active kernel driver
09:43:23 [DEBUG] (1) ptouch: Kernel driver inactive
09:43:23 [DEBUG] (1) ptouch: Claiming interface
09:43:23 [DEBUG] (1) ptouch: WRITE: [00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00]
09:43:23 [DEBUG] (1) ptouch: WRITE: [1b, 40]
09:43:23 [DEBUG] (1) ptouch_util: Connected! fetching status...
09:43:23 [DEBUG] (1) ptouch: WRITE: [1b, 69, 53]
Error: Operation timeout
This is where the bug happens: the program found the printer, sent data to it, then sent a status request, but when trying to fetch the response, a timeout happened.
Going into the code, I found out the exact error happened in the status method of lib.rs, line 332:
pub fn status(&mut self) -> Result<Status, Error> {
// Issue status request
self.status_req()?;
// Read status response
let d = self.read(self.timeout)?;
// Convert to status object
let s = Status::from(d);
debug!("Status: {:02x?}", s);
Ok(s)
}
The status_req method just writes the status request hex code in the USB connection:
fn status_req(&mut self) -> Result<(), Error> {
self.write(&[0x1b, 0x69, 0x53], self.timeout)
}
This method does not fail, but the call to self.read
does. The read method tries to read as much bytes as the length of the buffer (32 bytes in our case), and if the number of read bytes is not 32, it returns Err(Error::Timeout)
.
fn read(&mut self, timeout: Duration) -> Result<[u8; 32], Error> {
let mut buff = [0u8; 32];
// Execute read
let n = self.handle.read_bulk(self.stat_ep, &mut buff, timeout)?;
if n != 32 {
return Err(Error::Timeout)
}
// TODO: parse out status?
Ok(buff)
}
That's exactly what is happening. Since the call to read
is placed before a ? operator, the error will be propagated, and later the program will see the status fetching was unsuccessfull, and therefore stop itself.
I really don't know why isn't the printer responding via USB. I've checked the printer's documentation to see if there's any way to enable or disable the USB responses, but I didn't find anything. I haven't found any similar issue reported on the internet.
One of the possibility is that the USB over IP software to bind the USB ports to WSL doesn't allow read and write, but I've asked a friend who used it by the past and he said he hasn't been experiencing any issue with it.
With this in mind, I tried running a Ubuntu 22.04 virtual machine in VMware to run the program, since the USB mapping from windows to a virtual machine is reliable (at least I never had problems with it).
Sadly, the result was exactly the same.
At some point, I got the idea of running the program directly on windows instead of WSL. I installed all the rust toolchain on windows via rustup, and compiled and run the program again, with the same command: cargo run -- --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
. I got another error this time:
> cargo run -- --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
warning: unused borrow that must be used
--> src\commands.rs:138:9
|
138 | &buff[7..11].copy_from_slice(&raster_bytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the borrow produces a value
|
= note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
|
138 | let _ = &buff[7..11].copy_from_slice(&raster_bytes);
| +++++++
warning: `ptouch` (lib) generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.15s
Running `target\debug\ptouch-util.exe --log-level debug --device pt-e550w print qr-text hello "hello friend"`
12:03:21 [DEBUG] (1) ptouch_util: Connecting to PTouch device: Options { device: PtE550W, index: 0, no_reset: false, usb_no_claim: false, usb_no_detach: false }
12:03:21 [DEBUG] (1) ptouch: Found matching devices: [(Bus 002 Device 011: ID 04f9:2060, DeviceDescriptor { bLength: 18, bDescriptorType: 1, bcdUSB: 272, bDeviceClass: 0, bDeviceSubClass: 0, bDeviceProtocol: 0, bMaxPacketSize: 64, idVendor: 1273, idProduct: 8288, bcdDevice: 256, iManufacturer: 1, iProduct: 2, iSerialNumber: 3, bNumConfigurations: 1 })]
12:03:21 [DEBUG] (1) ptouch: Error opening device
Error: Error connecting to PTouch: Usb(NotSupported)
Running it in a console with admin privileges led to the same message.
After diving inside the code again, I found the origin of the error: the util.rs file, at line 128, tries to call the new function of the PTouch struct. The new function will call the call_with_context function of lib.rs, which will, at line 188, try to start a connection with the device by calling the open method on it. In case of error, a debug message will be printed, and the function will return the error returned by open:
let mut handle = match device.open() {
Ok(v) => v,
Err(e) => {
debug!("Error opening device");
return Err(e.into());
}
};
The open method can return a rusb::error, and among those errors is rusb::error::NotSupported, which means "Operation not supported or unimplemented on this platform.", according to the documentation.
But the device is an instance of the rusb::Device struct from the rusb crate, so if the error comes from this crate, it is beyond the scope of this repository.
But still, it seems that this ptouch driver does not work on windows. I'm running windows 11 by the way.
I needed to get the printing to work.
What I then did is that I created an alternative method to get_status, which I called get_status_mocked. The goal was to build an instance of the Status struct ith the printer informations and to return it. The needed informations about the status can be found in the pt-e550w manual, section 4. Printing command details, Status command.
My function was like this:
pub fn status_mock(&mut self) -> Result<Status, Error> {
Ok(Status {
model: 0x66,
error1: Error1::empty(),
error2: Error2::empty(),
media_width: 12,
media_kind: MediaKind::LaminatedTape,
status_type: DeviceStatus::Completed,
phase: Phase::Editing,
tape_colour: TapeColour::White,
text_colour: TextColour::Black
})
}
Warning: if you try to do the same workaround, you might need to change some fields, depending on your printer (the model, the tape colour, the media width, etc).
I then edited the line 133 of util.rs to call status_mock instead of status:
let status = pt.status_mock()?;
After this change, I tried to cargo build
again, and to run the program again with sudo target/debug/ptouch-util --log-level debug --device pt-e550w print qr-text "hello" "hello friend"
: the printer printed the expected qr code and text ! (I'm not giving the output because it is very long since all the data sent to the printer are logged).
With the workaround, the printing function now works. However, if someone gets stuck on the same problem than me in the future, this issue should contain enough information to help them.
In the end, maybe what I'm experimenting is not a problem with this program, but with rusb ; if that's the case, then I'm sorry, but I still wanted to report it.
That's actually the first GitHub issue on an open source project I've ever written, If some information are missing, please tell me.
Hi,
While trying to add a new feature (the switch to bypass the status request you suggested here), I noticed something that looks like a bug: in the device.rs file, in method width, you return a width based on the model of self
; but the width for 3 of them seems to miss a digit:
Tze12mm => 2,
Tze18mm => 8,
Tze24mm => 4,
That probably should be 12, 18 and 24, right ?
Fortunately, it looks like this method is not used anywhere. It is still good that you implemented it, because it turns out I needed it for the feature I'm adding.
Anyway, I am fixing this in the pull request I'm gonna open for the new feature.
The raster manual specifies this advanced mode setting:
No chain printing
When printing multiple copies, the labels are fed after the last one is printed.
But I can't see anywhere how to actually print multiple copies of the same label...?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.