ptouch/
device.rs

1//! PTouch printer device definitions
2// Rust PTouch Driver / Utility
3//
4// https://github.com/ryankurte/rust-ptouch
5// Copyright 2021 Ryan Kurte
6
7use crate::Error;
8
9use bitflags::bitflags;
10
11#[cfg(feature = "strum")]
12use strum_macros::{Display, EnumString, EnumVariantNames};
13
14bitflags::bitflags! {
15    /// First error byte
16    pub struct Error1: u8 {
17        const NO_MEDIA = 0x01;
18        const CUTTER_JAM = 0x04;
19        const WEAK_BATT = 0x08;
20        const HIGH_VOLT = 0x40;
21    }
22}
23
24bitflags::bitflags! {
25    /// Second device error type
26    pub struct Error2: u8 {
27        const WRONG_MEDIA = 0x01;
28        const COVER_OPEN = 0x10;
29        const OVERHEAT = 0x20;
30    }
31}
32
33/// PTouch device type.
34/// Note that only the p710bt has been tested
35#[derive(Copy, Clone, PartialEq, Debug)]
36#[cfg_attr(feature = "strum", derive(Display, EnumString, EnumVariantNames))]
37#[cfg_attr(feature = "strum", strum(serialize_all = "snake_case"))]
38pub enum PTouchDevice {
39    #[cfg_attr(feature = "strum", strum(serialize = "pt-e550w"))]
40    PtE550W = 0x2060,
41    #[cfg_attr(feature = "strum", strum(serialize = "pt-p750w"))]
42    PtP750W = 0x2062,
43    #[cfg_attr(feature = "strum", strum(serialize = "pt-p710bt"))]
44    PtP710Bt = 0x20af,
45}
46
47
48/// Media width encoding for Status message
49#[derive(Copy, Clone, PartialEq, Debug)]
50#[cfg_attr(feature = "strum", derive(Display, EnumString, EnumVariantNames))]
51#[cfg_attr(feature = "strum", strum(serialize_all = "snake_case"))]
52pub enum Media {
53    /// 6mm TZe Tape
54    Tze6mm = 257,
55    /// 9mm TZe Tape
56    Tze9mm = 258,
57    /// 12mm TZe Tape
58    Tze12mm = 259,
59    /// 18mm TZe Tape
60    Tze18mm = 260,
61    /// 24mm TZe Tape
62    Tze24mm = 261,
63
64    /// 6mm HeatShrink Tube
65    Hs6mm = 415,
66    /// 9mm HeatShrink Tube
67    Hs9mm = 416,
68    /// 12mm HeatShrink Tube
69    Hs12mm = 417,
70    /// 18mm HeatShrink Tube
71    Hs18mm = 418,
72    /// 24mm HeatShrink Tube
73    Hs24mm = 419,
74
75    /// Unknown media width
76    Unknown = 0xFFFF,
77}
78
79/// Generate a MediaWidth from provided MediaKind and u8 width
80impl From<(MediaKind, u8)> for Media {
81    fn from(v: (MediaKind, u8)) -> Self {
82        use MediaKind::*;
83        use Media::*;
84
85        match v {
86            (LaminatedTape, 6) | (NonLaminatedTape, 6) | (FlexibleTape, 6) => Tze6mm,
87            (LaminatedTape, 9) | (NonLaminatedTape, 9) | (FlexibleTape, 9) => Tze9mm,
88            (LaminatedTape, 12) | (NonLaminatedTape, 12) | (FlexibleTape, 12) => Tze12mm,
89            (LaminatedTape, 18) | (NonLaminatedTape, 18) | (FlexibleTape, 18) => Tze18mm,
90            (LaminatedTape, 24) | (NonLaminatedTape, 24) | (FlexibleTape, 24) => Tze24mm,
91            (HeatShrinkTube, 6) => Hs6mm,
92            (HeatShrinkTube, 9) => Hs9mm,
93            (HeatShrinkTube, 12)  => Hs12mm,
94            (HeatShrinkTube, 18)  => Hs18mm,
95            (HeatShrinkTube, 24)  => Hs24mm,
96            _ => Unknown,
97        }
98    }
99}
100
101impl Media {
102    /// Fetch media print area (left margin, print area, right margin)
103    pub fn area(&self) -> (usize, usize, usize) {
104        use Media::*;
105
106        match self {
107            Tze6mm => (52, 32, 52),
108            Tze9mm => (39, 50, 39),
109            Tze12mm => (29, 70, 29),
110            Tze18mm => (8, 112, 8),
111            Tze24mm => (0, 128, 0),
112
113            Hs6mm => (50, 28, 50),
114            Hs9mm => (40, 48, 40),
115            Hs12mm => (31, 66, 31),
116            Hs18mm => (11, 106, 11),
117            Hs24mm => (0, 128, 0),
118
119            Unknown => (0, 0, 0)
120        }
121    }
122
123    /// Check if a media type is _tape_
124    pub fn is_tape(&self) -> bool {
125        use Media::*;
126
127        match self {
128            Tze6mm | Tze9mm | Tze12mm | Tze18mm | Tze24mm => true,
129            _ => false,
130        }
131    }
132
133    /// Fetch the (approximate) media width in mm
134    pub fn width(&self) -> usize {
135        use Media::*;
136
137        match self {
138            Tze6mm => 6,
139            Tze9mm => 9,
140            Tze12mm => 12,
141            Tze18mm => 18,
142            Tze24mm => 24,
143            Hs6mm => 6,
144            Hs9mm => 9,
145            Hs12mm => 12,
146            Hs18mm => 18,
147            Hs24mm => 24,
148            _ => panic!("Unknown media width"),
149        }
150    }
151}
152
153/// Kind of media loaded in printer
154#[derive(Copy, Clone, PartialEq, Debug)]
155pub enum MediaKind {
156    None = 0x00,
157    LaminatedTape = 0x01,
158    NonLaminatedTape = 0x03,
159    HeatShrinkTube = 0x11,
160    FlexibleTape = 0x14,
161    IncompatibleTape = 0xFF,
162}
163
164/// Device operating phase
165#[derive(Copy, Clone, PartialEq, Debug)]
166pub enum Phase {
167    Editing,
168    Printing,
169    Unknown,
170}
171
172impl From<u8> for Phase {
173    fn from(v: u8) -> Self {
174        use Phase::*;
175
176        match v {
177            0 => Editing,
178            1 => Printing,
179            _ => Unknown
180        }
181    }
182}
183
184/// Create media kind from status values
185impl From<u8> for MediaKind {
186    fn from(v: u8) -> Self {
187        match v {
188           0x00 => MediaKind::None,
189           0x01 => MediaKind::LaminatedTape,
190           0x03 => MediaKind::NonLaminatedTape,
191           0x11 => MediaKind::HeatShrinkTube,
192           0x14 => MediaKind::FlexibleTape,
193           0xFF => MediaKind::IncompatibleTape,
194           _ => MediaKind::IncompatibleTape,
195       }
196    }
197}
198
199/// Device state enumeration
200#[derive(Copy, Clone, PartialEq, Debug)]
201pub enum DeviceStatus {
202    Reply = 0x00,
203    Completed = 0x01,
204    Error = 0x02,
205    ExitIF = 0x03,
206    TurnedOff = 0x04,
207    Notification = 0x05,
208    PhaseChange = 0x06,
209
210    Unknown = 0xFF,
211}
212
213impl From<u8> for DeviceStatus {
214    fn from(v: u8) -> Self {
215        use DeviceStatus::*;
216
217        match v {
218            0x00 => Reply,
219            0x01 => Completed,
220            0x02 => Error,
221            0x03 => ExitIF,
222            0x04 => TurnedOff,
223            0x05 => Notification,
224            0x06 => PhaseChange,
225            _ => Unknown,
226       }
227    }
228}
229
230/// Device mode for set_mode command
231#[derive(Copy, Clone, PartialEq, Debug)]
232pub enum Mode {
233    /// Not sure tbqh?
234    EscP = 0x00,
235    /// Raster mode, what this driver uses
236    Raster = 0x01,
237    /// Note PTouchTemplate is not available on most devices
238    PTouchTemplate = 0x03,
239}
240
241bitflags! {
242    /// Various mode flags
243    pub struct VariousMode: u8 {
244        const AUTO_CUT = (1 << 6);
245        const MIRROR = (1 << 7);
246    }
247}
248
249bitflags! {
250    /// Advanced mode flags
251    pub struct AdvancedMode: u8 {
252        const HALF_CUT = (1 << 2);
253        const NO_CHAIN = (1 << 3);
254        const SPECIAL_TAPE = (1 << 4);
255        const HIGH_RES = (1 << 6);
256        const NO_BUFF_CLEAR = (1 << 7);
257    }
258}
259
260/// Notification enumerations
261#[derive(Copy, Clone, PartialEq, Debug)]
262pub enum Notification {
263    NotAvailable = 0x00,
264    CoverOpen = 0x01,
265    CoverClosed = 0x02,
266}
267
268/// Tape colour enumerations
269#[derive(Copy, Clone, PartialEq, Debug)]
270pub enum TapeColour {
271    White = 0x01,
272    Other = 0x02,
273    ClearBlack = 0x03,
274    Red = 0x04,
275    Blue = 0x05,
276    Black = 0x08,
277    ClearWhite = 0x09,
278    MatteWhite = 0x20,
279    MatteClear = 0x21,
280    MatteSilver = 0x22,
281    SatinGold = 0x23,
282    SatinSilver = 0x24,
283    BlueD = 0x30,
284    RedD = 0x31,
285    FluroOrange=0x40,
286    FluroYellow=0x41,
287    BerryPinkS = 0x50,
288    LightGrayS = 0x51,
289    LimeGreenS = 0x52,
290    YellowF = 0x60,
291    PinkF = 0x61,
292    BlueF = 0x62,
293    WhiteHst = 0x70,
294    WhiteFlexId = 0x90,
295    YellowFlexId = 0x91,
296    Cleaning = 0xF0,
297    Stencil = 0xF1,
298    Incompatible = 0xFF,
299}
300
301impl From<u8> for TapeColour {
302    fn from(v: u8) -> TapeColour {
303        use TapeColour::*;
304
305        match v {
306            0x01 => White,
307            0x02 => Other,
308            0x03 => ClearBlack,
309            0x04 => Red,
310            0x05 => Blue,
311            0x08 => Black,
312            0x09 => ClearWhite,
313            0x20 => MatteWhite,
314            0x21 => MatteClear,
315            0x22 => MatteSilver,
316            0x23 => SatinGold,
317            0x24 => SatinSilver,
318            0x30 => BlueD,
319            0x31 => RedD,
320            0x40 => FluroOrange,
321            0x41 => FluroYellow,
322            0x50 => BerryPinkS,
323            0x51 => LightGrayS,
324            0x52 => LimeGreenS,
325            0x60 => YellowF,
326            0x61 => PinkF,
327            0x62 => BlueF,
328            0x70 => WhiteHst,
329            0x90 => WhiteFlexId,
330            0x91 => YellowFlexId,
331            0xF0 => Cleaning,
332            0xF1 => Stencil,
333            0xFF | _ => Incompatible,
334        }
335    }
336}
337
338/// Text colour enumerations
339#[derive(Copy, Clone, PartialEq, Debug)]
340pub enum TextColour {
341    White = 0x01,
342    Red = 0x04,
343    Blue = 0x05,
344    Black = 0x08,
345    Gold = 0x0A,
346    BlueF = 0x62,
347    Cleaning = 0xf0,
348    Stencil = 0xF1,
349    Other = 0x02,
350    Incompatible = 0xFF,
351}
352
353impl From<u8> for TextColour {
354    fn from(v: u8) -> TextColour {
355        use TextColour::*;
356        
357        match v {
358            0x01 => White,
359            0x04 => Red,
360            0x05 => Blue,
361            0x08 => Black,
362            0x0A => Gold,
363            0x62 => BlueF,
364            0xf0 => Cleaning,
365            0xF1 => Stencil,
366            0x02 => Other,
367            0xFF | _=> Incompatible,
368        }
369    }
370}
371
372/// Device status message
373#[derive(Clone, PartialEq, Debug)]
374pub struct Status {
375    pub model: u8,
376
377    pub error1: Error1,
378    pub error2: Error2,
379
380    pub media_width: u8,
381    pub media_kind: MediaKind,
382
383    pub status_type: DeviceStatus,
384    pub phase: Phase,
385
386    pub tape_colour: TapeColour,
387    pub text_colour: TextColour,
388}
389
390impl Status {
391    // This function is gonna be called if the --no-status-fetch flag is enabled.
392    // It returns a default status, which is assumed to be correct to then print.
393    pub fn new(media: &Media) -> Result<Status, Error> {
394        Ok(Status {
395            model: 0,                                   // The model is not that important, and also the manual only shows the model ID of E550W and E750W
396            error1: Error1::empty(),                    // Assuming there's no error
397            error2: Error2::empty(),                    // Assuming there's no error
398            media_width: media.width() as u8,           // Width given by user in command
399            media_kind: match media.is_tape() {         // Not sure if this is really important, but this is an easy way to detect if it is tape (can't know if laminated or not) or not
400                true => MediaKind::LaminatedTape,
401                false => MediaKind::HeatShrinkTube
402            },
403            status_type: DeviceStatus::Completed,       // Assuming the printer is ready to print
404            phase: Phase::Editing,                      // Assuming the printer is not printing
405            tape_colour: TapeColour::White,             // By default, assuming the tape is white...
406            text_colour: TextColour::Black,             // ...and the text colour is black. Would maybe be good to let the user change it in the command
407        })
408    }
409}
410
411impl From<[u8; 32]> for Status {
412
413    fn from(r: [u8; 32]) -> Self {
414        Self {
415            model: r[0],
416            error1: Error1::from_bits_truncate(r[8]),
417            error2: Error2::from_bits_truncate(r[9]),
418            media_width: r[10],
419            media_kind: MediaKind::from(r[11]),
420
421            status_type: DeviceStatus::from(r[18]),
422            phase: Phase::from(r[20]),
423            tape_colour: TapeColour::from(r[24]),
424            text_colour: TextColour::from(r[25]),
425        }
426    }
427}
428
429/// Print information command
430#[derive(Clone, PartialEq, Debug)]
431pub struct PrintInfo {
432    /// Media kind
433    pub kind: Option<MediaKind>,
434    /// Tape width in mm
435    pub width: Option<u8>,
436    /// Tape length, always set to 0
437    pub length: Option<u8>,
438    /// Raster number (??)
439    pub raster_no: u32,
440    /// Enable print recovery
441    pub recover: bool,
442}
443
444impl Default for PrintInfo {
445    fn default() -> Self {
446        Self {
447            kind: None,
448            width: None,
449            length: Some(0),
450            raster_no: 0,
451            recover: true,
452        }
453    }
454}
455
456/// Compression mode enumeration
457#[derive(Copy, Clone, PartialEq, Debug)]
458pub enum CompressionMode {
459    None = 0x00,
460    Tiff = 0x02,
461}