Files
vfd/examples/update_at.rs
T
Кобелев Андрей Андреевич 244d907cc2 Rename crate to escpos-vfd and add tokio support
Rename crate to escpos-vfd and add tokio support

Introduce a configurable crate-ready API with presets, typed errors,
optional Tokio async support, and expanded documentation.
2026-08-16 11:24:20 +05:00

106 lines
4.1 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Имитирует компактный дашборд и обновляет только изменяемые поля через `print_at`.
mod common;
use std::error::Error;
use escpos_vfd::VfdWorker;
fn pad_left(s: &str, width: usize) -> String {
// Подгоняем ширину поля, чтобы при уменьшении числа не оставались "хвосты" от
// предыдущего значения. Например, после 1000 должно появиться " 999", а не "9990".
if s.chars().count() >= width {
s.chars().take(width).collect()
} else {
format!("{:>width$}", s, width = width)
}
}
fn main() -> Result<(), Box<dyn Error>> {
// Аргументы:
// 1) port - serial-порт дисплея;
// 2) width - ширина строки;
// 3) delay_ms - пауза между изменениями данных.
let mut args = common::ExampleArgs::from_env()?;
let delay_ms: u64 = args.parse_or(200);
let columns = args.columns;
// Координаты ниже подобраны под 20 символов. Для более узких дисплеев лучше
// сделать другой layout, поэтому пример явно сообщает об ограничении.
if columns < 20 {
return Err("update_at requires a display width of at least 20 columns".into());
}
// Worker сохраняет кэш строк. Благодаря этому `print_at` и `print_line_diff`
// согласованно обновляют только изменившиеся области.
let worker = VfdWorker::start(args.config)?;
let vfd = worker.handle();
vfd.clear()?;
// Рисуем "шаблон" один раз. Дальше меняем только числовые поля внутри шаблона.
// 12345678901234567890
// Temp: __.__C RPM:____
// Load: ___% Uptime:____
vfd.print_line_diff(1, "Temp: 00.00C RPM:0000")?;
vfd.print_line_diff(2, "Load: 000% Up:0000s")?;
// Координаты (1-based):
// "Temp: 00.00C ..." -> числа начинаются с x=7, длина 5 (00.00)
let temp_x = 7u8;
let temp_w = 5usize;
// "RPM:0000" -> числа начинаются после "RPM:"; в строке выше это x=16, длина 4
let rpm_x = 16u8;
let rpm_w = 4usize;
// "Load: 000%" -> числа x=7, длина 3
let load_x = 7u8;
let load_w = 3usize;
// "Up:0000s" -> числа x=12, длина 4
let up_x = 12u8;
let up_w = 4usize;
let mut t: f32 = 21.50;
let mut rpm: u32 = 900;
let mut load: u32 = 10;
let mut uptime: u32 = 0;
let spinner = ["|", "/", "-", "\\"];
let mut si = 0usize;
loop {
// Чуть "шевелим" данные, чтобы на дисплее были видны частичные обновления.
t += 0.03;
if t > 29.99 {
t = 21.50;
}
rpm = (rpm + 37) % 9999;
load = (load + 3) % 100;
uptime = uptime.wrapping_add(1);
// Важно: обновляем только куски строки в фиксированных местах. Это меньше
// нагружает serial-линию и обычно выглядит спокойнее, чем полная перерисовка.
let temp_s = pad_left(&format!("{:.2}", t), temp_w);
let rpm_s = pad_left(&format!("{}", rpm), rpm_w);
let load_s = pad_left(&format!("{}", load), load_w);
let up_s = pad_left(&format!("{}", uptime % 10000), up_w);
vfd.print_at(temp_x, 1, temp_s)?;
vfd.print_at(rpm_x, 1, rpm_s)?;
vfd.print_at(load_x, 2, load_s)?;
vfd.print_at(up_x, 2, up_s)?;
// "Живой" индикатор справа показывает, что цикл продолжает выполняться.
if columns >= 20 {
vfd.print_at(20, 2, spinner[si])?;
si = (si + 1) % spinner.len();
}
common::sleep_ms(delay_ms);
}
}