From ce2f9869830ae25c22639ed87efe97f387445353 Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 8 Mar 2024 11:50:25 +0100 Subject: [PATCH] Restructure printer code --- showbits-thermal-printer/src/command.rs | 7 -- showbits-thermal-printer/src/drawer.rs | 104 ++++++++++++++++++++++ showbits-thermal-printer/src/main.rs | 21 ++++- showbits-thermal-printer/src/printer.rs | 111 ++++++------------------ showbits-thermal-printer/src/server.rs | 2 +- 5 files changed, 149 insertions(+), 96 deletions(-) delete mode 100644 showbits-thermal-printer/src/command.rs create mode 100644 showbits-thermal-printer/src/drawer.rs diff --git a/showbits-thermal-printer/src/command.rs b/showbits-thermal-printer/src/command.rs deleted file mode 100644 index 2f27e57..0000000 --- a/showbits-thermal-printer/src/command.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub enum Command { - Stop, - Test, - Rip, - Text(String), - ChatMessage { username: String, content: String }, -} diff --git a/showbits-thermal-printer/src/drawer.rs b/showbits-thermal-printer/src/drawer.rs new file mode 100644 index 0000000..bc9ece8 --- /dev/null +++ b/showbits-thermal-printer/src/drawer.rs @@ -0,0 +1,104 @@ +use tokio::sync::mpsc; + +use crate::printer::Printer; + +pub enum Command { + Stop, + Rip, + Test, + Text(String), + ChatMessage { username: String, content: String }, +} + +pub struct Drawer { + rx: mpsc::Receiver, + printer: Printer, +} + +impl Drawer { + pub fn new(rx: mpsc::Receiver, printer: Printer) -> Self { + Self { rx, printer } + } + + pub fn run(&mut self) -> anyhow::Result<()> { + while let Some(command) = self.rx.blocking_recv() { + if matches!(command, Command::Stop) { + break; + }; + + self.on_command(command)?; + } + Ok(()) + } + + fn on_command(&mut self, command: Command) -> anyhow::Result<()> { + match command { + Command::Stop => {} // Already handled one level above + Command::Rip => self.printer.rip()?, + Command::Test => todo!(), + Command::Text(_) => todo!(), + Command::ChatMessage { username, content } => todo!(), + } + Ok(()) + } + + // fn on_test(&mut self) -> anyhow::Result<()> { + // self.printer.init()?; + + // let x = 48; // bytes + // let y = 48; // dots + + // let m = 0; + // let x_l = x as u8; + // let x_h = (x >> 8) as u8; + // let y_l = y as u8; + // let y_h = (y >> 8) as u8; + // let mut command = vec![0x1D, b'v', b'0', m, x_l, x_h, y_l, y_h]; + // for _y in 0..y { + // for _x in 0..x { + // // command.push((x + y) as u8); + // command.push(0b0000_0011); + // } + // } + // self.printer.custom(&command)?; + + // self.printer.print()?; + + // Ok(()) + // } + + // fn on_rip(&mut self) -> anyhow::Result<()> { + // self.printer.init()?.feeds(6)?.print()?; + // Ok(()) + // } + + // fn on_text(&mut self, text: String) -> anyhow::Result<()> { + // let text = util::sanitize(&text); + // self.printer.init()?.write(&text)?.print()?; + // Ok(()) + // } + + // fn on_chat_message(&mut self, username: String, content: String) -> anyhow::Result<()> { + // let username = util::sanitize(&username); + // let content = util::sanitize(&content); + + // let username = username + // .chars() + // .map(|c| if c.is_ascii_whitespace() { '_' } else { c }) + // .take(16) + // .collect::(); + + // let content = content.chars().take(300).collect::(); + + // self.printer + // .init()? + // .reverse(true)? + // .write(&username)? + // .reverse(false)? + // .write(" ")? + // .writeln(&content)? + // .print()?; + + // Ok(()) + // } +} diff --git a/showbits-thermal-printer/src/main.rs b/showbits-thermal-printer/src/main.rs index 1dd91c1..0e5f164 100644 --- a/showbits-thermal-printer/src/main.rs +++ b/showbits-thermal-printer/src/main.rs @@ -1,4 +1,4 @@ -mod command; +mod drawer; mod printer; mod server; mod util; @@ -6,26 +6,39 @@ mod util; use std::path::PathBuf; use clap::Parser; +use drawer::Drawer; use printer::Printer; use tokio::{runtime::Runtime, sync::mpsc}; #[derive(Parser)] struct Args { - path: PathBuf, + /// Address the web server will listen at. addr: String, + + /// Path to the printer's USB device file. + /// + /// Usually, this is located at `/dev/usb/lp0` or a similar location. + #[arg(long, short)] + printer: Option, + + /// Export an image of whatever is printed here. + #[arg(long, short)] + export: Option, } fn main() -> anyhow::Result<()> { let args = Args::parse(); let (tx, rx) = mpsc::channel(3); - let mut printer = Printer::new(rx, &args.path)?; + + let printer = Printer::new(args.printer, args.export)?; + let mut drawer = Drawer::new(rx, printer); let runtime = Runtime::new()?; runtime.spawn(server::run(tx, args.addr)); println!("Running"); - printer.run()?; + drawer.run()?; Ok(()) } diff --git a/showbits-thermal-printer/src/printer.rs b/showbits-thermal-printer/src/printer.rs index bebf516..f6bdf12 100644 --- a/showbits-thermal-printer/src/printer.rs +++ b/showbits-thermal-printer/src/printer.rs @@ -1,103 +1,46 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use escpos::{ driver::FileDriver, printer::Printer as EPrinter, utils::{PageCode, Protocol}, }; -use tokio::sync::mpsc; - -use crate::{command::Command, util}; pub struct Printer { - rx: mpsc::Receiver, - printer: EPrinter, + printer: Option>, + export_path: Option, } impl Printer { - pub fn new(rx: mpsc::Receiver, path: &Path) -> anyhow::Result { - let driver = FileDriver::open(path)?; + /// Experimentation has determined that the printer uses PC437 and the page + /// code can't be changed. + /// + /// https://en.wikipedia.org/wiki/Code_page_437 + /// https://www.epson-biz.com/modules/ref_charcode_en/index.php?content_id=10 + const PAGE_CODE: PageCode = PageCode::PC437; - // Experimentation has determined that the printer uses PC437 and the - // page code can't be changed. - // https://en.wikipedia.org/wiki/Code_page_437 - // https://www.epson-biz.com/modules/ref_charcode_en/index.php?content_id=10 - let printer = EPrinter::new(driver, Protocol::default(), Some(PageCode::PC437)); + pub fn new( + printer_path: Option, + export_path: Option, + ) -> anyhow::Result { + let printer = if let Some(path) = printer_path { + let driver = FileDriver::open(&path)?; + let printer = EPrinter::new(driver, Protocol::default(), Some(Self::PAGE_CODE)); + Some(printer) + } else { + None + }; - Ok(Self { rx, printer }) + Ok(Self { + printer, + export_path, + }) } - pub fn run(&mut self) -> anyhow::Result<()> { - while let Some(command) = self.rx.blocking_recv() { - match command { - Command::Stop => break, - Command::Test => self.on_test()?, - Command::Rip => self.on_rip()?, - Command::Text(text) => self.on_text(text)?, - Command::ChatMessage { username, content } => { - self.on_chat_message(username, content)? - } - } + pub fn rip(&mut self) -> anyhow::Result<()> { + if let Some(printer) = &mut self.printer { + printer.init()?.feeds(4)?.print()?; } - Ok(()) - } - - fn on_test(&mut self) -> anyhow::Result<()> { - self.printer.init()?; - - let x = 48; // bytes - let y = 48; // dots - - let m = 0; - let x_l = x as u8; - let x_h = (x >> 8) as u8; - let y_l = y as u8; - let y_h = (y >> 8) as u8; - let mut command = vec![0x1D, b'v', b'0', m, x_l, x_h, y_l, y_h]; - for _y in 0..y { - for _x in 0..x { - // command.push((x + y) as u8); - command.push(0b0000_0011); - } - } - self.printer.custom(&command)?; - - self.printer.print()?; - - Ok(()) - } - - fn on_rip(&mut self) -> anyhow::Result<()> { - self.printer.init()?.feeds(6)?.print()?; - Ok(()) - } - - fn on_text(&mut self, text: String) -> anyhow::Result<()> { - let text = util::sanitize(&text); - self.printer.init()?.write(&text)?.print()?; - Ok(()) - } - - fn on_chat_message(&mut self, username: String, content: String) -> anyhow::Result<()> { - let username = util::sanitize(&username); - let content = util::sanitize(&content); - - let username = username - .chars() - .map(|c| if c.is_ascii_whitespace() { '_' } else { c }) - .take(16) - .collect::(); - - let content = content.chars().take(300).collect::(); - - self.printer - .init()? - .reverse(true)? - .write(&username)? - .reverse(false)? - .write(" ")? - .writeln(&content)? - .print()?; Ok(()) } diff --git a/showbits-thermal-printer/src/server.rs b/showbits-thermal-printer/src/server.rs index d4f6cfc..a4b5816 100644 --- a/showbits-thermal-printer/src/server.rs +++ b/showbits-thermal-printer/src/server.rs @@ -2,7 +2,7 @@ use axum::{extract::State, routing::post, Form, Router}; use serde::Deserialize; use tokio::{net::TcpListener, sync::mpsc}; -use crate::command::Command; +use crate::drawer::Command; #[derive(Clone)] struct Server {