1#![cfg_attr(not(feature = "std"), no_std)]
25
26#[cfg(not(feature = "std"))]
27extern crate alloc;
28
29#[cfg(not(feature = "std"))]
30use alloc::format;
31use bitvec::prelude::*;
32use core::fmt::{Arguments, Error, Write};
33use core::iter::zip;
34
35use derive_builder::Builder;
36use embedded_hal::delay;
37use num_enum::IntoPrimitive;
38use tinybmp::RawBmp;
39
40const ESC: u8 = 0x1B; const HT: u8 = 0x09; const MARK: u8 = 0x21; const AT: u8 = 0x40; const GS: u8 = 0x1D;
45
46const INIT_SEQUENCE: [u8; 2] = [ESC, AT];
47const TAB_STOP_SEQUENCE: [u8; 2] = [ESC, b'D'];
48const MODE_SEQUENCE: [u8; 2] = [ESC, MARK];
49const MODE_ORDER: [[u8; 2]; 3] = [[GS, 0x42], [ESC, 0x7B], [ESC, 0x45]];
51
52const TAB_WIDTH: u8 = 4;
53pub const PIXEL_COLOR_CUTOFF: u32 = 0x0000FFFF;
56const BAUDRATE: u64 = 19_200;
57const DOT_WIDTH: u32 = 384;
59const BYTE_TIME_MICROS: u64 = ((11 * 1000000) + (BAUDRATE / 2)) / BAUDRATE;
61
62#[derive(Clone, Copy)]
65pub enum Font {
66 FontA,
67 FontB,
68}
69
70impl Default for Font {
71 fn default() -> Self {
72 Self::FontA
73 }
74}
75
76pub enum Justification {
78 Left,
79 Center,
80 Right,
81}
82
83impl Default for Justification {
84 fn default() -> Self {
85 Self::Left
86 }
87}
88
89pub enum Underline {
91 None,
92 Normal,
93 Double,
94}
95
96impl Default for Underline {
97 fn default() -> Self {
98 Self::None
99 }
100}
101
102#[derive(IntoPrimitive)]
112#[repr(u8)]
113pub enum RasterBitImageMode {
114 Normal = 0,
115 DoubleWidth,
116 DoubleHeight,
117 Quadruple,
118}
119
120impl Default for RasterBitImageMode {
121 fn default() -> Self {
122 Self::Normal
123 }
124}
125
126#[derive(IntoPrimitive)]
128#[repr(u8)]
129pub enum CharacterSet {
130 USA = 0,
131 France,
132 Germany,
133 UK,
134 DenmarkI,
135 Sweden,
136 Italy,
137 SpainI,
138 Japan,
139 Norway,
140 DenmarkII,
141 SpainII,
142 LatinAmerica,
143 Korea,
144 SloveniaCroatia,
145 China,
146}
147
148impl Default for CharacterSet {
149 fn default() -> Self {
150 Self::USA
151 }
152}
153
154#[derive(IntoPrimitive)]
156#[repr(u8)]
157pub enum CodeTable {
158 CP437 = 0,
159 Katakana = 1,
160 CP850 = 2,
161 CP860 = 3,
162 CP863 = 4,
163 CP865 = 5,
164 WCP1251 = 6,
165 CP866 = 7,
166 MIK = 8,
167 CP755 = 9,
168 Iran = 10,
169 CP862 = 15,
170 WCP1252 = 16,
171 WCP1253 = 17,
172 CP852 = 18,
173 CP858 = 19,
174 IranII = 20,
175 Latvian = 21,
176 CP864 = 22,
177 Iso8859_1 = 23,
178 CP737 = 24,
179 WCP1257 = 25,
180 Thai = 26,
181 CP720 = 27,
182 CP855 = 28,
183 CP857 = 29,
184 WCP1250 = 30,
185 CP775 = 31,
186 WCP1254 = 32,
187 WCP1255 = 33,
188 WCP1256 = 34,
189 WCP1258 = 35,
190 Iso8859_2 = 36,
191 Iso8859_3 = 37,
192 Iso8859_4 = 38,
193 Iso8859_5 = 39,
194 Iso8859_6 = 40,
195 Iso8859_7 = 41,
196 Iso8859_8 = 42,
197 Iso8859_9 = 43,
198 Iso8859_15 = 44,
199 Thai2 = 45,
200 CP856 = 46,
201 CP874 = 47,
202}
203
204impl Default for CodeTable {
205 fn default() -> Self {
206 Self::CP437
207 }
208}
209
210#[derive(IntoPrimitive)]
214#[repr(u8)]
215pub enum BarCodeSystem {
216 UpcA = 65,
217 UpcE = 66,
218 Ean13 = 67,
219 Ean8 = 68,
220 Code39 = 69,
221 Itf = 70,
222 Codabar = 71,
223 Code93 = 72,
224 Code128 = 73,
225}
226
227impl Default for BarCodeSystem {
228 fn default() -> Self {
229 Self::UpcA
230 }
231}
232
233#[derive(IntoPrimitive)]
237#[repr(u8)]
238pub enum BarCodeSpecialCharacter {
239 Shift = 0x53,
240 CodeA = 0x41,
241 CodeB = 0x42,
242 CodeC = 0x43,
243 Fnc1 = 0x31,
244 Fnc2 = 0x32,
245 Fnc3 = 0x33,
246 Fnc4 = 0x34,
247 CurlyOpen = 0x7B,
249}
250
251#[derive(IntoPrimitive)]
265#[repr(u8)]
266pub enum BarcodeWidth {
267 Width2 = 2,
268 Width3 = 3,
269 Width4 = 4,
270 Width5 = 5,
271 Width6 = 6,
272}
273
274#[derive(Default, Builder, Clone, Copy)]
279#[builder(default, setter(into), no_std)]
280pub struct PrintMode {
281 pub font: Font,
283 pub inverse: bool,
285 pub upside_down: bool,
287 pub emph: bool,
289 pub double_height: bool,
291 pub double_width: bool,
293 pub delete_line: bool,
295}
296
297#[derive(Builder, Clone, Copy)]
301#[builder(default, setter(into), no_std)]
302pub struct PrintSettings {
303 dots: u8,
307 time: u8,
311 interval: u8,
316}
317
318impl Default for PrintSettings {
319 fn default() -> Self {
320 PrintSettings {
321 dots: 11,
322 time: 120,
323 interval: 20,
324 }
325 }
326}
327
328impl Into<u8> for PrintMode {
329 fn into(self) -> u8 {
330 let mut mode = 0;
331
332 match self.font {
333 Font::FontA => mode &= 1 << 0,
334 Font::FontB => mode |= 1 << 0,
335 }
336
337 if self.inverse {
339 mode |= 1 << 1;
340 }
341
342 if self.upside_down {
343 mode |= 1 << 2;
344 }
345
346 if self.emph {
347 mode |= 1 << 3;
348 }
349
350 if self.double_height {
351 mode |= 1 << 4;
352 }
353
354 if self.double_width {
355 mode |= 1 << 5;
356 }
357
358 if self.delete_line {
359 mode |= 1 << 6;
360 }
361 mode
362 }
363}
364
365impl Into<[u8; 3]> for PrintSettings {
366 fn into(self) -> [u8; 3] {
367 [self.dots, self.time, self.interval]
368 }
369}
370
371pub struct Printer<
374 #[cfg(feature = "embedded-io")] Port: embedded_io::Write,
375 #[cfg(feature = "embedded-hal-nb")] Port: embedded_hal_nb::serial::Write,
376 Delay: delay::DelayNs> {
377 pub serial: Port,
378 pub delay: Delay,
379 prev_byte: char,
380 max_column: u8,
381 char_height: u8,
382 char_width: u8,
383 line_spacing: u8,
384 barcode_height: u8,
385 dot_print_time: u32,
386 dot_feed_time: u32,
387 current_column: u8,
388 print_mode: u8,
389}
390
391impl<
392 #[cfg(feature = "embedded-io")] Port: embedded_io::Write,
393 #[cfg(feature = "embedded-hal-nb")] Port: embedded_hal_nb::serial::Write,
394 Delay: delay::DelayNs> Printer<Port, Delay> {
395 pub fn new(serial: Port, delay: Delay) -> Printer<Port, Delay> {
400 Printer {
401 serial,
402 delay,
403 prev_byte: '\n',
404 max_column: 32,
405 char_height: 24,
406 char_width: 12,
407 line_spacing: 6,
408 barcode_height: 162,
409 dot_print_time: 0,
410 dot_feed_time: 0,
411 current_column: 0,
412 print_mode: 0,
413 }
414 }
415
416 fn write_bytes(&mut self, bytes: &[u8]) {
421 for b in bytes.iter() {
422 self.write_byte(*b).unwrap();
423 }
424 }
425
426 fn write_byte(&mut self, byte: u8) -> Result<(), ()> {
430 #[cfg(feature = "embedded-io")]
431 let result = self.serial.write(&[byte]);
432 #[cfg(feature = "embedded-hal-nb")]
433 let result = self.serial.write(byte);
434 self.sleep(BYTE_TIME_MICROS);
435 match result {
436 Ok(_) => Ok(()),
437 Err(_) => Err(()),
438 }
439 }
440
441 pub fn write(&mut self, bytes: &[u8]) {
443 for b in bytes.iter() {
444 self.write_one(*b).unwrap();
445 }
446 }
447
448 fn write_one(&mut self, byte: u8) -> Result<(), ()> {
452 #[cfg(feature = "embedded-io")]
453 let result = self.serial.write(&[byte]);
454 #[cfg(feature = "embedded-hal-nb")]
455 let result = self.serial.write(byte);
456
457 let mut wait_duration: u64 = BYTE_TIME_MICROS;
460
461 if byte == b'\n' || self.current_column == self.max_column {
463 let char_height: u64 = self.char_height.into();
464 let line_spacing: u64 = self.line_spacing.into();
465 let dot_feed_time: u64 = self.dot_feed_time.into();
466 let dot_print_time: u64 = self.dot_print_time.into();
467 if self.prev_byte == '\n' {
468 wait_duration += (char_height + line_spacing) * dot_feed_time;
470 } else {
471 wait_duration += (char_height * dot_print_time) + (line_spacing * dot_feed_time);
473 }
474 self.current_column = 0;
475 self.prev_byte = '\n';
476 } else {
477 if byte == HT {
479 let next_column: u8 = (self.current_column / TAB_WIDTH) + 1;
480 self.current_column += next_column;
481 }
482 self.current_column += 1;
483 self.prev_byte = byte as char;
484 }
485 self.sleep(wait_duration);
486 match result {
487 Ok(_) => Ok(()),
488 Err(_) => Err(()),
489 }
490 }
491
492 fn sleep(&mut self, duration: u64) {
496 self.delay.delay_us(duration as u32);
497 }
498
499 fn update_tabs(&mut self) {
501 self.write_bytes(&TAB_STOP_SEQUENCE);
502 for i in 1..(self.max_column / TAB_WIDTH) {
503 self.write_byte(i * TAB_WIDTH).unwrap();
504 }
505 self.write_byte(0x00).unwrap();
506 }
507
508 pub fn reset(&mut self) {
510 self.write_bytes(&INIT_SEQUENCE);
512
513 self.update_tabs();
515 self.set_print_settings(PrintSettings::default());
516 self.set_character_set(CharacterSet::default());
517 self.set_code_table(CodeTable::default());
518 self.set_barcode_height(self.barcode_height);
519 }
520
521 pub fn wake(&mut self) {
524 self.write_bytes(&[ESC, 0x38, 0x00, 0x00]);
525 self.sleep(75_000);
526 }
527
528 pub fn init(&mut self) {
530 self.sleep(500_000);
532 self.wake();
533 self.write_bytes(&[ESC, 0x38, 0x00, 0x00]);
535 self.reset();
536 self.feed();
537 }
538
539 fn adjust_char_values(&mut self, print_mode: PrintMode) {
542 self.char_height = match print_mode.font {
544 Font::FontA => 24,
545 Font::FontB => 17,
546 };
547 self.char_width = match print_mode.font {
548 Font::FontA => 12,
549 Font::FontB => 9,
550 };
551
552 if print_mode.double_width {
554 self.char_width *= 2;
555 }
556
557 if print_mode.double_height {
559 self.char_height *= 2;
560 }
561
562 self.max_column = (DOT_WIDTH / self.char_width as u32) as u8;
563 }
564
565 pub fn set_print_mode(&mut self, print_mode: PrintMode) {
567 let mode_byte: u8 = print_mode.into();
568 self.print_mode = mode_byte;
569
570 self.write_bytes(&MODE_SEQUENCE);
571 self.write_byte(mode_byte).unwrap();
572
573 let modes = [
575 print_mode.inverse as u8,
576 print_mode.upside_down as u8,
577 print_mode.emph as u8,
578 ];
579 for pair in zip(MODE_ORDER, modes) {
580 let (cmd, n) = pair;
581 self.write_bytes(&cmd);
582 self.write_byte(n).unwrap();
583 }
584
585 self.adjust_char_values(print_mode);
586 }
587
588 pub fn set_print_settings(&mut self, print_settings: PrintSettings) {
590 let settings_bytes: [u8; 3] = print_settings.into();
591 self.write_bytes(&[ESC, 0x37]);
592 self.write_bytes(&settings_bytes);
593 }
594
595 pub fn set_justification(&mut self, justification: Justification) {
596 let justification_byte = match justification {
597 Justification::Left => 0x00,
598 Justification::Center => 0x01,
599 Justification::Right => 0x02,
600 };
601 self.write_bytes(&[ESC, 0x61, justification_byte]);
602 }
603
604 pub fn set_underline(&mut self, mode: Underline) {
605 let underline_byte = match mode {
606 Underline::None => 0x00,
607 Underline::Normal => 0x01,
608 Underline::Double => 0x02,
609 };
610 self.write_bytes(&[ESC, 0x2D, underline_byte]);
611 }
612
613 pub fn set_character_set(&mut self, character_set: CharacterSet) {
614 self.write_bytes(&[ESC, 0x52, character_set.into()]);
615 }
616
617 pub fn set_code_table(&mut self, code_table: CodeTable) {
618 self.write_bytes(&[ESC, 0x74, code_table.into()]);
619 }
620
621 pub fn print_bitmap(&mut self, bmp: RawBmp, mode: RasterBitImageMode) {
640 let x_bits = bmp.header().image_size.width;
641 let x_bytes = (x_bits / 8) as u8 + u8::from(x_bits % 8 != 0);
642 let y_bits = bmp.header().image_size.height;
643
644 self.write_bytes(&[GS, 0x76, 0, mode.into(), x_bytes, 0, y_bits as u8, 0]);
646
647 let mut image_bits = bitvec![u8, Msb0;];
648 for pixel in bmp.pixels() {
649 let column = pixel.position.x as u32;
650
651 image_bits.push(pixel.color < PIXEL_COLOR_CUTOFF);
652
653 if column == ((x_bits - 1) as u32) && x_bits % 8 > 0 {
654 let fill_bits = 8 - (x_bits % 8);
655
656 for _ in 0..fill_bits {
657 image_bits.push(false);
658 }
659 }
660 }
661 for (i, byte) in image_bits.as_raw_slice().iter().enumerate() {
662 self.write_byte(*byte).unwrap();
663 if i as u8 % x_bytes == 0 {
664 self.sleep((self.dot_print_time + self.dot_feed_time) as u64);
665 }
666 }
667 }
668
669 pub fn print_barcode(&mut self, system: BarCodeSystem, text: &str) {
672 self.write_bytes(&[GS, 0x6B, system.into(), text.len() as u8]);
673 for b in text.chars() {
674 self.write_byte(b as u8).unwrap();
675 }
676 self.sleep(self.barcode_height as u64 * (self.dot_print_time + self.dot_feed_time) as u64)
677 }
678
679 pub fn set_barcode_height(&mut self, height: u8) {
681 self.write_bytes(&[GS, 0x68, height]);
682 }
683
684 pub fn set_barcode_left_space(&mut self, space: u8) {
686 self.write_bytes(&[GS, 0x78, space]);
687 }
688
689 pub fn set_barcode_width(&mut self, width: BarcodeWidth) {
691 self.write_bytes(&[GS, 0x77, width.into()]);
692 }
693
694 pub fn set_rotation_mode(&mut self, rotate: bool) {
696 self.write_bytes(&[ESC, 0x56, rotate.into()]);
697 }
698
699 pub fn feed(&mut self) {
701 self.feed_n(1);
702 }
703
704 pub fn feed_n(&mut self, lines: u8) {
706 self.write_bytes(&[ESC, 0x4A, lines]);
707
708 let dot_feed_time: u64 = self.dot_feed_time.into();
709 let char_height: u64 = self.char_height.into();
710 self.sleep(dot_feed_time * char_height);
711 self.prev_byte = '\n';
712 self.current_column = 0;
713 }
714}
715
716impl<
717 #[cfg(feature = "embedded-io")] Port: embedded_io::Write,
718 #[cfg(feature = "embedded-hal-nb")] Port: embedded_hal_nb::serial::Write,
719 Delay: delay::DelayNs> Write for Printer<Port, Delay> {
720 fn write_str(&mut self, s: &str) -> Result<(), Error> {
721 self.write(s.as_bytes());
722 Ok(())
723 }
724
725 fn write_char(&mut self, c: char) -> Result<(), Error> {
726 self.write_one(c as u8).unwrap();
727 Ok(())
728 }
729
730 fn write_fmt(&mut self, args: Arguments<'_>) -> Result<(), Error> {
731 self.write_str(format!("{}", args).as_str())
732 }
733}