mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31939f41ba |
@@ -20,8 +20,3 @@ desktop-extensions/gnome*/@types/gir-generated
|
|||||||
desktop-extensions/gnome*/node_modules
|
desktop-extensions/gnome*/node_modules
|
||||||
desktop-extensions/gnome*/schemas/gschemas.compiled
|
desktop-extensions/gnome*/schemas/gschemas.compiled
|
||||||
desktop-extensions/gnome*/*.zip
|
desktop-extensions/gnome*/*.zip
|
||||||
|
|
||||||
# agents and reference
|
|
||||||
CLAUDE.md
|
|
||||||
AGENTS.md
|
|
||||||
/reference
|
|
||||||
|
|||||||
@@ -1,547 +0,0 @@
|
|||||||
//! LED scanning tool for discovering AniMe Matrix buffer-to-LED mappings.
|
|
||||||
//!
|
|
||||||
//! This tool lights up one buffer index at a time, allowing you to observe
|
|
||||||
//! which physical LED corresponds to each buffer position. This is essential
|
|
||||||
//! for mapping new device types like G835L where the exact layout is unknown.
|
|
||||||
//!
|
|
||||||
//! You might want to use it slowly, as it sometimes doesn't work properly.
|
|
||||||
//! Maybe there's better ways to make this reliable but for now it works for my use case.
|
|
||||||
//!
|
|
||||||
//! # Usage
|
|
||||||
//! ```
|
|
||||||
//! cargo run --example anime-led-scan -- [options]
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! # Controls
|
|
||||||
//! - `n` or `Enter`: Next index
|
|
||||||
//! - `p` or `Backspace`: Previous index
|
|
||||||
//! - `j` followed by number: Jump to specific index
|
|
||||||
//! - `+` / `-`: Adjust step size (default 1)
|
|
||||||
//! - `s`: Save current index to notes file
|
|
||||||
//! - `r`: Mark current index as row start
|
|
||||||
//! - `q` or `Ctrl+C`: Quit
|
|
||||||
//!
|
|
||||||
//! # Output
|
|
||||||
//! Creates a `led-scan-notes.txt` file with recorded observations.
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::fs::OpenOptions;
|
|
||||||
use std::io::{self, BufRead, Write};
|
|
||||||
|
|
||||||
use rog_anime::usb::{get_anime_type, Brightness};
|
|
||||||
use rog_anime::{AnimeDataBuffer, AnimeType};
|
|
||||||
use rog_dbus::zbus_anime::AnimeProxyBlocking;
|
|
||||||
use zbus::blocking::Connection;
|
|
||||||
|
|
||||||
/// Saved device state for restoration on exit
|
|
||||||
struct SavedState {
|
|
||||||
builtins_enabled: bool,
|
|
||||||
brightness: Brightness,
|
|
||||||
display_enabled: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_help(scan_len: usize, buffer_len: usize) {
|
|
||||||
println!("\n=== LED Scan Tool ===");
|
|
||||||
println!(
|
|
||||||
"Scan range: 0-{} (buffer size: {})",
|
|
||||||
scan_len - 1,
|
|
||||||
buffer_len
|
|
||||||
);
|
|
||||||
println!("Commands:");
|
|
||||||
println!(" n, Enter - Next index");
|
|
||||||
println!(" p, Backspace - Previous index");
|
|
||||||
println!(" j <num> - Jump to index");
|
|
||||||
println!(" + / - - Increase/decrease step size");
|
|
||||||
println!(" s - Save note for current index");
|
|
||||||
println!(" r - Mark as row start");
|
|
||||||
println!(" a - Auto-scan (runs through all indices)");
|
|
||||||
println!(" f - Fill all buffer bytes");
|
|
||||||
println!(" f <start> <end> - Fill range (inclusive)");
|
|
||||||
println!(" p1/p2/p3 - Fill pane 1/2/3 only (each is 627 bytes)");
|
|
||||||
println!(" hold - Hold current LED (press Enter to release)");
|
|
||||||
println!(" hold <s> <e> - Hold range (press Enter to release)");
|
|
||||||
println!(" c - Clear display");
|
|
||||||
println!(" row - Step through rows (G835L, provisional)");
|
|
||||||
println!(" row <n> - Show specific row (G835L, provisional)");
|
|
||||||
println!(" allrows - Light all rows sequentially (G835L)");
|
|
||||||
println!(" rowmap - Print the full row mapping (G835L)");
|
|
||||||
println!(" h - Show this help");
|
|
||||||
println!(" q - Quit and restore state");
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_note(index: usize, note: &str) -> io::Result<()> {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.create(true)
|
|
||||||
.append(true)
|
|
||||||
.open("led-scan-notes.txt")?;
|
|
||||||
writeln!(file, "Index {}: {}", index, note)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_single_led(
|
|
||||||
proxy: &AnimeProxyBlocking,
|
|
||||||
anime_type: AnimeType,
|
|
||||||
index: usize,
|
|
||||||
brightness: u8,
|
|
||||||
) {
|
|
||||||
let mut buffer = AnimeDataBuffer::new(anime_type);
|
|
||||||
let data = buffer.data_mut();
|
|
||||||
if index < data.len() {
|
|
||||||
data[index] = brightness;
|
|
||||||
}
|
|
||||||
if let Err(e) = proxy.write(buffer) {
|
|
||||||
eprintln!("Error writing to device: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_display(proxy: &AnimeProxyBlocking, anime_type: AnimeType) {
|
|
||||||
let buffer = AnimeDataBuffer::new(anime_type);
|
|
||||||
let _ = proxy.write(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_display(proxy: &AnimeProxyBlocking, anime_type: AnimeType, brightness: u8) {
|
|
||||||
let mut buffer = AnimeDataBuffer::new(anime_type);
|
|
||||||
let data = buffer.data_mut();
|
|
||||||
for byte in data.iter_mut() {
|
|
||||||
*byte = brightness;
|
|
||||||
}
|
|
||||||
if let Err(e) = proxy.write(buffer) {
|
|
||||||
eprintln!("Error writing to device: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fill a range of LEDs. Both start and end are INCLUSIVE.
|
|
||||||
fn fill_range(
|
|
||||||
proxy: &AnimeProxyBlocking,
|
|
||||||
anime_type: AnimeType,
|
|
||||||
start: usize,
|
|
||||||
end: usize,
|
|
||||||
brightness: u8,
|
|
||||||
) {
|
|
||||||
let mut buffer = AnimeDataBuffer::new(anime_type);
|
|
||||||
let data = buffer.data_mut();
|
|
||||||
for i in start..=end.min(data.len().saturating_sub(1)) {
|
|
||||||
data[i] = brightness;
|
|
||||||
}
|
|
||||||
if let Err(e) = proxy.write(buffer) {
|
|
||||||
eprintln!("Error writing to device: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_pane(proxy: &AnimeProxyBlocking, anime_type: AnimeType, pane: usize, brightness: u8) {
|
|
||||||
const PANE_LEN: usize = 627;
|
|
||||||
let start = pane * PANE_LEN;
|
|
||||||
let end = start + PANE_LEN - 1;
|
|
||||||
fill_range(proxy, anime_type, start, end, brightness);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// G835L row pattern (PROVISIONAL - needs hardware verification):
|
|
||||||
/// - Rows 0-1: 1 LED each
|
|
||||||
/// - Rows 2-3: 2 LEDs each
|
|
||||||
/// - ... (pairs of rows with same length)
|
|
||||||
/// - Rows 26-27: 14 LEDs each
|
|
||||||
/// - Rows 28+: 15 LEDs each (constant)
|
|
||||||
///
|
|
||||||
/// Returns (start_index, end_index_inclusive, row_length)
|
|
||||||
fn g835l_row_bounds(row: usize) -> (usize, usize, usize) {
|
|
||||||
let triangle_rows = 28;
|
|
||||||
let triangle_leds = 210;
|
|
||||||
|
|
||||||
if row < triangle_rows {
|
|
||||||
let length = row / 2 + 1;
|
|
||||||
let mut start = 0usize;
|
|
||||||
for r in 0..row {
|
|
||||||
start += r / 2 + 1;
|
|
||||||
}
|
|
||||||
(start, start + length - 1, length)
|
|
||||||
} else {
|
|
||||||
let rows_after_triangle = row - triangle_rows;
|
|
||||||
let start = triangle_leds + rows_after_triangle * 15;
|
|
||||||
(start, start + 14, 15)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn g835l_total_rows() -> usize {
|
|
||||||
28 + 40
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_state(proxy: &AnimeProxyBlocking) -> SavedState {
|
|
||||||
SavedState {
|
|
||||||
builtins_enabled: proxy.builtins_enabled().unwrap_or(false),
|
|
||||||
brightness: proxy.brightness().unwrap_or(Brightness::Med),
|
|
||||||
display_enabled: proxy.enable_display().unwrap_or(true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restore_state(proxy: &AnimeProxyBlocking, state: &SavedState) {
|
|
||||||
let _ = proxy.set_builtins_enabled(state.builtins_enabled);
|
|
||||||
let _ = proxy.set_brightness(state.brightness);
|
|
||||||
let _ = proxy.set_enable_display(state.display_enabled);
|
|
||||||
let _ = proxy.run_main_loop(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
|
|
||||||
let mut start_index = 0usize;
|
|
||||||
let mut brightness = 200u8;
|
|
||||||
let mut scan_limit: Option<usize> = None;
|
|
||||||
|
|
||||||
let mut i = 1;
|
|
||||||
while i < args.len() {
|
|
||||||
match args[i].as_str() {
|
|
||||||
"--start" | "-s" => {
|
|
||||||
if i + 1 < args.len() {
|
|
||||||
start_index = args[i + 1].parse().unwrap_or(0);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"--brightness" | "-b" => {
|
|
||||||
if i + 1 < args.len() {
|
|
||||||
brightness = args[i + 1].parse().unwrap_or(200);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"--limit" | "-l" => {
|
|
||||||
if i + 1 < args.len() {
|
|
||||||
scan_limit = args[i + 1].parse().ok();
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"--help" | "-h" => {
|
|
||||||
println!("LED Scan Tool for AniMe Matrix");
|
|
||||||
println!();
|
|
||||||
println!("Usage: anime-led-scan [options]");
|
|
||||||
println!();
|
|
||||||
println!("Options:");
|
|
||||||
println!(" -s, --start <N> Start at index N (default: 0)");
|
|
||||||
println!(" -b, --brightness <N> LED brightness 0-255 (default: 200)");
|
|
||||||
println!(" -l, --limit <N> Cap scan range to N indices (e.g. 810 for G835L)");
|
|
||||||
println!(" -h, --help Show this help");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let conn = match Connection::system() {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Failed to connect to D-Bus: {}", e);
|
|
||||||
eprintln!("Make sure asusd is running.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let proxy = match AnimeProxyBlocking::new(&conn) {
|
|
||||||
Ok(p) => p,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Failed to create Anime proxy: {}", e);
|
|
||||||
eprintln!("Make sure asusd supports your device.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let anime_type = get_anime_type();
|
|
||||||
let buffer_len = anime_type.data_length();
|
|
||||||
let scan_len = scan_limit.unwrap_or(buffer_len).min(buffer_len);
|
|
||||||
|
|
||||||
println!("=== LED Scan Tool ===");
|
|
||||||
println!("Device type: {:?}", anime_type);
|
|
||||||
println!("Buffer length: {} bytes", buffer_len);
|
|
||||||
println!("Scan range: 0-{}", scan_len - 1);
|
|
||||||
println!("Brightness: {}", brightness);
|
|
||||||
println!();
|
|
||||||
|
|
||||||
// Save current state for restoration
|
|
||||||
let saved_state = save_state(&proxy);
|
|
||||||
println!("Saved device state for restoration on exit.");
|
|
||||||
|
|
||||||
// Stop system animations
|
|
||||||
if let Err(e) = proxy.run_main_loop(false) {
|
|
||||||
eprintln!("Warning: Could not stop main loop: {}", e);
|
|
||||||
}
|
|
||||||
println!("Stopped system animations.");
|
|
||||||
|
|
||||||
print_help(scan_len, buffer_len);
|
|
||||||
|
|
||||||
let mut current_index = start_index.min(scan_len - 1);
|
|
||||||
let mut step = 1usize;
|
|
||||||
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
println!(">>> Index: {} (step: {})", current_index, step);
|
|
||||||
|
|
||||||
let stdin = io::stdin();
|
|
||||||
let mut input = String::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
input.clear();
|
|
||||||
print!("> ");
|
|
||||||
io::stdout().flush().unwrap();
|
|
||||||
|
|
||||||
if stdin.lock().read_line(&mut input).is_err() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd = input.trim();
|
|
||||||
|
|
||||||
match cmd {
|
|
||||||
"q" | "quit" | "exit" => {
|
|
||||||
clear_display(&proxy, anime_type);
|
|
||||||
restore_state(&proxy, &saved_state);
|
|
||||||
println!("Restored device state. Goodbye!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
"n" | "" => {
|
|
||||||
current_index = (current_index + step).min(scan_len - 1);
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
println!(">>> Index: {} (step: {})", current_index, step);
|
|
||||||
}
|
|
||||||
"p" => {
|
|
||||||
current_index = current_index.saturating_sub(step);
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
println!(">>> Index: {} (step: {})", current_index, step);
|
|
||||||
}
|
|
||||||
"+" => {
|
|
||||||
step = step.saturating_mul(2).max(1);
|
|
||||||
println!("Step size: {}", step);
|
|
||||||
}
|
|
||||||
"-" => {
|
|
||||||
step = step.saturating_div(2).max(1);
|
|
||||||
println!("Step size: {}", step);
|
|
||||||
}
|
|
||||||
"r" => {
|
|
||||||
if let Err(e) = save_note(current_index, "ROW START") {
|
|
||||||
eprintln!("Error saving note: {}", e);
|
|
||||||
} else {
|
|
||||||
println!("Saved: Index {} marked as ROW START", current_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"h" | "help" | "?" => {
|
|
||||||
print_help(scan_len, buffer_len);
|
|
||||||
}
|
|
||||||
cmd if cmd.starts_with('j') => {
|
|
||||||
let num_str = cmd.trim_start_matches('j').trim();
|
|
||||||
if let Ok(idx) = num_str.parse::<usize>() {
|
|
||||||
if idx < scan_len {
|
|
||||||
current_index = idx;
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
println!(">>> Index: {} (step: {})", current_index, step);
|
|
||||||
} else {
|
|
||||||
println!("Index {} out of range (max: {})", idx, scan_len - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Usage: j <number>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmd if cmd.starts_with('s') && !cmd.starts_with("show") => {
|
|
||||||
let note = cmd.trim_start_matches('s').trim();
|
|
||||||
let note = if note.is_empty() { "observed" } else { note };
|
|
||||||
if let Err(e) = save_note(current_index, note) {
|
|
||||||
eprintln!("Error saving note: {}", e);
|
|
||||||
} else {
|
|
||||||
println!("Saved note for index {}", current_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"a" => {
|
|
||||||
println!("Auto-scan mode (0 to {})...", scan_len - 1);
|
|
||||||
let delay = std::time::Duration::from_millis(10);
|
|
||||||
for idx in current_index..scan_len {
|
|
||||||
write_single_led(&proxy, anime_type, idx, brightness);
|
|
||||||
print!("\rIndex: {} / {} ", idx, scan_len - 1);
|
|
||||||
io::stdout().flush().unwrap();
|
|
||||||
std::thread::sleep(delay);
|
|
||||||
current_index = idx;
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
println!("Auto-scan complete. Current index: {}", current_index);
|
|
||||||
}
|
|
||||||
"c" => {
|
|
||||||
clear_display(&proxy, anime_type);
|
|
||||||
println!("Display cleared");
|
|
||||||
}
|
|
||||||
"f" => {
|
|
||||||
fill_display(&proxy, anime_type, brightness);
|
|
||||||
println!("All buffer bytes filled at brightness {}", brightness);
|
|
||||||
}
|
|
||||||
"p1" => {
|
|
||||||
fill_pane(&proxy, anime_type, 0, brightness);
|
|
||||||
println!("Pane 1 (indices 0-626) filled");
|
|
||||||
}
|
|
||||||
"p2" => {
|
|
||||||
fill_pane(&proxy, anime_type, 1, brightness);
|
|
||||||
println!("Pane 2 (indices 627-1253) filled");
|
|
||||||
}
|
|
||||||
"p3" => {
|
|
||||||
fill_pane(&proxy, anime_type, 2, brightness);
|
|
||||||
println!("Pane 3 (indices 1254-1880) filled");
|
|
||||||
}
|
|
||||||
cmd if cmd.starts_with("f ") => {
|
|
||||||
let parts: Vec<&str> = cmd.split_whitespace().collect();
|
|
||||||
if parts.len() == 3 {
|
|
||||||
if let (Ok(start), Ok(end)) =
|
|
||||||
(parts[1].parse::<usize>(), parts[2].parse::<usize>())
|
|
||||||
{
|
|
||||||
fill_range(&proxy, anime_type, start, end, brightness);
|
|
||||||
println!("Filled indices {} to {}", start, end);
|
|
||||||
} else {
|
|
||||||
println!("Usage: f <start> <end>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Usage: f <start> <end>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"show" => {
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
println!(">>> Index: {} (step: {})", current_index, step);
|
|
||||||
}
|
|
||||||
"row" => {
|
|
||||||
if anime_type != AnimeType::G835L {
|
|
||||||
println!("Warning: Row commands use G835L mapping (provisional). You can add to this code to support other types. `examples/anime-led-scan.rs[402:425]`");
|
|
||||||
}
|
|
||||||
println!("Row stepping mode. Press Enter for next row, 'q' to quit.");
|
|
||||||
let total = g835l_total_rows();
|
|
||||||
for row_num in 0..total {
|
|
||||||
let (start, end, len) = g835l_row_bounds(row_num);
|
|
||||||
if end >= scan_len {
|
|
||||||
println!("Row {} exceeds scan limit, stopping.", row_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
println!("Row {}: indices {}-{} ({} LEDs)", row_num, start, end, len);
|
|
||||||
fill_range(&proxy, anime_type, start, end, brightness);
|
|
||||||
input.clear();
|
|
||||||
print!("(Enter=next, q=quit) > ");
|
|
||||||
io::stdout().flush().unwrap();
|
|
||||||
if stdin.lock().read_line(&mut input).is_err() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if input.trim() == "q" {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
clear_display(&proxy, anime_type);
|
|
||||||
}
|
|
||||||
println!("Row stepping done.");
|
|
||||||
}
|
|
||||||
cmd if cmd.starts_with("row ") => {
|
|
||||||
if anime_type != AnimeType::G835L {
|
|
||||||
println!("Warning: Row commands use G835L mapping (provisional).");
|
|
||||||
}
|
|
||||||
let row_str = cmd.trim_start_matches("row ").trim();
|
|
||||||
if let Ok(row_num) = row_str.parse::<usize>() {
|
|
||||||
let total = g835l_total_rows();
|
|
||||||
if row_num < total {
|
|
||||||
let (start, end, len) = g835l_row_bounds(row_num);
|
|
||||||
if end < scan_len {
|
|
||||||
println!("Row {}: indices {}-{} ({} LEDs)", row_num, start, end, len);
|
|
||||||
fill_range(&proxy, anime_type, start, end, brightness);
|
|
||||||
} else {
|
|
||||||
println!("Row {} exceeds scan limit", row_num);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Row {} out of range (max: {})", row_num, total - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Usage: row <number>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"allrows" => {
|
|
||||||
if anime_type != AnimeType::G835L {
|
|
||||||
println!("Warning: Row commands use G835L mapping (provisional).");
|
|
||||||
}
|
|
||||||
println!("Lighting all rows sequentially (200ms each)...");
|
|
||||||
let total = g835l_total_rows();
|
|
||||||
let delay = std::time::Duration::from_millis(200);
|
|
||||||
for row_num in 0..total {
|
|
||||||
let (start, end, len) = g835l_row_bounds(row_num);
|
|
||||||
if end >= scan_len {
|
|
||||||
println!("\nRow {} exceeds scan limit, stopping.", row_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
print!(
|
|
||||||
"\rRow {}/{}: indices {}-{} ({} LEDs) ",
|
|
||||||
row_num,
|
|
||||||
total - 1,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
len
|
|
||||||
);
|
|
||||||
io::stdout().flush().unwrap();
|
|
||||||
fill_range(&proxy, anime_type, start, end, brightness);
|
|
||||||
std::thread::sleep(delay);
|
|
||||||
clear_display(&proxy, anime_type);
|
|
||||||
}
|
|
||||||
println!("\nDone.");
|
|
||||||
}
|
|
||||||
"rowmap" => {
|
|
||||||
if anime_type != AnimeType::G835L {
|
|
||||||
println!("Warning: Row map is for G835L (provisional).");
|
|
||||||
}
|
|
||||||
println!("G835L Row Map:");
|
|
||||||
let total = g835l_total_rows();
|
|
||||||
for row_num in 0..total {
|
|
||||||
let (start, end, len) = g835l_row_bounds(row_num);
|
|
||||||
let marker = if end >= scan_len {
|
|
||||||
" (exceeds limit)"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
println!(
|
|
||||||
" Row {:2}: indices {:4}-{:4} ({:2} LEDs){}",
|
|
||||||
row_num, start, end, len, marker
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"hold" => {
|
|
||||||
// Single write, wait for Enter to release
|
|
||||||
println!("Holding index {}. Press Enter to release...", current_index);
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
input.clear();
|
|
||||||
let _ = stdin.lock().read_line(&mut input);
|
|
||||||
clear_display(&proxy, anime_type);
|
|
||||||
println!("Released.");
|
|
||||||
}
|
|
||||||
cmd if cmd.starts_with("hold ") => {
|
|
||||||
let arg = cmd.trim_start_matches("hold ").trim();
|
|
||||||
let (start, end): (usize, usize) = match arg {
|
|
||||||
"p1" | "1" => (0, 626),
|
|
||||||
"p2" | "2" => (627, 1253),
|
|
||||||
_ => {
|
|
||||||
let parts: Vec<&str> = arg.split_whitespace().collect();
|
|
||||||
if parts.len() == 2 {
|
|
||||||
if let (Ok(s), Ok(e)) = (parts[0].parse(), parts[1].parse()) {
|
|
||||||
(s, e)
|
|
||||||
} else {
|
|
||||||
println!("Usage: hold p1, hold p2, or hold <start> <end>");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Usage: hold p1, hold p2, or hold <start> <end>");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
println!("Holding range {}-{}. Press Enter to release...", start, end);
|
|
||||||
fill_range(&proxy, anime_type, start, end, brightness);
|
|
||||||
input.clear();
|
|
||||||
let _ = stdin.lock().read_line(&mut input);
|
|
||||||
clear_display(&proxy, anime_type);
|
|
||||||
println!("Released.");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if let Ok(idx) = cmd.parse::<usize>() {
|
|
||||||
if idx < scan_len {
|
|
||||||
current_index = idx;
|
|
||||||
write_single_led(&proxy, anime_type, current_index, brightness);
|
|
||||||
println!(">>> Index: {} (step: {})", current_index, step);
|
|
||||||
} else {
|
|
||||||
println!("Index {} out of range (max: {})", idx, scan_len - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Unknown command: '{}'. Type 'h' for help.", cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -114,7 +114,7 @@ impl AnimeType {
|
|||||||
match self {
|
match self {
|
||||||
AnimeType::GU604 => 70,
|
AnimeType::GU604 => 70,
|
||||||
// TODO: Find G635L W*H
|
// TODO: Find G635L W*H
|
||||||
AnimeType::G635L => 68,
|
// AnimeType::G635L => 68
|
||||||
AnimeType::G835L => 68,
|
AnimeType::G835L => 68,
|
||||||
_ => 74,
|
_ => 74,
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ impl AnimeType {
|
|||||||
match self {
|
match self {
|
||||||
AnimeType::GA401 => 36,
|
AnimeType::GA401 => 36,
|
||||||
AnimeType::GU604 => 43,
|
AnimeType::GU604 => 43,
|
||||||
AnimeType::G635L => 34,
|
// AnimeType::G635L => 34,
|
||||||
AnimeType::G835L => 34,
|
AnimeType::G835L => 34,
|
||||||
_ => 39,
|
_ => 39,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ impl AnimeDiagonal {
|
|||||||
/// Generate the base image from inputs. The result can be displayed as is
|
/// Generate the base image from inputs. The result can be displayed as is
|
||||||
/// or updated via scale, position, or angle then displayed again after
|
/// or updated via scale, position, or angle then displayed again after
|
||||||
/// `update()`.
|
/// `update()`.
|
||||||
|
///
|
||||||
|
/// TODO: G835L and G635L only supports grayscale
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_png(
|
pub fn from_png(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
@@ -383,6 +385,8 @@ impl AnimeDiagonal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement `to_g635l_packets` and `to_g835l_packets` functions
|
// TODO: Implement `to_g635l_packets` and `to_g835l_packets` functions
|
||||||
|
// IMPORTANT NOTE: G635L and G835L ONLY SUPPORT GRAYSCALE
|
||||||
|
//
|
||||||
// fn to_g835l_packets(buf: &[u8]) -> Result<AnimeDataBuffer> {
|
// fn to_g835l_packets(buf: &[u8]) -> Result<AnimeDataBuffer> {
|
||||||
// let mut buf = vec![0u8; AnimeType::GU604.data_length()];
|
// let mut buf = vec![0u8; AnimeType::GU604.data_length()];
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 187 B |
Binary file not shown.
|
Before Width: | Height: | Size: 829 B |
Binary file not shown.
|
Before Width: | Height: | Size: 148 B |
@@ -5,7 +5,7 @@ use zbus::proxy;
|
|||||||
#[proxy(
|
#[proxy(
|
||||||
interface = "xyz.ljones.Anime",
|
interface = "xyz.ljones.Anime",
|
||||||
default_service = "xyz.ljones.Asusd",
|
default_service = "xyz.ljones.Asusd",
|
||||||
default_path = "/xyz/ljones/aura/anime"
|
default_path = "/xyz/ljones"
|
||||||
)]
|
)]
|
||||||
pub trait Anime {
|
pub trait Anime {
|
||||||
/// DeviceState method
|
/// DeviceState method
|
||||||
|
|||||||
Reference in New Issue
Block a user