ql_label/error.rs
1//! Error types for P-Touch printer operations.
2//!
3//! This module defines all possible errors that can occur during printer
4//! communication, configuration, and print operations.
5
6use crate::Media;
7use rusb;
8use thiserror::Error;
9
10/// Main error type for P-Touch printer operations.
11///
12/// This enum encompasses all possible errors that can occur when using
13/// the printer, from USB communication issues to printer-specific errors.
14#[derive(Error, Debug)]
15pub enum Error {
16 /// USB communication error.
17 ///
18 /// Wraps underlying rusb errors for device communication issues,
19 /// timeouts, or permission problems.
20 #[error(transparent)]
21 UsbError(#[from] rusb::Error),
22
23 /// Printer device is not connected or not responding.
24 ///
25 /// This error occurs when the printer cannot be found on USB or
26 /// fails to respond to initialization commands.
27 #[error("Device is offline")]
28 DeviceOffline,
29
30 #[error("Can't read device list, permission issue ?")]
31 DeviceListNotReadable,
32
33 #[error("Device is missing endpoint")]
34 MissingEndpoint,
35
36 #[error("Received invalid response from printer")]
37 InvalidResponse(usize),
38
39 /// Invalid configuration parameter provided.
40 ///
41 /// This error occurs when configuration values are out of range
42 /// or incompatible with the selected printer model.
43 #[error("Invalid configuration parameter")]
44 InvalidConfig(String),
45
46 #[error("No media is installed in the printer")]
47 NoMediaInstalled,
48
49 /// Media type mismatch between configuration and installed tape.
50 ///
51 /// The printer has different media installed than what was specified
52 /// in the configuration. Check the installed tape and update config.
53 #[error("Media mismatch: expected {expected:?}, found {actual:?}")]
54 MediaMismatch { expected: Media, actual: Media },
55
56 #[error("Status request return no response")]
57 ReadStatusTimeout,
58
59 /// Print job timed out waiting for completion.
60 ///
61 /// The printer did not complete the print job within the expected time.
62 /// This may indicate a hardware issue or very long label.
63 #[error("Print job timeout waiting for completion")]
64 PrintTimeout,
65
66 #[error("Unexpected printer phase: {0:?}")]
67 UnexpectedPhase(crate::printer::Phase),
68
69 /// Hardware-level printer error.
70 ///
71 /// Wraps printer-specific errors reported by the device itself,
72 /// such as cover open, media issues, or mechanical problems.
73 #[error(transparent)]
74 PrinterError(PrinterError),
75}
76
77/// Hardware-specific errors reported by the printer.
78///
79/// These errors are parsed from the printer's status response and indicate
80/// physical problems with the device that need user intervention.
81#[derive(Error, Debug)]
82pub enum PrinterError {
83 // Following errors are read from printer status
84 #[error("No media is installed")]
85 NoMedia,
86
87 #[error("End of media")]
88 EndOfMedia,
89
90 #[error("Cutter jam")]
91 CutterJam,
92
93 #[error("Printer is in use")]
94 PrinterInUse,
95
96 #[error("Printer if offline")]
97 PrinterOffline,
98
99 #[error("Installed media is not match")]
100 InvalidMedia,
101
102 #[error("Expansion buffer is full")]
103 BufferFull,
104
105 #[error("Communication error")]
106 CommunicationError,
107
108 #[error("Cover is open")]
109 CoverOpen,
110
111 #[error("Media can not be fed")]
112 FeedMediaFail,
113
114 #[error("System error")]
115 SystemError,
116
117 #[error("Unknown error")]
118 UnknownError((u8, u8)),
119}
120
121impl PrinterError {
122 /// Parse printer error from 32-byte status buffer.
123 ///
124 /// Analyzes bytes 8 and 9 of the printer status response to determine
125 /// the specific error condition reported by the hardware.
126 ///
127 /// # Arguments
128 /// * `buf` - 32-byte status response from printer
129 ///
130 /// # Returns
131 /// Parsed printer error or `UnknownError((0, 0))` if no error
132 pub fn from_buf(buf: [u8; 32]) -> Self {
133 let err_1 = buf[8];
134 let err_2 = buf[9];
135
136 match err_1 {
137 0b0000_0001 => Self::NoMedia,
138 0b0000_0010 => Self::EndOfMedia,
139 0b0000_0100 => Self::CutterJam,
140 0b0001_0000 => Self::PrinterInUse,
141 0b0010_0000 => Self::PrinterOffline,
142 _ => match err_2 {
143 0b0000_0001 => Self::InvalidMedia,
144 0b0000_0010 => Self::BufferFull,
145 0b0000_0100 => Self::CommunicationError,
146 0b0001_0000 => Self::CoverOpen,
147 0b0100_0000 => Self::FeedMediaFail,
148 0b1000_0000 => Self::SystemError,
149 _ => Self::UnknownError((err_1, err_2)),
150 },
151 }
152 }
153
154 /// Check if this represents a "no error" state.
155 ///
156 /// Returns `true` if the printer is reporting no error condition.
157 /// Used to distinguish between actual errors and normal status.
158 ///
159 /// # Returns
160 /// `true` if no error is present, `false` otherwise
161 pub fn is_no_error(&self) -> bool {
162 matches!(self, Self::UnknownError((0, 0)))
163 }
164}