From 2f8a9d7e5ffe8950ad4ec2c585fbca8f7bfe2508 Mon Sep 17 00:00:00 2001 From: shylie Date: Tue, 24 Feb 2026 16:50:15 -0500 Subject: [PATCH] Rework for custom pcb --- src/main.rs | 216 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 146 insertions(+), 70 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2c109eb..cb548e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,46 +1,48 @@ use image::imageops::FilterType; use image::{EncodableLayout, ImageError}; -use nusb::transfer::{Bulk, Out, TransferError}; use nusb::MaybeFuture; -use nusb::{list_devices, ErrorKind}; +use nusb::transfer::{Bulk, In, Out, TransferError}; +use nusb::{ErrorKind, list_devices}; use reqwest::header::ACCEPT; use serde::Deserialize; use std::env; use std::fmt::{Display, Formatter}; -use std::io::Write; +use std::io::{Read, Write}; +use std::time::Duration; #[derive(Debug)] struct Error { - message: &'static str + message: String, } impl From for Error { fn from(value: nusb::Error) -> Self { - Error{ + Error { message: match value.kind() { - ErrorKind::Disconnected => "Device disconnected", - ErrorKind::Busy => "Device busy", - ErrorKind::PermissionDenied => "No permission to access device", - ErrorKind::NotFound => "Device not found", - ErrorKind::Unsupported => "Device not supported", - _ => "Unknown error" - } + ErrorKind::Disconnected => "Device disconnected".to_owned(), + ErrorKind::Busy => "Device busy".to_owned(), + ErrorKind::PermissionDenied => "No permission to access device".to_owned(), + ErrorKind::NotFound => "Device not found".to_owned(), + ErrorKind::Unsupported => "Device not supported".to_owned(), + ErrorKind::Other => value.to_string(), + _ => "Unknown error".to_owned(), + }, } } } impl From for Error { - fn from(_: TransferError) -> Self { - Error{ - message: "Error during transfer" + fn from(value: TransferError) -> Self { + Error { + message: value.to_string(), } } } impl From for Error { - fn from(_: std::io::Error) -> Self { + fn from(value: std::io::Error) -> Self { Error { - message: "Error during transfer" + message: value.to_string(), } } } @@ -48,7 +50,7 @@ impl From for Error { impl From for Error { fn from(_: ImageError) -> Self { Error { - message: "Error reading image" + message: "Error reading image".to_owned(), } } } @@ -56,7 +58,7 @@ impl From for Error { impl From for Error { fn from(_: reqwest::Error) -> Self { Error { - message: "Error retrieving card info" + message: "Error retrieving card info".to_owned(), } } } @@ -69,7 +71,7 @@ impl Display for Error { #[derive(Deserialize)] struct ImageUris { - pub png: String + pub png: String, } #[derive(Deserialize)] @@ -77,17 +79,20 @@ struct ScryfallCardInfo { pub cmc: f32, pub colors: Vec, pub name: String, - pub image_uris: ImageUris + pub image_uris: ImageUris, } struct RelevantCardInfo { pub cmc: u8, pub colors: u8, pub name: String, - pub image: Vec + pub image: Vec, } -fn get_relevant_card_info(set_code: &str, collector_number: &str) -> Result { +fn get_relevant_card_info( + set_code: &str, + collector_number: &str, +) -> Result { let client = reqwest::blocking::ClientBuilder::new() .user_agent("Digital MtG Token/0.1.0") .build()?; @@ -95,23 +100,28 @@ fn get_relevant_card_info(set_code: &str, collector_number: &str) -> Result { colors |= 0b10000; - }, + } "U" => { colors |= 0b1000; - }, + } "B" => { colors |= 0b100; - }, + } "R" => { colors |= 0b10; - }, + } "G" => { colors |= 0b1; } @@ -123,14 +133,17 @@ fn get_relevant_card_info(set_code: &str, collector_number: &str) -> Result Result<(), Error> { - let device = list_devices().wait()? + let device = list_devices() + .wait()? .find(|dev| dev.vendor_id() == 0xCAFE && dev.product_id() == 0xCA6D) - .ok_or(Error { message: "Device not found" })?; + .ok_or(Error { + message: "Device not found".to_owned(), + })?; let device = device.open().wait()?; let interface = device.claim_interface(1).wait()?; @@ -138,44 +151,107 @@ fn main() -> Result<(), Error> { let mut writer = interface.endpoint::(0x01)?.writer(4096); let args: Vec = env::args().collect(); - if args.len() == 1 { - writer.write(&[0x42])?; - writer.flush()?; + if args.len() > 1 { + match args[1].as_str() { + "erase" => { + writer.write_all(&[0x42])?; + writer.flush()?; + } + "test" => { + writer.write_all(&[0x69])?; + writer.flush()?; + + let mut reader = interface + .endpoint::(0x81)? + .reader(128) + .with_read_timeout(Duration::from_millis(2500)); + + let mut temp = [0u8; 256]; + let mut buf: Vec = vec![]; + loop { + match reader.read(&mut temp) { + Ok(n) => { + if n > 0 { + buf.extend_from_slice(&temp[..n]); + println!("extended: {}", n); + } + } + Err(e) if e.kind() == std::io::ErrorKind::TimedOut => break, + r => { + r?; + } + } + } + + println!("buflen: {}", buf.len()); + let mut card_index = 0; + for (i, val) in buf.iter().enumerate() { + print!("{:02x}", val); + if i > 0 && i % 256 == 0 { + println!(); + let b0 = (buf[256 * card_index] as u16) + + ((buf[256 * card_index + 1] as u16) << 8); + let is_used = b0 & 0x01 > 0; + let name_length = (b0 >> 1) & 0x1F; + let cmc = (b0 >> 6) & 0x1F; + let colors = (b0 >> 11) & 0x1F; + + let name = + &buf[256 * card_index + 8..256 * card_index + 8 + name_length as usize]; + + for ch in name { + print!("{}", *ch as char); + } + println!(" ({})", name_length); + println!("Used: {}", is_used); + println!("CMC: {}", cmc); + println!("Colors: {}", colors); + println!(); + + card_index += 1; + } + } + println!(); + } + _ => { + let slash_position = args[1].find("/").ok_or(Error { + message: "Error retrieving card info".to_owned(), + })?; + + let set_code = &args[1][0..slash_position]; + let collectors_number = &args[1][slash_position + 1..]; + + let relevant_info = get_relevant_card_info(set_code, collectors_number)?; + + // converted mana cost + writer.write_all(&[relevant_info.cmc])?; + + // colors + writer.write_all(&[relevant_info.colors])?; + + let name = relevant_info.name.as_str(); + let name_len = if name.len() >= 32 { 31 } else { name.len() }; + + // length of card name + writer.write_all(&[name_len as u8])?; + + // name of card + writer.write_all(&name.as_bytes()[0..name_len])?; + + let img = image::load_from_memory(relevant_info.image.as_bytes())?; + let img = img.crop_imm(28, 28, img.width() - 56, img.height() - 56); + let img = img.resize_exact(240, 320, FilterType::Lanczos3); + let img = img.into_rgb8(); + + // image of card + writer.write_all(img.as_flat_samples().samples)?; + writer.flush()?; + } + } + Ok(()) + } else { + Err(Error { + message: "Incorrect usage".to_owned(), + }) } - else { - let slash_position = args[1].find("/").ok_or(Error { - message: "Error retrieving card info" - })?; - - let set_code = &args[1][0..slash_position]; - let collectors_number = &args[1][slash_position + 1..]; - - let relevant_info = get_relevant_card_info(set_code, collectors_number)?; - - // converted mana cost - writer.write(&[relevant_info.cmc])?; - - // colors - writer.write(&[relevant_info.colors])?; - - let name = relevant_info.name.as_str(); - let name_len = if name.len() >= 32 { 31 } else { name.len() }; - - // length of card name - writer.write(&[name_len as u8])?; - - // name of card - writer.write(name[0..name_len].as_bytes())?; - - let img = image::load_from_memory(relevant_info.image.as_bytes())?; - let img = img.crop_imm(28, 28, img.width() - 56, img.height() - 56); - let img = img.resize_exact(240, 320, FilterType::Lanczos3); - let img = img.into_rgb8(); - - // image of card - writer.write_all(img.as_flat_samples().samples)?; - writer.flush()?; - } - - Ok(()) }