179 lines
5.7 KiB
C#
Raw 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.

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public static class ComPortScanner
{
// Параметры соединения
private const int BaudRate = 115200;
private const int DataBits = 8;
private const int Parity = 0; // 0 = None
private const int StopBits = 1; // 1 = One
private const int ReadTimeoutMs = 5;
private const int WriteTimeoutMs = 10;
// Команды устройств
private const string CmdPrize = "97"; // Для витрины и периферийника2
private const string CmdControllerAuth = "07";
private const int DeviceResponseTimeoutMs = 1000;
// Типы устройств
public enum DeviceType
{
None,
ControllerV1, // Периферийник1
ControllerV2, // Периферийник2
PrizeShowcase // Витрина
}
// Префиксы ответов
private const string RolePrefix = "ROLE :"; // Периферийник2 и витрина на 97
private const string PrizeRoleValue = "vitrina"; // Витрина: ROLE : vitrina
/// <summary>
/// Сканирует все доступные COM-порты и возвращает словарь {порт = тип устройства}
/// </summary>
public static Dictionary<string, DeviceType> ScanPorts()
{
var result = new Dictionary<string, DeviceType>();
string[] ports = ComNativeWrapper.ListPorts();
foreach (string port in ports)
{
if (port == "COM1") continue;
DeviceType type = CheckPort(port);
if (type != DeviceType.None)
{
result[port] = type;
}
}
return result;
}
/// <summary>
/// Проверяет один порт на наличие известных устройств
/// </summary>
private static DeviceType CheckPort(string port)
{
Debug.Log($"Проверка порта {port}");
string response97 = CheckDevice(
port,
CmdPrize,
line => line.StartsWith(RolePrefix, StringComparison.Ordinal));
if (response97 != null && response97.StartsWith(RolePrefix))
{
Debug.Log($"Role: {response97}");
// Извлекаем значение после "ROLE : "
string roleValue = response97.Substring(RolePrefix.Length).Trim();
// Если роль = "vitrina" - это витрина
if (string.Equals(roleValue, PrizeRoleValue, StringComparison.OrdinalIgnoreCase))
{
return DeviceType.PrizeShowcase;
}
else
{
return DeviceType.ControllerV2;
}
}
string computerChallenge = BoardAuthentication.CreateChallengeHex();
string authResponse = CheckDevice(
port,
CmdControllerAuth + computerChallenge,
IsAuthenticationResponse);
if (authResponse != null)
return DeviceType.ControllerV1;
return DeviceType.None;
}
/// <summary>
/// Очищает входной буфер порта
/// </summary>
private static void ClearPortBuffer(int handle)
{
byte[] tempBuffer = new byte[1024];
const float idleTimeout = 0.5f;
const int maxreads = 50;
int reads = 0;
float startTime = Time.unscaledTime;
while (reads < maxreads)
{
int bytesRead = ComNativeWrapper.Serial_ReadLineUTF8_bytes(handle, tempBuffer, tempBuffer.Length);
reads++;
if (bytesRead > 0)
{
startTime = Time.unscaledTime;
continue;
}
else if (bytesRead == 0)
{
float elapsed = Time.unscaledTime - startTime;
if (elapsed >= idleTimeout)
{
break;
}
}
else
{
break;
}
}
}
/// <summary>
/// Проверяет устройство на порту и возвращает ответ
/// </summary>
private static string CheckDevice(string port, string command, Func<string, bool> isExpectedResponse)
{
int handle = ComNativeWrapper.Serial_Open(port, BaudRate, DataBits, Parity, StopBits, 10, WriteTimeoutMs);
if (handle <= 0)
{
return null;
}
try
{
ClearPortBuffer(handle);
int writeResult = ComNativeWrapper.Serial_WriteStringUTF8(handle, command, 1);
if (writeResult < 0)
{
return null;
}
byte[] buffer = new byte[1024];
long deadline = DateTime.UtcNow.Ticks
+ DeviceResponseTimeoutMs * TimeSpan.TicksPerMillisecond;
while (DateTime.UtcNow.Ticks < deadline)
{
int bytesRead = ComNativeWrapper.Serial_ReadLineUTF8_bytes(handle, buffer, buffer.Length);
if (bytesRead <= 0)
continue;
string line = Encoding.UTF8.GetString(buffer, 0, bytesRead).Trim();
if (!string.IsNullOrEmpty(line) && isExpectedResponse(line))
return line;
}
return null;
}
finally
{
ComNativeWrapper.Serial_Close(handle);
}
}
private static bool IsAuthenticationResponse(string line)
=> BoardAuthentication.TryExtractHexPayload(line, "CHAL", out _)
|| BoardAuthentication.TryExtractHexPayload(line, "RAES", out _);
}