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.
This commit is contained in:
Кобелев Андрей Андреевич
2026-08-16 11:24:20 +05:00
parent efc53e6ef5
commit 244d907cc2
25 changed files with 3823 additions and 782 deletions
+30 -21
View File
@@ -2,13 +2,14 @@
mod common;
use anyhow::Result;
use std::error::Error;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use m::vfd::fit_to_width;
use m::worker::VfdWorker;
use escpos_vfd::{VfdWorker, fit_to_width};
fn run_date(args: &[&str]) -> Option<String> {
// Используем системную `date`, чтобы пример оставался без дополнительных зависимостей.
// Если команда недоступна или вернула ошибку, ниже покажем безопасную заглушку.
let out = std::process::Command::new("date")
.args(args)
.output()
@@ -20,6 +21,7 @@ fn run_date(args: &[&str]) -> Option<String> {
}
fn parse_datetime_and_weekday(value: &str) -> Option<(String, u8)> {
// Формат одной строки: "DD.MM.YYYY HH:MM:SS|N", где N - номер дня недели 1..=7.
let (datetime, weekday) = value.split_once('|')?;
let weekday = weekday.parse::<u8>().ok()?;
(1..=7)
@@ -28,6 +30,8 @@ fn parse_datetime_and_weekday(value: &str) -> Option<(String, u8)> {
}
fn local_datetime_and_weekday() -> (String, u8) {
// Один вызов `date` важен: дата, время и день недели приходят из одного snapshot.
// Это убирает редкие рассинхронизации на границе полуночи.
run_date(&["+%d.%m.%Y %H:%M:%S|%u"])
.as_deref()
.and_then(parse_datetime_and_weekday)
@@ -70,8 +74,8 @@ fn time_of_day_ru(hour: u8) -> &'static str {
}
fn extract_hour(datetime: &str) -> u8 {
// ожидаем "DD.MM.YYYY HH:MM:SS"
// берём HH как 2 символа после пробела
// Ожидаем "DD.MM.YYYY HH:MM:SS" и берём HH как два символа после пробела.
// При неожиданном формате возвращаем 12, чтобы пример продолжал работать.
datetime
.split_whitespace()
.nth(1)
@@ -80,43 +84,48 @@ fn extract_hour(datetime: &str) -> u8 {
.unwrap_or(12)
}
fn main() -> Result<()> {
// args:
// 1) port (default: /dev/cu.usbmodem101)
// 2) width (default: 20)
// 3) brightness 1..4 (default: 2)
let mut args = common::ExampleArgs::from_env();
fn main() -> Result<(), Box<dyn Error>> {
// Аргументы:
// 1) port - serial-порт дисплея;
// 2) width - ширина строки, нужна для подгонки текста;
// 3) brightness - яркость из диапазона пресета 1..=4.
let mut args = common::ExampleArgs::from_env()?;
let brightness: u8 = args.parse_or(2);
let width = args.width;
let columns = args.columns;
// Worker остаётся жить до конца процесса. Handle можно клонировать, но сам worker
// владеет serial-портом и фоновым потоком записи.
let worker = VfdWorker::start(args.config)?;
let vfd = worker.handle();
vfd.clear();
vfd.set_brightness(brightness);
vfd.clear()?;
vfd.set_brightness(brightness)?;
loop {
let (dt, wd) = local_datetime_and_weekday();
let hour = extract_hour(&dt);
let tod = time_of_day_ru(hour);
// 1 строка: "28.01.2006 12:03:34"
let line1 = fit_to_width(&dt, width);
// 1 строка: "28.01.2006 12:03:34". `fit_to_width` обрезает по символам и
// дополняет пробелами, чтобы старый текст справа не оставался на дисплее.
let line1 = fit_to_width(&dt, columns);
// 2 строка: "Понедельник сейчас день"
// но если не влазит — "Пн сейчас день"
// 2 строка: сначала пробуем полное название дня недели, если не влазит -
// короткое. Это показывает, как приложение может адаптироваться к ширине VFD.
let full = format!("{} сейчас {}", weekday_ru_full(wd), tod);
let mut line2 = full;
if line2.chars().count() > width {
if line2.chars().count() > columns {
line2 = format!("{} сейчас {}", weekday_ru_short(wd), tod);
}
line2 = fit_to_width(&line2, width);
line2 = fit_to_width(&line2, columns);
vfd.print_line_diff(1, line1)?;
vfd.print_line_diff(2, line2)?;
// чтобы обновлялось ровно раз в секунду (плюс/минус), можно “привязать” к UNIX time
// Привязываем паузу к следующей границе секунды. Тогда часы не "уплывают" из-за
// времени, потраченного на форматирование и serial-запись.
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()