- Добавлен ComSystemManager как новый публичный компонент COM-системы для поэтапной замены ComWrapper - Реализовано получение роли контроллера только после успешного handshake в ComDeviceClient - Добавлено публичное поле ControllerRole в ComDeviceClient - Добавлен запрос роли по команде 97 и разбор ответа формата ROLE : <value> (с пробелами) - В ComMultiManager добавлена логика выбора DefaultDeviceId по роли main_controller - Добавлен доступ к роли устройства через GetDeviceRole(deviceId) в менеджере и фасаде - В ComWrapper добавлены настройки роли: roleRequestCommand, roleResponsePrefix, roleRequestTimeoutMs, mainControllerRole - Дефолтная команда запроса роли изменена на 97 - Выполнена кодовая миграция зависимостей с ComWrapper на ComSystemManager в GameManager, GlobalsManager, PaymentManager, BalanceManager, InactivityManager, COMInput, LightController, PrizeSystem - В GlobalsManager исправлена инициализация ссылки после AddComponent<ComSystemManager>(), чтобы исключить NullReference
245 lines
8.4 KiB
C#
245 lines
8.4 KiB
C#
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using RR.Game2D.Core.Managers;
|
||
|
||
namespace RR.Common.Controls
|
||
{
|
||
internal sealed class ComMultiManager
|
||
{
|
||
private readonly Dictionary<string, ComDeviceClient> _devices = new();
|
||
private readonly ConcurrentQueue<string> _coinQueue = new();
|
||
private readonly ConcurrentQueue<DeviceInputMessage> _inputQueue = new();
|
||
private readonly ConcurrentQueue<string> _authorizedQueue = new();
|
||
|
||
private readonly bool _useAllDetectedPorts;
|
||
private readonly string[] _explicitPorts;
|
||
private readonly string _defaultDevicePort;
|
||
private readonly bool _enableEncryptedHandshake;
|
||
private readonly int _handshakeTimeoutMs;
|
||
private readonly bool _keepAlive;
|
||
private readonly string _roleRequestCommand;
|
||
private readonly string _roleResponsePrefix;
|
||
private readonly int _roleRequestTimeoutMs;
|
||
private readonly string _mainControllerRole;
|
||
|
||
private string _defaultDeviceId = string.Empty;
|
||
|
||
public ComMultiManager(
|
||
bool useAllDetectedPorts,
|
||
string[] explicitPorts,
|
||
string defaultDevicePort,
|
||
bool enableEncryptedHandshake,
|
||
int handshakeTimeoutMs,
|
||
bool keepAlive,
|
||
string roleRequestCommand,
|
||
string roleResponsePrefix,
|
||
int roleRequestTimeoutMs,
|
||
string mainControllerRole)
|
||
{
|
||
_useAllDetectedPorts = useAllDetectedPorts;
|
||
_explicitPorts = explicitPorts ?? Array.Empty<string>();
|
||
_defaultDevicePort = defaultDevicePort ?? string.Empty;
|
||
_enableEncryptedHandshake = enableEncryptedHandshake;
|
||
_handshakeTimeoutMs = handshakeTimeoutMs;
|
||
_keepAlive = keepAlive;
|
||
_roleRequestCommand = roleRequestCommand ?? string.Empty;
|
||
_roleResponsePrefix = roleResponsePrefix ?? "ROLE";
|
||
_roleRequestTimeoutMs = roleRequestTimeoutMs;
|
||
_mainControllerRole = string.IsNullOrWhiteSpace(mainControllerRole) ? "main_controller" : mainControllerRole;
|
||
}
|
||
|
||
public string DefaultDeviceId => _defaultDeviceId;
|
||
|
||
public string[] ConnectedDeviceIds => _devices.Keys.ToArray();
|
||
|
||
public void InitializeDevices()
|
||
{
|
||
ComNativeWrapper.Serial_CloseAll();
|
||
|
||
string[] allPorts = ComNativeWrapper.ListPorts();
|
||
if (allPorts.Length == 0)
|
||
{
|
||
GameManager.Logger?.LogWarning("ComMultiManager", "Не найдено COM-портов");
|
||
return;
|
||
}
|
||
|
||
string[] selectedPorts = SelectPorts(allPorts);
|
||
foreach (string port in selectedPorts)
|
||
{
|
||
TryCreateDevice(port);
|
||
}
|
||
|
||
ResolveDefaultDeviceId();
|
||
}
|
||
|
||
public void ShutdownAll(bool sendShutdownCommands)
|
||
{
|
||
foreach (ComDeviceClient client in _devices.Values)
|
||
{
|
||
UnsubscribeDevice(client);
|
||
client.Stop(sendShutdownCommands);
|
||
}
|
||
|
||
_devices.Clear();
|
||
_defaultDeviceId = string.Empty;
|
||
|
||
while (_coinQueue.TryDequeue(out _)) { }
|
||
while (_inputQueue.TryDequeue(out _)) { }
|
||
while (_authorizedQueue.TryDequeue(out _)) { }
|
||
}
|
||
|
||
public bool SendToDefault(string message)
|
||
{
|
||
if (string.IsNullOrEmpty(_defaultDeviceId)) return false;
|
||
return SendToDevice(_defaultDeviceId, message);
|
||
}
|
||
|
||
public bool SendToDevice(string deviceId, string message)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(deviceId)) return false;
|
||
if (!_devices.TryGetValue(deviceId, out ComDeviceClient client)) return false;
|
||
client.Send(message);
|
||
return true;
|
||
}
|
||
|
||
public void SendToAll(string message)
|
||
{
|
||
foreach (ComDeviceClient client in _devices.Values)
|
||
{
|
||
client.Send(message);
|
||
}
|
||
}
|
||
|
||
public string GetLastInputState(string deviceId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(deviceId)) return "11111111111111111111111111";
|
||
return _devices.TryGetValue(deviceId, out ComDeviceClient client)
|
||
? client.LastInputBits
|
||
: "11111111111111111111111111";
|
||
}
|
||
|
||
public bool TryDequeueCoin(out string deviceId) => _coinQueue.TryDequeue(out deviceId);
|
||
|
||
public bool TryDequeueInput(out DeviceInputMessage message) => _inputQueue.TryDequeue(out message);
|
||
|
||
public bool TryDequeueAuthorized(out string deviceId) => _authorizedQueue.TryDequeue(out deviceId);
|
||
|
||
public string GetDeviceRole(string deviceId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(deviceId)) return string.Empty;
|
||
return _devices.TryGetValue(deviceId, out ComDeviceClient client)
|
||
? client.ControllerRole
|
||
: string.Empty;
|
||
}
|
||
|
||
private string[] SelectPorts(string[] allPorts)
|
||
{
|
||
if (_useAllDetectedPorts) return allPorts;
|
||
if (_explicitPorts.Length == 0) return Array.Empty<string>();
|
||
|
||
HashSet<string> explicitSet = new HashSet<string>(_explicitPorts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||
return allPorts.Where(explicitSet.Contains).ToArray();
|
||
}
|
||
|
||
private void ResolveDefaultDeviceId()
|
||
{
|
||
if (!string.IsNullOrWhiteSpace(_defaultDevicePort) && _devices.ContainsKey(_defaultDevicePort))
|
||
{
|
||
_defaultDeviceId = _defaultDevicePort;
|
||
return;
|
||
}
|
||
|
||
_defaultDeviceId = _devices.Keys.FirstOrDefault() ?? string.Empty;
|
||
}
|
||
|
||
private void TryCreateDevice(string port)
|
||
{
|
||
ComDeviceClient client = new ComDeviceClient(
|
||
port,
|
||
_enableEncryptedHandshake,
|
||
_handshakeTimeoutMs,
|
||
_keepAlive,
|
||
_roleRequestCommand,
|
||
_roleResponsePrefix,
|
||
_roleRequestTimeoutMs);
|
||
|
||
SubscribeDevice(client);
|
||
|
||
if (!client.Start())
|
||
{
|
||
UnsubscribeDevice(client);
|
||
return;
|
||
}
|
||
|
||
_devices[client.DeviceId] = client;
|
||
}
|
||
|
||
private void SubscribeDevice(ComDeviceClient client)
|
||
{
|
||
client.CoinAccepted += OnDeviceCoinAccepted;
|
||
client.InputReceived += OnDeviceInputReceived;
|
||
client.Authorized += OnDeviceAuthorized;
|
||
client.Disconnected += OnDeviceDisconnected;
|
||
}
|
||
|
||
private void UnsubscribeDevice(ComDeviceClient client)
|
||
{
|
||
client.CoinAccepted -= OnDeviceCoinAccepted;
|
||
client.InputReceived -= OnDeviceInputReceived;
|
||
client.Authorized -= OnDeviceAuthorized;
|
||
client.Disconnected -= OnDeviceDisconnected;
|
||
}
|
||
|
||
private void OnDeviceCoinAccepted(string deviceId)
|
||
{
|
||
_coinQueue.Enqueue(deviceId);
|
||
}
|
||
|
||
private void OnDeviceInputReceived(string deviceId, string inputBits)
|
||
{
|
||
_inputQueue.Enqueue(new DeviceInputMessage(deviceId, inputBits));
|
||
}
|
||
|
||
private void OnDeviceAuthorized(string deviceId)
|
||
{
|
||
if (_devices.TryGetValue(deviceId, out ComDeviceClient client) &&
|
||
string.Equals(client.ControllerRole, _mainControllerRole, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
_defaultDeviceId = deviceId;
|
||
}
|
||
else if (string.IsNullOrWhiteSpace(_defaultDeviceId))
|
||
{
|
||
_defaultDeviceId = deviceId;
|
||
}
|
||
|
||
_authorizedQueue.Enqueue(deviceId);
|
||
}
|
||
|
||
private void OnDeviceDisconnected(string deviceId)
|
||
{
|
||
if (!_devices.TryGetValue(deviceId, out ComDeviceClient client)) return;
|
||
UnsubscribeDevice(client);
|
||
_devices.Remove(deviceId);
|
||
|
||
if (_defaultDeviceId == deviceId)
|
||
{
|
||
_defaultDeviceId = _devices.Keys.FirstOrDefault() ?? string.Empty;
|
||
}
|
||
}
|
||
}
|
||
|
||
internal readonly struct DeviceInputMessage
|
||
{
|
||
public readonly string DeviceId;
|
||
public readonly string InputBits;
|
||
|
||
public DeviceInputMessage(string deviceId, string inputBits)
|
||
{
|
||
DeviceId = deviceId;
|
||
InputBits = inputBits;
|
||
}
|
||
}
|
||
}
|