На ноутбуке магазина автопоиск спотыкался о Bluetooth-порты (COM7/COM8 — Open/Write висят), выбирал по умолчанию BT и не доходил до COM22 (USB-SERIAL CH340, где весы). Парсер/протокол исправны (ручной выбор COM22 57600 работает) — баг только в поиске. - ScaleAutodiscovery.DiscoverAsync: тирами по типу порта — USB-serial первыми, неопознанные в середине, Bluetooth последними; на каждый порт ЖЁСТКИЙ таймаут (Open обёрнут в задачу с гонкой против Task.Delay — SerialPort.Open на BT виснет); порты перебираются параллельно (до 4), общий бюджет ~15 с; любая ошибка/таймаут → следующий порт; по каждому порту строка в лог («COM22 CH340: ENQ→ACK, вес 0.000 кг», «COM7 Bluetooth: пропущен», «COM15: нет ответа»). - HardwareProbe: Classify (CH340/Prolific/FTDI/CP210x → USB-serial; BTHENUM/Bluetooth → Bluetooth; ttyUSB/ttyACM → USB-serial), ClassifyPorts (без открытия портов), OpenCloseBounded (жёсткий таймаут — листинг не виснет на BT). ListComPorts не открывает Bluetooth-порты. - HwCheck: по умолчанию выбирается НЕ Bluetooth-порт; окно показывает журнал автопоиска по портам; список портов помечает [USB-serial]/[Bluetooth]. - Основная касса (экран «Оборудование») — та же DiscoverScaleAsync; --probe-hw не открывает BT-порты. - Из zip hardware-check убран ярлык «(с тестовой печатью).bat» (печать — отдельно по слову владельца). - Тесты: зависающий порт (Open 30 с) не задерживает поиск > таймаута, живой порт вторым — найден; USB-serial проверяется раньше Bluetooth (BT не трогаем). 53/53. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
80 lines
3.5 KiB
C#
80 lines
3.5 KiB
C#
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using FluentAssertions;
|
||
using foodmarket.Pos.Core.Hardware;
|
||
using Xunit;
|
||
using PortKind = foodmarket.Pos.Core.Hardware.HardwareProbe.PortKind;
|
||
using PortDesc = foodmarket.Pos.Core.Hardware.HardwareProbe.PortDesc;
|
||
|
||
public class ScaleAutodiscoveryTests
|
||
{
|
||
private static byte[] Frame(string payload, byte control = 0x71)
|
||
{
|
||
var body = new List<byte> { MassaK.SOH, MassaK.STX };
|
||
body.AddRange(Encoding.ASCII.GetBytes(payload));
|
||
body.Add(control); body.Add(MassaK.ETX); body.Add(MassaK.EOT);
|
||
return body.ToArray();
|
||
}
|
||
|
||
// Требование 5: «зависающий» порт не должен задерживать поиск дольше таймаута;
|
||
// живой порт вторым — должен быть найден.
|
||
[Fact]
|
||
public async Task Hanging_port_does_not_block_discovery_of_live_port()
|
||
{
|
||
var ports = new List<PortDesc>
|
||
{
|
||
new("COMHANG", PortKind.Unknown, "зависает на Open"),
|
||
new("COMLIVE", PortKind.Unknown, "живой"),
|
||
};
|
||
var live = Frame("S 1.235kg");
|
||
foodmarket.Pos.Core.Hardware.ISerialTransport Make(string p, int b) =>
|
||
p == "COMHANG" ? new foodmarket.UnitTests.FakeScaleTransport { OpenDelayMs = 30000 }
|
||
: new foodmarket.UnitTests.FakeScaleTransport { AnswerAck = true, Frame = live };
|
||
|
||
var sw = Stopwatch.StartNew();
|
||
var res = await ScaleAutodiscovery.DiscoverAsync(
|
||
log: null, transportFactory: Make, portsOverride: ports,
|
||
perPortMs: 1500, maxParallel: 4, budgetMs: 15000);
|
||
sw.Stop();
|
||
|
||
res.Device.Should().NotBeNull();
|
||
res.Device!.Port.Should().Be("COMLIVE");
|
||
res.Device.SampleKg.Should().Be(1.235m);
|
||
sw.ElapsedMilliseconds.Should().BeLessThan(5000); // не ждём 30 с зависшего порта
|
||
}
|
||
|
||
// Требование 2/3: USB-serial проверяется раньше Bluetooth — находим весы на CH340,
|
||
// не трогая Bluetooth-порт первым.
|
||
[Fact]
|
||
public async Task UsbSerial_tier_is_probed_before_bluetooth()
|
||
{
|
||
var ports = new List<PortDesc>
|
||
{
|
||
new("COM7", PortKind.Bluetooth, "Bluetooth"),
|
||
new("COM22", PortKind.UsbSerial, "USB-SERIAL CH340"),
|
||
};
|
||
var btTouched = false;
|
||
var live = Frame("S 0.000kg");
|
||
foodmarket.Pos.Core.Hardware.ISerialTransport Make(string p, int b)
|
||
{
|
||
if (p == "COM7") { btTouched = true; return new foodmarket.UnitTests.FakeScaleTransport { OpenDelayMs = 30000 }; }
|
||
return new foodmarket.UnitTests.FakeScaleTransport { AnswerAck = true, Frame = live };
|
||
}
|
||
var res = await ScaleAutodiscovery.DiscoverAsync(transportFactory: Make, portsOverride: ports);
|
||
res.Device!.Port.Should().Be("COM22");
|
||
btTouched.Should().BeFalse("USB-serial найден в первом тире — до Bluetooth дело не дошло");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task No_device_reports_cleanly()
|
||
{
|
||
var ports = new List<PortDesc> { new("COMX", PortKind.Unknown, "пусто") };
|
||
foodmarket.Pos.Core.Hardware.ISerialTransport Make(string p, int b)
|
||
=> new foodmarket.UnitTests.FakeScaleTransport { AnswerAck = false };
|
||
var res = await ScaleAutodiscovery.DiscoverAsync(transportFactory: Make, portsOverride: ports, perPortMs: 400);
|
||
res.Device.Should().BeNull();
|
||
}
|
||
}
|