hardless_http_dialects/lib.rs
1#![doc = include_str!("../README.md")]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4
5/// This crate's README, which holds the request and response reference for both dialects.
6/// The MCP server's `hardless://docs/http-dialects` resource and the docs site read it, so
7/// the reference has one source.
8pub const REFERENCE: &str = include_str!("../README.md");
9
10pub mod epos;
11mod escpos;
12pub mod webprnt;
13mod xml;
14
15use std::fmt;
16
17/// Largest request document accepted, in bytes. Real receipts with images stay far below it.
18pub const MAX_DOCUMENT_BYTES: usize = 8 * 1024 * 1024;
19
20/// A print request translated to ESC/POS (FR-31). Feeding [`PrintRequest::escpos`] to an
21/// ESC/POS printer gives the same command AST as printing over Web Serial.
22#[derive(Clone, Debug, Default, PartialEq, Eq)]
23pub struct PrintRequest {
24 /// The equivalent ESC/POS bytes. They start with `ESC @`: each request starts from the
25 /// printer's power-on settings.
26 pub escpos: Vec<u8>,
27 /// Parts of the request the emulator does not reproduce (a buzzer, page mode, ...), for
28 /// the event log.
29 pub warnings: Vec<String>,
30}
31
32/// What a request document could not be understood for. Both dialects answer it as a
33/// schema error.
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct DialectError(String);
36
37impl DialectError {
38 pub(crate) fn new(message: impl Into<String>) -> Self {
39 Self(message.into())
40 }
41}
42
43impl fmt::Display for DialectError {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.write_str(&self.0)
46 }
47}
48
49impl std::error::Error for DialectError {}
50
51/// The printer's condition after a print, as both dialects report it.
52///
53/// Read it back from the printer's own `DLE EOT` replies with
54/// [`PrinterStatus::from_dle_eot`], so faults and the drawer setting count exactly as they do
55/// for Web Serial.
56///
57/// ```
58/// use hardless_http_dialects::PrinterStatus;
59/// // DLE EOT 1, 2 and 4 replies of a printer that is out of paper.
60/// let status = PrinterStatus::from_dle_eot(0x1A, 0x32, 0x7E);
61/// assert!(status.paper_end && status.paper_near_end && !status.online);
62/// ```
63#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
64pub struct PrinterStatus {
65 /// The printer is online (not stopped by paper end or an open cover).
66 pub online: bool,
67 /// The cover is open.
68 pub cover_open: bool,
69 /// The roll is empty.
70 pub paper_end: bool,
71 /// The roll is nearly empty.
72 pub paper_near_end: bool,
73 /// The drawer-kick connector's pin 3 (the drawer sensor) reads high.
74 pub drawer_pin3_high: bool,
75}
76
77impl PrinterStatus {
78 /// From the replies to `DLE EOT 1` (printer), `DLE EOT 2` (offline cause) and `DLE EOT 4`
79 /// (paper sensor), as defined in the ESC/POS command reference.
80 pub fn from_dle_eot(printer: u8, offline_cause: u8, paper: u8) -> Self {
81 Self {
82 online: printer & 0x08 == 0,
83 drawer_pin3_high: printer & 0x04 != 0,
84 cover_open: offline_cause & 0x04 != 0,
85 paper_end: paper & 0x60 != 0,
86 paper_near_end: paper & 0x0C != 0,
87 }
88 }
89}
90
91/// How a print request turned out.
92#[derive(Clone, Debug, PartialEq, Eq)]
93pub enum Outcome {
94 /// Printed.
95 Printed,
96 /// Not printed: the roll is empty.
97 PaperEnd,
98 /// Not printed: the cover is open.
99 CoverOpen,
100 /// Not printed in time: the request's timeout passed.
101 Timeout,
102 /// The request document could not be understood.
103 BadDocument(String),
104 /// No printer with the requested device ID.
105 DeviceNotFound,
106}
107
108impl Outcome {
109 /// The outcome of a print from the printer's status afterwards: paper end and an open
110 /// cover stop a printer, so the print did not happen.
111 pub fn after_print(status: &PrinterStatus) -> Self {
112 if status.paper_end {
113 Outcome::PaperEnd
114 } else if status.cover_open {
115 Outcome::CoverOpen
116 } else {
117 Outcome::Printed
118 }
119 }
120
121 /// Whether the document printed.
122 pub fn printed(&self) -> bool {
123 matches!(self, Outcome::Printed)
124 }
125}