This commit is contained in:
Kezi 2024-08-21 09:31:43 +02:00 committed by GitHub
commit 71b5089739
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1320 additions and 487 deletions

1696
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,11 +6,11 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
btleplug = "0.8" btleplug = "0.11"
uuid = "0.8" uuid = "1.10"
futures = "0.3" futures = "0.3"
tokio = {version = "1.10", features = ["rt", "macros", "rt-multi-thread"] } tokio = {version = "1.10", features = ["rt", "macros", "rt-multi-thread"] }
crc = { git = "https://github.com/mrhooray/crc-rs.git" } crc = { git = "https://github.com/mrhooray/crc-rs.git" }
dither = "=1.3.7" # last version without nightly requirement dither = "=1.3.7" # last version without nightly requirement
image = "0.23" image = "0.25"
clap = "3.0.0-beta.4" clap = { version = "4.5", features = ["derive"] }

View file

@ -2,20 +2,19 @@ use btleplug::platform::Manager;
use catprint::*; use catprint::*;
use std::error::Error; use std::error::Error;
use clap::{crate_authors, crate_version, AppSettings, ArgEnum, Clap}; use clap::{Parser, ValueEnum};
#[derive(Clap)] #[derive(Parser, Debug)]
#[clap(version = crate_version!(), author = crate_authors!())] #[command(author, version, about, long_about = None)]
#[clap(setting = AppSettings::ColoredHelp)]
struct Opts { struct Opts {
/// Set the device name of your printer. /// Set the device name of your printer.
#[clap(short, long, default_value = "GB02")] #[arg(short, long, default_value = "GB02")]
device_name: String, device_name: String,
#[clap(subcommand)] #[command(subcommand)]
subcmd: SubCommand, subcmd: SubCommand,
} }
#[derive(Clap)] #[derive(Parser, Debug)]
enum SubCommand { enum SubCommand {
/// Move the paper without printing /// Move the paper without printing
Feed(Feed), Feed(Feed),
@ -24,7 +23,7 @@ enum SubCommand {
Print(Print), Print(Print),
} }
#[derive(Clap)] #[derive(Parser, Debug)]
struct Feed { struct Feed {
/// Print debug info /// Print debug info
#[clap(short, long)] #[clap(short, long)]
@ -33,13 +32,13 @@ struct Feed {
length: u8, length: u8,
} }
#[derive(Clap)] #[derive(Parser, Debug)]
struct Print { struct Print {
/// The path to the image you want to print out /// The path to the image you want to print out
input_image: String, input_image: String,
/// The ditherer supposed to be used. none is good for text and vector graphics /// The ditherer supposed to be used. none is good for text and vector graphics
#[clap(arg_enum, short, long, default_value = "k-mean")] #[clap(value_enum, short, long, default_value = "k-mean")]
ditherer: Ditherers, ditherer: Ditherers,
/// Rotate picture by 90 degrees /// Rotate picture by 90 degrees
@ -51,7 +50,7 @@ struct Print {
no_compress: bool, no_compress: bool,
} }
#[derive(ArgEnum)] #[derive(ValueEnum, Debug, Clone)]
enum Ditherers { enum Ditherers {
None, None,
KMean, KMean,

View file

@ -1,6 +1,5 @@
use btleplug::api::{Central, Manager as _, Peripheral}; use btleplug::api::{Central, Manager as _, Peripheral, ScanFilter, WriteType};
use btleplug::platform::Manager; use btleplug::platform::Manager;
use std::collections::VecDeque;
use std::error::Error; use std::error::Error;
use std::time::Duration; use std::time::Duration;
use tokio::time; use tokio::time;
@ -12,7 +11,8 @@ const TX_CHARACTERISTIC_UUID: Uuid = Uuid::from_u128(0x0000ae01_0000_1000_8000_0
pub struct Device { pub struct Device {
peripheral: btleplug::platform::Peripheral, peripheral: btleplug::platform::Peripheral,
supports_compression: bool, supports_compression: bool,
tx_buffer: VecDeque<u8>, tx_buffer: Vec<u8>,
tx_characteristic: btleplug::api::Characteristic,
} }
impl Device { impl Device {
@ -26,7 +26,7 @@ impl Device {
for adapter in adapter_list.iter() { for adapter in adapter_list.iter() {
println!("Starting scan..."); println!("Starting scan...");
adapter adapter
.start_scan() .start_scan(ScanFilter::default())
.await .await
.expect("Can't scan BLE adapter for connected devices..."); .expect("Can't scan BLE adapter for connected devices...");
time::sleep(Duration::from_secs(2)).await; time::sleep(Duration::from_secs(2)).await;
@ -41,17 +41,27 @@ impl Device {
if !peripheral.is_connected().await? { if !peripheral.is_connected().await? {
peripheral.connect().await?; peripheral.connect().await?;
} }
let _ = peripheral.discover_characteristics().await?;
let supports_compression = match name { println!("Connected to {}", name);
"MX10" => false, println!("Discovering services...");
_ => true, peripheral.discover_services().await?;
};
let supports_compression = name != "MX10";
let characteristics = peripheral.characteristics();
println!("Found {} characteristics", characteristics.len());
let tx_characteristic = characteristics
.iter()
.find(|c| c.uuid == TX_CHARACTERISTIC_UUID)
.expect("Could not find TX characteristic");
device_result = Ok(Device { device_result = Ok(Device {
peripheral, peripheral,
tx_buffer: VecDeque::new(), tx_buffer: Vec::new(),
supports_compression, supports_compression,
tx_characteristic: tx_characteristic.clone(),
}); });
break; break;
} }
@ -60,6 +70,7 @@ impl Device {
} }
} }
println!("Scan complete");
device_result device_result
} }
@ -74,46 +85,25 @@ impl Device {
} }
pub async fn flush(&mut self) -> Result<(), Box<dyn Error>> { pub async fn flush(&mut self) -> Result<(), Box<dyn Error>> {
const MTU_SIZE: usize = 20; let chunks = self.tx_buffer.chunks(20);
while !self.tx_buffer.is_empty() { let write_type = if chunks.len() > 1 {
let mut buf = Vec::with_capacity(MTU_SIZE); WriteType::WithoutResponse
for _ in 0..MTU_SIZE { } else {
if let Some(byte) = self.tx_buffer.pop_front() { WriteType::WithResponse
buf.push(byte); };
} else {
break;
}
// this could be nicer i guess for chunk in chunks {
} self.peripheral
.write(&self.tx_characteristic, chunk, write_type)
self.tx(&buf).await?; .await
.unwrap();
std::thread::sleep(std::time::Duration::from_millis(10));
} }
Ok(()) Ok(())
} }
async fn tx(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>> {
let characteristics = self.peripheral.characteristics();
let tx_characteristic = characteristics
.iter()
.filter(|c| c.uuid == TX_CHARACTERISTIC_UUID)
.next()
.unwrap();
self.peripheral
.write(
&tx_characteristic,
data,
btleplug::api::WriteType::WithoutResponse,
)
.await?;
Ok(())
}
pub async fn destroy(self) { pub async fn destroy(self) {
self.peripheral.disconnect().await.unwrap(); self.peripheral.disconnect().await.unwrap();
} }

View file

@ -93,7 +93,7 @@ impl Image {
let pixel = self.image.get((x, y)).unwrap(); let pixel = self.image.get((x, y)).unwrap();
let val = if pixel > &self.mean { 0 } else { 1 }; let val = if pixel > &self.mean { 0 } else { 1 };
if val == last_val { if val == last_val {
counter = counter + 1 counter += 1
} else if counter > 0 { } else if counter > 0 {
compressed.extend(rle_bytes(last_val, counter)); compressed.extend(rle_bytes(last_val, counter));
counter = 1; counter = 1;

View file

@ -72,7 +72,7 @@ impl Command {
DeviceId(_) => 0xBB, DeviceId(_) => 0xBB,
SetSpeed(_) => 0xBD, SetSpeed(_) => 0xBD,
SetDrawingMode(_) => 0xBE, SetDrawingMode(_) => 0xBE,
Print(true, _, _) => 0xBf, // compressed Print(true, _, _) => 0xBF, // compressed
} }
} }
@ -107,7 +107,7 @@ impl Command {
let mut crc = CCITT.digest(); let mut crc = CCITT.digest();
crc.update(&payload); crc.update(&payload);
let crc = crc.finalize() as u8; let crc = crc.finalize();
let payload_len = payload.len(); let payload_len = payload.len();