docs(pos): фикс автопоиска весов (Bluetooth) проверен на Win11 + --autofind
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run

- HwCheck: флаг --autofind (автопоиск при старте — для скриншотов/проверки).
- docs/pos-scale-2026-10-11: добавлен скриншот автопоиска на VM (COM1 в журнале,
  без зависания), отчёт обновлён — новый zip hardware-check и его SHA256; полная
  проверка с эмулятором/зависшим виртуальным портом ждёт com0com (решение владельца).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
nns 2026-10-11 09:09:37 +05:00
parent f15a12695c
commit 8371ef6683
5 changed files with 81 additions and 1 deletions

View file

@ -88,6 +88,50 @@ Linux-сборку не ломали (System.IO.Ports/System.Management общи
тогда уточним смысл флага и control-байта (сейчас они логируются, но не тогда уточним смысл флага и control-байта (сейчас они логируются, но не
интерпретируются). интерпретируются).
## Исправление бага автопоиска (Bluetooth) — по реальному запуску на кассе 11.10
**Симптом (sysadmin):** на ноутбуке магазина порты COM7/COM8 (Bluetooth, «The write
timed out»), COM15–17 (неопознанные), **COM22 = USB-SERIAL CH340 (там весы)**.
«Найти весы» → «Весы не найдены ни на одном порту», хотя ручной выбор
COM22/57600/Масса-К-кадр даёт «0,000 кг, стабильно». Причина: автопоиск спотыкался
о Bluetooth-порты (Open/Write на них висят) и до COM22 не доходил; по умолчанию в
списке стоял COM7 (Bluetooth).
**Исправлено (и в кассе, и в HwCheck):**
- Порты классифицируются по типу (WMI, без открытия): **USB-serial** (CH340/
Prolific/FTDI/CP210x), **Bluetooth** (BTHENUM/«по соединению Bluetooth»),
неопознанные. Порядок автопоиска: **USB-serial → неопознанные → Bluetooth**.
- На каждый порт — **жёсткий таймаут** (Open обёрнут в задачу с гонкой против
Task.Delay; при зависании транспорт принудительно закрывается). Порты
перебираются **параллельно (до 4)**, общий бюджет ~15 с. Любая ошибка/таймаут
на порту → следующий порт, перебор не останавливается.
- **Лог по каждому порту** в окне: «COM22 (USB-SERIAL CH340): ENQ→ACK, вес 0.000 кг»,
«COM7: пропущен Bluetooth-порт», «COM15: нет ответа». Листинг портов тоже не
открывает Bluetooth (помечает «не опрашивается»). По умолчанию выбирается
НЕ Bluetooth-порт.
- Из zip hardware-check **убран ярлык «(с тестовой печатью).bat»** (печать — только
отдельно, по слову владельца).
- Юнит-тесты: «зависающий» порт (Open 30 с) **не задерживает поиск дольше таймаута**,
живой порт вторым — **найден**; USB-serial проверяется раньше Bluetooth
(BT не трогаем). Всего по оборудованию 53/53 зелёных.
**Проверка на Windows 11 (VM):** «Проверка оборудования» запущена с автопоиском
(`--autofind`) — перебрала COM1, записала в журнал «COM1: нет ответа» и **завершилась
быстро, без зависания** (на VM нет весов и нет Bluetooth-порта). См.
`vm-hwcheck-autofind.png`.
**НОВЫЙ zip hardware-check (с фиксом):**
`~/pos-release/allmarket-pos-win-x64-20261011-0906-hardware-check.zip`
SHA256 `ac5cedef0f5dd63e98f0f3044ef453666f71d8c18280107983b1023cbd573623`
(один ярлык «Проверка оборудования.bat», без ярлыка печати).
**Полная проверка с эмулятором весов + «зависающим» виртуальным портом (п. 7) —
по-прежнему требует com0com на VM**, установка драйвера которого упирается в доверие
издателю (см. выше) — ждёт решения владельца. Поведение «не виснуть на зависшем
порту» доказано юнит-тестом детерминированно; на VM показано, что автопоиск логирует
по портам и быстро завершается.
## Файлы ## Файлы
- `vm-hwcheck-launch.png` — окно «Проверка оборудования» на Windows 11. - `vm-hwcheck-launch.png` — окно «Проверка оборудования» на Windows 11.
- `index.html` — та же сводка со скриншотом. - `vm-hwcheck-autofind.png` — автопоиск с журналом по портам (COM1), без зависания.
- `index.html` — сводка со скриншотами.

View file

@ -17,6 +17,8 @@ code{background:#eef2f7;padding:1px 5px;border-radius:4px;font-size:13px}
<li class="ok">✓ Контрольная цифра EAN-13/EAN-8; сканер vs ручной ввод</li> <li class="ok">✓ Контрольная цифра EAN-13/EAN-8; сканер vs ручной ввод</li>
<li class="ok">✓ Юнит-тесты оборудования: 50/50 зелёных</li> <li class="ok">✓ Юнит-тесты оборудования: 50/50 зелёных</li>
<li class="ok">✓ «Проверка оборудования» запускается на реальной Windows 11 (скриншот ниже)</li> <li class="ok">✓ «Проверка оборудования» запускается на реальной Windows 11 (скриншот ниже)</li>
<li class="ok">✓ Фикс автопоиска: USB-serial первыми, Bluetooth последними, жёсткий таймаут на порт, параллельно, лог по портам (баг на кассе 11.10 — виснул на Bluetooth, не доходил до CH340)</li>
<li class="ok">✓ Тест: «зависающий» порт (Open 30 с) не задерживает поиск; живой порт вторым — найден</li>
<li class="no">✗ Живое чтение веса через виртуальную пару COM на VM — НЕ выполнено (драйвер com0com требует доверия издателю; нужно решение владельца)</li> <li class="no">✗ Живое чтение веса через виртуальную пару COM на VM — НЕ выполнено (драйвер com0com требует доверия издателю; нужно решение владельца)</li>
<li class="no">✗ Реальные весы с грузом (гирей) в магазине — НЕ проверялись (нужен человек)</li> <li class="no">✗ Реальные весы с грузом (гирей) в магазине — НЕ проверялись (нужен человек)</li>
</ul> </ul>
@ -26,5 +28,9 @@ code{background:#eef2f7;padding:1px 5px;border-radius:4px;font-size:13px}
<figcaption>«ALL MARKET — Проверка оборудования» на Win11 (VM): без входа; определены COM1 и принтер; тестовая печать выключена; поле сканера активно.</figcaption> <figcaption>«ALL MARKET — Проверка оборудования» на Win11 (VM): без входа; определены COM1 и принтер; тестовая печать выключена; поле сканера активно.</figcaption>
<img src="vm-hwcheck-launch.png" loading="lazy"> <img src="vm-hwcheck-launch.png" loading="lazy">
</figure> </figure>
<figure>
<figcaption>Фикс автопоиска на Win11: перебрал COM1, записал в журнал «COM1: нет ответа», завершился быстро без зависания (на VM нет весов/Bluetooth).</figcaption>
<img src="vm-hwcheck-autofind.png" loading="lazy">
</figure>
<p>Подробности, SHA256 сборок и список «нужно решение владельца» — в <code>REPORT.md</code>.</p> <p>Подробности, SHA256 сборок и список «нужно решение владельца» — в <code>REPORT.md</code>.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View file

@ -66,6 +66,9 @@ public MainWindow(bool allowTestPrint)
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(350) }; _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(350) };
_timer.Tick += (_, _) => LiveTick(); _timer.Tick += (_, _) => LiveTick();
if (Program.AutoFind)
Dispatcher.UIThread.Post(() => DiscoverScale(), DispatcherPriority.Background);
} }
private Control BuildLayout() private Control BuildLayout()

View file

@ -8,15 +8,42 @@ internal static class Program
/// (ключ даёт владелец). Без него кнопка «Тестовая печать» выключена и на принтер /// (ключ даёт владелец). Без него кнопка «Тестовая печать» выключена и на принтер
/// ничего не отправляется.</summary> /// ничего не отправляется.</summary>
public static bool AllowTestPrint { get; private set; } public static bool AllowTestPrint { get; private set; }
/// <summary>Запустить автопоиск весов сразу при открытии (для скриншотов/проверки).</summary>
public static bool AutoFind { get; private set; }
[STAThread] [STAThread]
public static int Main(string[] args) public static int Main(string[] args)
{ {
AllowTestPrint = args.Contains("--allow-test-print"); AllowTestPrint = args.Contains("--allow-test-print");
AutoFind = args.Contains("--autofind");
// Headless-режим для скриптов/интеграционного теста: одно чтение веса и выход.
// --read-once <PORT> [BAUD] [MassaKFrame|MassaKAscii|Cas]
if (args.Contains("--read-once")) return ReadOnceCli(args);
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
return 0; return 0;
} }
private static int ReadOnceCli(string[] args)
{
int i = Array.IndexOf(args, "--read-once");
string port = (i + 1 < args.Length) ? args[i + 1] : "";
int baud = (i + 2 < args.Length && int.TryParse(args[i + 2], out var b)) ? b : 57600;
var proto = (i + 3 < args.Length && Enum.TryParse<Core.Hardware.ScaleProto>(args[i + 3], out var p))
? p : Core.Hardware.ScaleProto.MassaKFrame;
if (string.IsNullOrEmpty(port)) { Console.Error.WriteLine("usage: --read-once <PORT> [BAUD] [PROTO]"); return 2; }
try
{
using var t = new Core.Hardware.SystemSerialTransport(port, baud);
t.Open();
var (r, hex, err) = Core.Hardware.SerialScaleReader.ReadDetailed(t, proto);
if (r is null) { Console.Error.WriteLine($"FAIL: {err} hex=[{hex}]"); return 1; }
Console.WriteLine($"OK kg={r.Value.Kg:0.000} unit={r.Value.Unit} flag='{r.Value.Flag}' " +
$"control={(r.Value.Control is null ? "-" : "0x" + r.Value.Control.Value.ToString("X2"))} hex=[{r.Value.RawHex}]");
return 0;
}
catch (Exception ex) { Console.Error.WriteLine("ERR: " + ex.Message); return 3; }
}
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
{ {
var b = AppBuilder.Configure<App>().UsePlatformDetect(); var b = AppBuilder.Configure<App>().UsePlatformDetect();