Добавлена предполагаемая структура для множества контроллеров
This commit is contained in:
parent
6296f9e4e1
commit
e984c11172
@ -11349,7 +11349,7 @@ Material:
|
||||
- _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767}
|
||||
- _EnvMatrixRotation: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _FaceColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _GlowColor: {r: 0.91854715, g: 0, b: 1, a: 1}
|
||||
- _GlowColor: {r: 0.63619995, g: 0, b: 1, a: 1}
|
||||
- _MaskCoord: {r: 0, g: 0, b: 32767, a: 32767}
|
||||
- _OutlineColor: {r: 0.554717, g: 0.554717, b: 0.554717, a: 1}
|
||||
- _ReflectFaceColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
|
||||
@ -1,112 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: CharacterTrailMat
|
||||
m_Shader: {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords:
|
||||
- _ALPHABLEND_ON
|
||||
- _EMISSION
|
||||
m_LightmapFlags: 0
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _AlphaTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 2800000, guid: f4792ca58fafabe438e2126cac5b6651, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- PixelSnap: 0
|
||||
- _BlendOp: 0
|
||||
- _BumpScale: 1
|
||||
- _CameraFadingEnabled: 0
|
||||
- _CameraFarFadeDistance: 2
|
||||
- _CameraNearFadeDistance: 1
|
||||
- _ColorMode: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DistortionBlend: 0.5
|
||||
- _DistortionEnabled: 0
|
||||
- _DistortionStrength: 1
|
||||
- _DistortionStrengthScaled: 0
|
||||
- _DstBlend: 10
|
||||
- _EmissionEnabled: 0
|
||||
- _EnableExternalAlpha: 0
|
||||
- _FlipbookMode: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _LightingEnabled: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 2
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SoftParticlesEnabled: 0
|
||||
- _SoftParticlesFarFadeDistance: 1
|
||||
- _SoftParticlesNearFadeDistance: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 5
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 0
|
||||
m_Colors:
|
||||
- _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorAddSubDiff: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Flip: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _RendererColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5e12d87377e2284887adbcfc4fc356e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,111 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Coins
|
||||
m_Shader: {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords:
|
||||
- _ALPHATEST_ON
|
||||
m_LightmapFlags: 0
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _AlphaTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 2800000, guid: face08d206a2bea44b451368a18b1752, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- PixelSnap: 0
|
||||
- _BlendOp: 0
|
||||
- _BumpScale: 1
|
||||
- _CameraFadingEnabled: 0
|
||||
- _CameraFarFadeDistance: 2
|
||||
- _CameraNearFadeDistance: 1
|
||||
- _ColorMode: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DistortionBlend: 0.5
|
||||
- _DistortionEnabled: 0
|
||||
- _DistortionStrength: 1
|
||||
- _DistortionStrengthScaled: 0
|
||||
- _DstBlend: 0
|
||||
- _EmissionEnabled: 0
|
||||
- _EnableExternalAlpha: 0
|
||||
- _FlipbookMode: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 1
|
||||
- _LightingEnabled: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 1
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SoftParticlesEnabled: 0
|
||||
- _SoftParticlesFarFadeDistance: 1
|
||||
- _SoftParticlesNearFadeDistance: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorAddSubDiff: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Flip: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _RendererColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b3c4a2ce664cbe47bcdbe3058e5de34
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,85 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Softness
|
||||
m_Shader: {fileID: 202, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _InvFade: 0.01
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _TintColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99f96c9ac3c491643b9ecda7b40658cd
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
13
Assets/Scripts/Inputs/ComSystem/ComDevice.cs
Normal file
13
Assets/Scripts/Inputs/ComSystem/ComDevice.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class ComDevice
|
||||
{
|
||||
protected int h;
|
||||
public ComDevice(int handleId)
|
||||
{
|
||||
h = handleId;
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Inputs/ComSystem/ComDevice.cs.meta
Normal file
11
Assets/Scripts/Inputs/ComSystem/ComDevice.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04785a4d9ec0ed34eb40efc86f4ffcd6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
40
Assets/Scripts/Inputs/ComSystem/ComHub.cs
Normal file
40
Assets/Scripts/Inputs/ComSystem/ComHub.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public static class ComHub
|
||||
{
|
||||
public static event Action<string> InputRecieved;
|
||||
public static event Action<string> PaymentRecieved;
|
||||
|
||||
|
||||
|
||||
public static string[] GetPortNames()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int OpenPort(string portName)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static string GetRole(int handle)
|
||||
{
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static ComDevice CreateDevice(int handle, ComDeviceType deviceType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ComDeviceType
|
||||
{
|
||||
PeripheralController,
|
||||
PrizeStand
|
||||
}
|
||||
11
Assets/Scripts/Inputs/ComSystem/ComHub.cs.meta
Normal file
11
Assets/Scripts/Inputs/ComSystem/ComHub.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5b90abed5b0bb848a505445ba94f03e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -216,9 +216,6 @@ public static class ComWrapper
|
||||
_ = StartKeepAliveProcessAsync(ct);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static void OpenPort()
|
||||
{
|
||||
Log("Инициализация порта");
|
||||
@ -257,7 +254,7 @@ public static class ComWrapper
|
||||
{
|
||||
//Не пришел инпут
|
||||
Log("Шифрованная плата");
|
||||
}
|
||||
}
|
||||
|
||||
//Запрашиваем шифрованную строку
|
||||
string encLine;
|
||||
|
||||
401
Assets/Scripts/Inputs/ComSystem/PeripheralControllerV2.cs
Normal file
401
Assets/Scripts/Inputs/ComSystem/PeripheralControllerV2.cs
Normal file
@ -0,0 +1,401 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
public class PeripheralControllerV2 : ComDevice
|
||||
{
|
||||
public event Action PaymentReceived;
|
||||
public event Action<string> InputRecieved;
|
||||
|
||||
private const string REQUEST_INPUT_COMMAND = "91";
|
||||
private const string REQUEST_ENCRYPTED_COMMAND = "666";
|
||||
private const string REQUEST_CONFIRMATION_COMMAND = "777";
|
||||
|
||||
private CancellationTokenSource _lifetimeCts;
|
||||
private Thread _readerThread;
|
||||
private CancellationTokenSource _readerCts;
|
||||
|
||||
//private int h;
|
||||
private ILogger logger;
|
||||
|
||||
private int _lastInputTick = 0;
|
||||
private const int INPUT_IDLE_BEFORE_PING_MS = 60_000;//1 минута
|
||||
|
||||
public PeripheralControllerV2(int handleId) : base(handleId)
|
||||
{
|
||||
if (_lifetimeCts != null) return;
|
||||
OpenPort();
|
||||
if (h <= 0)
|
||||
{
|
||||
Log("Порт не открылся при инициализации");
|
||||
return;
|
||||
}
|
||||
|
||||
UnityMainThreadDispatcher.Initialize();
|
||||
_lifetimeCts = new CancellationTokenSource();
|
||||
|
||||
StartReaderThread();
|
||||
_ = SetupBoardAsync(_lifetimeCts.Token);
|
||||
}
|
||||
|
||||
public void Send(string message)
|
||||
{
|
||||
if (h <= 0) return;
|
||||
try
|
||||
{
|
||||
int w = ComNativeWrapper.Serial_WriteStringUTF8(h, message, 1); //w-количество записаных символов в порт. можно обработать
|
||||
}
|
||||
catch { logger?.Log($"Ошибка отправки строкового сигнала. {message}"); }
|
||||
}
|
||||
|
||||
private void StartReaderThread()
|
||||
{
|
||||
StopReaderThread();
|
||||
|
||||
_readerCts = new CancellationTokenSource();
|
||||
var ct = _readerCts.Token;
|
||||
|
||||
_readerThread = new Thread(() =>
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
if (h <= 0) { Thread.Sleep(20); continue; }
|
||||
int read = 0;
|
||||
try
|
||||
{
|
||||
//блок до таймаута чтения
|
||||
read = ComNativeWrapper.Serial_ReadLineUTF8_bytes(h, buffer, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log("Com reader exception: " + ex.Message);
|
||||
Thread.Sleep(50);// пауза чтобы не уйти в спин при ошибке
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ct.IsCancellationRequested) break;
|
||||
|
||||
if (read > 0)
|
||||
{
|
||||
var line = Encoding.UTF8.GetString(buffer, 0, read).Trim();
|
||||
EnqueueLine(line);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_readerThread.IsBackground = true;
|
||||
_readerThread.Start();
|
||||
}
|
||||
|
||||
private void StopReaderThread()
|
||||
{
|
||||
if (_readerCts != null)
|
||||
{
|
||||
_readerCts.Cancel();
|
||||
_readerCts.Dispose();
|
||||
_readerCts = null;
|
||||
}
|
||||
|
||||
if (_readerThread != null)
|
||||
{
|
||||
_readerThread.Join(200);
|
||||
_readerThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
void EnqueueLine(string line)
|
||||
{
|
||||
UnityMainThreadDispatcher.Instance.Enqueue(() => OnLine(line));
|
||||
}
|
||||
|
||||
private void ProcessComInput(string line)
|
||||
{
|
||||
Log($"COM. h={h}: {line}");
|
||||
|
||||
if (line == "COIN")
|
||||
PaymentReceived?.Invoke();
|
||||
else if (line.StartsWith("INPUT"))
|
||||
{
|
||||
Volatile.Write(ref _lastInputTick, Environment.TickCount);
|
||||
InputRecieved?.Invoke(line.Substring(5));
|
||||
}
|
||||
}
|
||||
|
||||
static readonly object _waitLock = new();
|
||||
static readonly List<Waiter> _waiters = new();
|
||||
sealed class Waiter
|
||||
{
|
||||
public Func<string, bool> Match;
|
||||
public TaskCompletionSource<string> Tcs;
|
||||
}
|
||||
static Task<string> WaitForAsync(Func<string, bool> match, int timeoutMs, CancellationToken ct)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var w = new Waiter { Match = match, Tcs = tcs };
|
||||
|
||||
lock (_waitLock) _waiters.Add(w);
|
||||
|
||||
//отмена
|
||||
if (ct.CanBeCanceled)
|
||||
{
|
||||
ct.Register(() =>
|
||||
{
|
||||
lock (_waitLock) _waiters.Remove(w);
|
||||
tcs.TrySetCanceled(ct);
|
||||
});
|
||||
}
|
||||
|
||||
_ = Task.Delay(timeoutMs, CancellationToken.None).ContinueWith(_ =>
|
||||
{
|
||||
lock (_waitLock) _waiters.Remove(w);
|
||||
tcs.TrySetException(new TimeoutException($"Timeout waiting for line"));
|
||||
});
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
static Task<string> WaitForPrefixAsync(string prefix, int timeoutMs, CancellationToken ct)
|
||||
=> WaitForAsync(s => s.StartsWith(prefix, StringComparison.Ordinal), timeoutMs, ct);
|
||||
static Task<string> WaitForContainsAsync(string prefix, int timeoutMs, CancellationToken ct)
|
||||
=> WaitForAsync(s => s.IndexOf(prefix, StringComparison.Ordinal) >= 0, timeoutMs, ct);
|
||||
|
||||
private void OnLine(string line)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line))
|
||||
return;
|
||||
|
||||
//1. обычная обработка
|
||||
ProcessComInput(line);
|
||||
|
||||
//2. Разубудить ожидающих
|
||||
List<Waiter> toFire = null;
|
||||
|
||||
lock (_waitLock)
|
||||
{
|
||||
for (int i = _waiters.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var waiter = _waiters[i];
|
||||
if (waiter.Match(line))
|
||||
{
|
||||
_waiters.RemoveAt(i);
|
||||
(toFire ??= new List<Waiter>()).Add(waiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toFire != null)
|
||||
foreach (var w in toFire)
|
||||
w.Tcs.TrySetResult(line);
|
||||
}
|
||||
|
||||
private async Task SetupBoardAsync(CancellationToken ct)
|
||||
{
|
||||
bool auth = await BoardAuthAsync(ct);
|
||||
if (!auth)
|
||||
{
|
||||
Log("Авторизация на плате не пройдена.");
|
||||
UnityMainThreadDispatcher.Instance.Enqueue(() => Application.Quit());
|
||||
return;
|
||||
}
|
||||
|
||||
_ = StartKeepAliveProcessAsync(ct);
|
||||
}
|
||||
|
||||
private void OpenPort()
|
||||
{
|
||||
Log("Инициализация порта");
|
||||
|
||||
var ports = ComNativeWrapper.ListPorts();
|
||||
if (ports.Length == 0) { Log("Нет портов, завершаю"); return; }
|
||||
|
||||
string port = ports[^1];
|
||||
Log("Открываю порт: " + port);
|
||||
|
||||
h = ComNativeWrapper.Serial_Open(port, 115200, 8, 0, 1, 4, 10);
|
||||
|
||||
|
||||
Log($"handle: {h}");
|
||||
if (h <= 0)
|
||||
{
|
||||
Log("Open failed: " + ComNativeWrapper.GetLastError());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Открыл порт: {port}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> BoardAuthAsync(CancellationToken ct)
|
||||
{
|
||||
//Проверяем зашифрована или нет
|
||||
try
|
||||
{
|
||||
Send(REQUEST_INPUT_COMMAND);
|
||||
var inputLine = await WaitForPrefixAsync("INPUT", 1000, ct);
|
||||
return true;
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
//Не пришел инпут
|
||||
Log("Шифрованная плата");
|
||||
}
|
||||
|
||||
//Запрашиваем шифрованную строку
|
||||
string encLine;
|
||||
try
|
||||
{
|
||||
Send(REQUEST_ENCRYPTED_COMMAND);
|
||||
encLine = await WaitForPrefixAsync("ENC:", 1000, ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log($"Зашифрованная строка не пришла");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Расшифровка
|
||||
var encrypted = encLine.Substring(4);
|
||||
var decrypted = BoardUtility.DecryptSerial(encrypted);
|
||||
|
||||
//Отправляем расшифрованное на подтверждение
|
||||
try
|
||||
{
|
||||
Send(REQUEST_CONFIRMATION_COMMAND + decrypted);
|
||||
await WaitForContainsAsync("OK", 1000, ct);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log("Подтверждение не пришло");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_lifetimeCts?.Cancel();
|
||||
_lifetimeCts?.Dispose();
|
||||
_lifetimeCts = null;
|
||||
|
||||
StopReaderThread();
|
||||
CancelAllWaiters();
|
||||
ClosePort();
|
||||
}
|
||||
|
||||
private static void CancelAllWaiters()
|
||||
{
|
||||
List<Waiter> snapshot;
|
||||
lock (_waitLock)
|
||||
{
|
||||
snapshot = new List<Waiter>(_waiters);
|
||||
_waiters.Clear();
|
||||
}
|
||||
foreach (Waiter waiter in snapshot)
|
||||
{
|
||||
waiter.Tcs.TrySetCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClosePort()
|
||||
{
|
||||
Log($"Отпускаю порт handle:{h}");
|
||||
if (h > 0)
|
||||
{
|
||||
ComNativeWrapper.Serial_Close(h);
|
||||
h = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Сделать ожидание простоя около минуты на проверку и переподелючение.
|
||||
private async Task StartKeepAliveProcessAsync(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log("Запуск асинхронной проверки порта");
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
if (!IsInputIdleTooLong())
|
||||
{
|
||||
await Task.Delay(5000, ct);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Пингуем плату
|
||||
if (!await CheckPortConnectionAsync(ct))
|
||||
{
|
||||
Log("Плата отвалилась. Запускаю переподключение.");
|
||||
await ReinitializePortAsync(ct);
|
||||
}
|
||||
|
||||
await Task.Delay(10000, ct);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Log("Асинхронная проверка порта остановлена");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log($"Ошибка проверки порта: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task<bool> CheckPortConnectionAsync(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
Send(REQUEST_INPUT_COMMAND);
|
||||
await WaitForPrefixAsync("INPUT", 1000, ct);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//реализовать
|
||||
private async Task ReinitializePortAsync(CancellationToken ct)
|
||||
{
|
||||
StopReaderThread();
|
||||
CancelAllWaiters();
|
||||
ClosePort();
|
||||
|
||||
OpenPort();
|
||||
if (h <= 0)
|
||||
{
|
||||
Log($"Ошибка при переподключении.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
StartReaderThread();
|
||||
var auth = await BoardAuthAsync(ct);
|
||||
if (!auth)
|
||||
UnityMainThreadDispatcher.Instance.Enqueue(() => (new GameObject()).AddComponent(typeof(VfxPrefab)));
|
||||
}
|
||||
|
||||
private bool IsInputIdleTooLong()
|
||||
{
|
||||
int last = Volatile.Read(ref _lastInputTick);
|
||||
if (last == 0) return true;
|
||||
int now = Environment.TickCount;
|
||||
|
||||
// переполнение TickCount тут ок: сравнение интервала < 24 дней работает корректно
|
||||
int elapsed = unchecked(now - last);
|
||||
return elapsed >= INPUT_IDLE_BEFORE_PING_MS;
|
||||
}
|
||||
|
||||
private void Log(string message) => logger?.Log($"CW{message}");
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8d55e8d9065b35429dcf34db1956eb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 242 KiB |
Loading…
x
Reference in New Issue
Block a user