Skip to main content

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}