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
///
/// Сканирует все доступные COM-порты и возвращает словарь {порт = тип устройства}
///
public static Dictionary ScanPorts()
{
var result = new Dictionary();
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;
}
///
/// Проверяет один порт на наличие известных устройств
///
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;
}
///
/// Очищает входной буфер порта
///
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;
}
}
}
///
/// Проверяет устройство на порту и возвращает ответ
///
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();
}
}
}