1use std::time::Duration;
7
8use commands::Commands;
9use device::Status;
10use image::ImageError;
11use log::{trace, debug, error};
12
13#[cfg(feature = "structopt")]
14use structopt::StructOpt;
15
16#[cfg(feature = "strum")]
17use strum::VariantNames;
18
19use rusb::{Context, Device, DeviceDescriptor, DeviceHandle, Direction, TransferType, UsbContext};
20
21pub mod device;
22use device::*;
23
24pub mod commands;
25
26pub mod bitmap;
27
28pub mod tiff;
29
30pub mod render;
31
32pub struct PTouch {
34 _device: Device<Context>,
35 handle: DeviceHandle<Context>,
36 descriptor: DeviceDescriptor,
37 timeout: Duration,
39
40 cmd_ep: u8,
41 stat_ep: u8,
42}
43
44pub const BROTHER_VID: u16 = 0x04F9;
46
47#[derive(Clone, PartialEq, Debug)]
49#[cfg_attr(feature = "structopt", derive(StructOpt))]
50pub struct Options {
51 #[cfg_attr(feature = "structopt", structopt(long, possible_values = &device::PTouchDevice::VARIANTS, default_value = "pt-p710bt"))]
52 pub device: device::PTouchDevice,
54
55 #[cfg_attr(feature = "structopt", structopt(long, default_value = "0"))]
56 pub index: usize,
58
59 #[cfg_attr(feature = "structopt", structopt(long, default_value = "500"))]
60 pub timeout_milliseconds: u64,
62
63 #[cfg_attr(feature = "structopt", structopt(long, hidden = true))]
64 pub no_reset: bool,
66
67 #[cfg_attr(feature = "structopt", structopt(long, hidden = true))]
68 pub usb_no_claim: bool,
70
71 #[cfg_attr(feature = "structopt", structopt(long, hidden = true))]
72 pub usb_no_detach: bool,
74
75 #[cfg_attr(feature = "structopt", structopt(long))]
76 pub no_status_fetch: bool,
78}
79
80lazy_static::lazy_static! {
82 static ref CONTEXT: Context = {
83 Context::new().unwrap()
84 };
85}
86
87#[derive(thiserror::Error, Debug)]
89pub enum Error {
90 #[error("USB error: {:?}", 0)]
91 Usb(rusb::Error),
92
93 #[error("IO error: {:?}", 0)]
94 Io(std::io::Error),
95
96 #[error("Image error: {:?}", 0)]
97 Image(ImageError),
98
99 #[error("Invalid device index")]
100 InvalidIndex,
101
102 #[error("No supported languages")]
103 NoLanguages,
104
105 #[error("Unable to locate expected endpoints")]
106 InvalidEndpoints,
107
108 #[error("Renderer error")]
109 Render,
110
111 #[error("Operation timeout")]
112 Timeout,
113
114 #[error("PTouch Error ({:?} {:?})", 0, 1)]
115 PTouch(Error1, Error2),
116}
117
118impl From<std::io::Error> for Error {
119 fn from(e: std::io::Error) -> Self {
120 Error::Io(e)
121 }
122}
123
124impl From<rusb::Error> for Error {
125 fn from(e: rusb::Error) -> Self {
126 Error::Usb(e)
127 }
128}
129
130impl From<ImageError> for Error {
131 fn from(e: ImageError) -> Self {
132 Error::Image(e)
133 }
134}
135
136#[derive(Clone, Debug, PartialEq)]
138pub struct Info {
139 pub manufacturer: String,
140 pub product: String,
141 pub serial: String,
142}
143
144impl PTouch {
145 pub fn new(o: &Options) -> Result<Self, Error> {
147 Self::new_with_context(o, &CONTEXT)
148 }
149
150 pub fn new_with_context(o: &Options, context: &Context) -> Result<Self, Error> {
152 let devices = context.devices()?;
154
155 let mut matches: Vec<_> = devices
157 .iter()
158 .filter_map(|d| {
159 let desc = match d.device_descriptor() {
161 Ok(d) => d,
162 Err(e) => {
163 debug!("Could not fetch descriptor for device {:?}: {:?}", d, e);
164 return None;
165 }
166 };
167
168 if desc.vendor_id() == BROTHER_VID && desc.product_id() == o.device as u16 {
170 Some((d, desc))
171 } else {
172 None
173 }
174 })
175 .collect();
176
177 if matches.len() < o.index || matches.len() == 0 {
179 debug!(
180 "Device index ({}) exceeds number of discovered devices ({})",
181 o.index,
182 matches.len()
183 );
184 return Err(Error::InvalidIndex);
185 }
186
187 debug!("Found matching devices: {:?}", matches);
188
189 let (device, descriptor) = matches.remove(o.index);
191
192 let mut handle = match device.open() {
194 Ok(v) => v,
195 Err(e) => {
196 debug!("Error opening device");
197 return Err(e.into());
198 }
199 };
200
201 if let Err(e) = handle.reset() {
203 debug!("Error resetting device handle");
204 return Err(e.into())
205 }
206
207 let config_desc = match device.config_descriptor(0) {
209 Ok(v) => v,
210 Err(e) => {
211 debug!("Failed to fetch config descriptor");
212 return Err(e.into());
213 }
214 };
215
216 let interface = match config_desc.interfaces().next() {
217 Some(i) => i,
218 None => {
219 debug!("No interfaces found");
220 return Err(Error::InvalidEndpoints);
221 }
222 };
223
224 let (mut cmd_ep, mut stat_ep) = (None, None);
228
229 for interface_desc in interface.descriptors() {
230 for endpoint_desc in interface_desc.endpoint_descriptors() {
231 match (endpoint_desc.transfer_type(), endpoint_desc.direction()) {
233 (TransferType::Bulk, Direction::In) => stat_ep = Some(endpoint_desc.address()),
234 (TransferType::Bulk, Direction::Out) => cmd_ep = Some(endpoint_desc.address()),
235 (_, _) => continue,
236 }
237 }
238 }
239
240 let (cmd_ep, stat_ep) = match (cmd_ep, stat_ep) {
241 (Some(cmd), Some(stat)) => (cmd, stat),
242 _ => {
243 debug!("Failed to locate command and status endpoints");
244 return Err(Error::InvalidEndpoints);
245 }
246 };
247
248 debug!("Checking for active kernel driver");
253 match handle.kernel_driver_active(interface.number())? {
254 true => {
255 if !o.usb_no_detach {
256 debug!("Detaching kernel driver");
257 handle.detach_kernel_driver(interface.number())?;
258 } else {
259 debug!("Kernel driver detach disabled");
260 }
261 },
262 false => {
263 debug!("Kernel driver inactive");
264 },
265 }
266
267 if !o.usb_no_claim {
272 debug!("Claiming interface");
273 handle.claim_interface(interface.number())?;
274 } else {
275 debug!("Claim interface disabled");
276 }
277
278 let mut s = Self {
280 _device: device,
281 handle,
282 descriptor,
283 cmd_ep,
284 stat_ep,
285 timeout: Duration::from_millis(o.timeout_milliseconds),
286 };
287
288 if !o.no_reset {
290 s.invalidate()?;
292 s.init()?;
294 } else {
295 debug!("Skipping device reset");
296 }
297
298 Ok(s)
299 }
300
301 pub fn info(&mut self) -> Result<Info, Error> {
303 let timeout = Duration::from_millis(200);
304
305 let languages = self.handle.read_languages(timeout)?;
307 let active_config = self.handle.active_configuration()?;
308
309 trace!("Active configuration: {}", active_config);
310 trace!("Languages: {:?}", languages);
311
312 if languages.len() == 0 {
314 return Err(Error::NoLanguages);
315 }
316
317 let language = languages[0];
319 let manufacturer =
320 self.handle
321 .read_manufacturer_string(language, &self.descriptor, timeout)?;
322 let product = self
323 .handle
324 .read_product_string(language, &self.descriptor, timeout)?;
325 let serial = self
326 .handle
327 .read_serial_number_string(language, &self.descriptor, timeout)?;
328
329 Ok(Info {
330 manufacturer,
331 product,
332 serial,
333 })
334 }
335
336 pub fn status(&mut self) -> Result<Status, Error> {
338 self.status_req()?;
340
341 let d = self.read(self.timeout)?;
343
344 let s = Status::from(d);
346
347 debug!("Status: {:02x?}", s);
348
349 Ok(s)
350 }
351
352 pub fn print_raw(&mut self, data: Vec<[u8; 16]>, info: &PrintInfo) -> Result<(), Error> {
357 self.switch_mode(Mode::Raster)?;
363
364 self.set_status_notify(true)?;
366
367 self.set_print_info(info)?;
369
370 self.set_various_mode(VariousMode::AUTO_CUT)?;
372
373 self.set_advanced_mode(AdvancedMode::NO_CHAIN)?;
379
380 self.set_margin(0)?;
383
384 self.set_compression_mode(CompressionMode::None)?;
387
388 for line in data {
390 self.raster_transfer(&line)?;
394 }
395
396 self.print_and_feed()?;
398
399
400 let mut i = 0;
402 loop {
403 if let Ok(s) = self.read_status(self.timeout) {
404 if !s.error1.is_empty() || !s.error2.is_empty() {
405 debug!("Print error: {:?} {:?}", s.error1, s.error2);
406 return Err(Error::PTouch(s.error1, s.error2));
407 }
408
409 if s.status_type == DeviceStatus::PhaseChange {
410 debug!("Started printing");
411 }
412
413 if s.status_type == DeviceStatus::Completed {
414 debug!("Print completed");
415 break;
416 }
417 }
418
419 if i > 10 {
420 debug!("Print timeout");
421 return Err(Error::Timeout);
422 }
423
424 i += 1;
425
426 std::thread::sleep(Duration::from_secs(1));
427 }
428
429
430 Ok(())
431 }
432
433 fn read(&mut self, timeout: Duration) -> Result<[u8; 32], Error> {
435 let mut buff = [0u8; 32];
436
437 let n = self.handle.read_bulk(self.stat_ep, &mut buff, timeout)?;
439
440 if n != 32 {
441 return Err(Error::Timeout)
442 }
443
444 Ok(buff)
447 }
448
449 fn write(&mut self, data: &[u8], timeout: Duration) -> Result<(), Error> {
451 debug!("WRITE: {:02x?}", data);
452
453 let n = self.handle.write_bulk(self.cmd_ep, &data, timeout)?;
455
456 if n != data.len() {
458 return Err(Error::Timeout)
459 }
460
461 Ok(())
462 }
463}