176 lines
6.0 KiB
C#
176 lines
6.0 KiB
C#
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 CmdControllerV1 = "666"; // Только для периферийника1
|
||
|
||
// Типы устройств
|
||
public enum DeviceType
|
||
{
|
||
None,
|
||
ControllerV1, // Периферийник1
|
||
ControllerV2, // Периферийник2
|
||
PrizeShowcase // Витрина
|
||
}
|
||
|
||
// Префиксы ответов
|
||
private const string ControllerV1ResponsePrefix = "ENC:"; // Периферийник1 на 666
|
||
private const string ControllerV1NotActivatedPrefix = "NOT_ACTIVATED:"; // Периферийник1 на всё остальное
|
||
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)
|
||
{
|
||
DeviceType type = CheckPort(port);
|
||
if (type != DeviceType.None)
|
||
{
|
||
result[port] = type;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет один порт на наличие известных устройств
|
||
/// </summary>
|
||
private static DeviceType CheckPort(string port)
|
||
{
|
||
Debug.Log($"Проверка порта {port}");
|
||
// ШАГ 1: Проверяем периферийник1 по команде 666
|
||
string response666 = CheckDevice(port, CmdControllerV1);
|
||
if (response666 != null)
|
||
{
|
||
// Если ответ начинается с "ENC:" - это точно периферийник1
|
||
if (response666.StartsWith(ControllerV1ResponsePrefix) || response666.StartsWith("ALREADY_ACTIVATED"))
|
||
{
|
||
return DeviceType.ControllerV1;
|
||
}
|
||
}
|
||
|
||
// ШАГ 2: Проверяем по команде 97 (витрина и периферийник2)
|
||
string response97 = CheckDevice(port, CmdPrize);
|
||
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;
|
||
}
|
||
|
||
}
|
||
|
||
// ШАГ 3: Дополнительная проверка для неактивированного периферийника1
|
||
// Если устройство ответило на 97 с "NOT_ACTIVATED:" - это периферийник1
|
||
if (response97 != null && response97.StartsWith(ControllerV1NotActivatedPrefix))
|
||
{
|
||
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)
|
||
{
|
||
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];
|
||
int bytesRead = ComNativeWrapper.Serial_ReadLineUTF8_bytes(handle, buffer, buffer.Length);
|
||
|
||
if (bytesRead <= 0)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
string line = Encoding.UTF8.GetString(buffer, 0, bytesRead).Trim();
|
||
return string.IsNullOrEmpty(line) ? null : line;
|
||
}
|
||
finally
|
||
{
|
||
ComNativeWrapper.Serial_CloseAll();
|
||
}
|
||
}
|
||
} |