Restructure printer code
This commit is contained in:
parent
dc6265f837
commit
ce2f986983
5 changed files with 149 additions and 96 deletions
|
|
@ -1,7 +0,0 @@
|
||||||
pub enum Command {
|
|
||||||
Stop,
|
|
||||||
Test,
|
|
||||||
Rip,
|
|
||||||
Text(String),
|
|
||||||
ChatMessage { username: String, content: String },
|
|
||||||
}
|
|
||||||
104
showbits-thermal-printer/src/drawer.rs
Normal file
104
showbits-thermal-printer/src/drawer.rs
Normal file
|
|
@ -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<Command>,
|
||||||
|
printer: Printer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drawer {
|
||||||
|
pub fn new(rx: mpsc::Receiver<Command>, 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::<String>();
|
||||||
|
|
||||||
|
// let content = content.chars().take(300).collect::<String>();
|
||||||
|
|
||||||
|
// self.printer
|
||||||
|
// .init()?
|
||||||
|
// .reverse(true)?
|
||||||
|
// .write(&username)?
|
||||||
|
// .reverse(false)?
|
||||||
|
// .write(" ")?
|
||||||
|
// .writeln(&content)?
|
||||||
|
// .print()?;
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
mod command;
|
mod drawer;
|
||||||
mod printer;
|
mod printer;
|
||||||
mod server;
|
mod server;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
@ -6,26 +6,39 @@ mod util;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use drawer::Drawer;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use tokio::{runtime::Runtime, sync::mpsc};
|
use tokio::{runtime::Runtime, sync::mpsc};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct Args {
|
struct Args {
|
||||||
path: PathBuf,
|
/// Address the web server will listen at.
|
||||||
addr: String,
|
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<PathBuf>,
|
||||||
|
|
||||||
|
/// Export an image of whatever is printed here.
|
||||||
|
#[arg(long, short)]
|
||||||
|
export: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(3);
|
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()?;
|
let runtime = Runtime::new()?;
|
||||||
runtime.spawn(server::run(tx, args.addr));
|
runtime.spawn(server::run(tx, args.addr));
|
||||||
|
|
||||||
println!("Running");
|
println!("Running");
|
||||||
printer.run()?;
|
drawer.run()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,103 +1,46 @@
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use escpos::{
|
use escpos::{
|
||||||
driver::FileDriver,
|
driver::FileDriver,
|
||||||
printer::Printer as EPrinter,
|
printer::Printer as EPrinter,
|
||||||
utils::{PageCode, Protocol},
|
utils::{PageCode, Protocol},
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc;
|
|
||||||
|
|
||||||
use crate::{command::Command, util};
|
|
||||||
|
|
||||||
pub struct Printer {
|
pub struct Printer {
|
||||||
rx: mpsc::Receiver<Command>,
|
printer: Option<EPrinter<FileDriver>>,
|
||||||
printer: EPrinter<FileDriver>,
|
export_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Printer {
|
impl Printer {
|
||||||
pub fn new(rx: mpsc::Receiver<Command>, path: &Path) -> anyhow::Result<Self> {
|
/// Experimentation has determined that the printer uses PC437 and the page
|
||||||
let driver = FileDriver::open(path)?;
|
/// 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
|
pub fn new(
|
||||||
// page code can't be changed.
|
printer_path: Option<PathBuf>,
|
||||||
// https://en.wikipedia.org/wiki/Code_page_437
|
export_path: Option<PathBuf>,
|
||||||
// https://www.epson-biz.com/modules/ref_charcode_en/index.php?content_id=10
|
) -> anyhow::Result<Self> {
|
||||||
let printer = EPrinter::new(driver, Protocol::default(), Some(PageCode::PC437));
|
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<()> {
|
pub fn rip(&mut self) -> anyhow::Result<()> {
|
||||||
while let Some(command) = self.rx.blocking_recv() {
|
if let Some(printer) = &mut self.printer {
|
||||||
match command {
|
printer.init()?.feeds(4)?.print()?;
|
||||||
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)?
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
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::<String>();
|
|
||||||
|
|
||||||
let content = content.chars().take(300).collect::<String>();
|
|
||||||
|
|
||||||
self.printer
|
|
||||||
.init()?
|
|
||||||
.reverse(true)?
|
|
||||||
.write(&username)?
|
|
||||||
.reverse(false)?
|
|
||||||
.write(" ")?
|
|
||||||
.writeln(&content)?
|
|
||||||
.print()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use axum::{extract::State, routing::post, Form, Router};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tokio::{net::TcpListener, sync::mpsc};
|
use tokio::{net::TcpListener, sync::mpsc};
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::drawer::Command;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Server {
|
struct Server {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue