|
|
@@ -0,0 +1,1714 @@
|
|
|
+using ScottPlot.Colormaps;
|
|
|
+using SWRIS.Enums;
|
|
|
+using SWRIS.Events;
|
|
|
+using SWRIS.Extensions;
|
|
|
+using SWRIS.Models;
|
|
|
+using SWRIS.Models.Data;
|
|
|
+using System;
|
|
|
+using System.Collections.Concurrent;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using System.Net;
|
|
|
+using System.Net.Sockets;
|
|
|
+using System.Security.Cryptography;
|
|
|
+using System.Text;
|
|
|
+using System.Threading;
|
|
|
+using System.Threading.Tasks;
|
|
|
+
|
|
|
+namespace SWRIS.Core
|
|
|
+{
|
|
|
+ public class TcpServerFrame : IDisposable
|
|
|
+ {
|
|
|
+ // 定义事件
|
|
|
+ public event EventHandler<ClientConnectedEventArgs> ClientConnected;
|
|
|
+ public event EventHandler<ClientDisconnectedEventArgs> ClientDisconnected;
|
|
|
+ public event EventHandler<LiveStreamReceivedEventArgs> LiveStreamReceived;
|
|
|
+ public event EventHandler<AlarmDataReceivedEventArgs> AlarmDataReceived;
|
|
|
+ public event EventHandler<FaultDataReceivedEventArgs> FaultDataReceived;
|
|
|
+ public event EventHandler<DetectionDataReceivedEventArgs> DetectionDataReceived;
|
|
|
+ public event EventHandler<RealTimeDataReceivedEventArgs> RealTimeDataReceived;
|
|
|
+ public event EventHandler<DetectionRawDataReceivedEventArgs> DetectionRawDataReceived;
|
|
|
+ public event EventHandler<ResetSystemDataReceivedEventArgs> ResetSystemDataReceived;
|
|
|
+ public event EventHandler<SetAbsolutePositionDataReceivedEventArgs> SetAbsolutePositionDataReceived;
|
|
|
+ public event EventHandler<DetectionRawDataResultReceivedEventArgs> DetectionRawDataResultReceived;
|
|
|
+ public event EventHandler<DetectionStatusResultReceivedEventArgs> DetectionStatusResultReceived;
|
|
|
+ public event EventHandler<UpgradedResultReceivedEventArgs> UpgradedRequestResultReceived;
|
|
|
+ public event EventHandler<ClockResultReceivedEventArgs> ClockResultReceived;
|
|
|
+ public event EventHandler<EncoderDirectionResultReceivedEventArgs> EncoderDirectionResultReceived;
|
|
|
+ public event EventHandler<HeartbeatReceviedEventArgs> HeartbeatReceived;
|
|
|
+ public event EventHandler<DebugMessageReceivedEventArgs> DebugMessageReceived;
|
|
|
+
|
|
|
+ private Socket _listener;
|
|
|
+ private bool _isRunning;
|
|
|
+ private readonly string _ipAddress;
|
|
|
+ private readonly int _port;
|
|
|
+ private readonly ByteTransform byteTransform;
|
|
|
+ private const string PASSWORD = "WNDTM4";
|
|
|
+ private static ConcurrentDictionary<string, ClientState> _connectedClients;
|
|
|
+ public TcpServerFrame(string ipAddress, int port)
|
|
|
+ {
|
|
|
+ _ipAddress = ipAddress;
|
|
|
+ _port = port;
|
|
|
+ byteTransform = new ByteTransform(DataFormat.DCBA);
|
|
|
+ _connectedClients = new ConcurrentDictionary<string, ClientState>();
|
|
|
+ }
|
|
|
+ public void Start()
|
|
|
+ {
|
|
|
+ _isRunning = true;
|
|
|
+ _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 使用指定的IP地址和端口
|
|
|
+ IPAddress ipAddress = IPAddress.Parse(_ipAddress);
|
|
|
+ _listener.Bind(new IPEndPoint(ipAddress, _port));
|
|
|
+
|
|
|
+ _listener.Listen(10);
|
|
|
+
|
|
|
+ // 启动心跳检测线程
|
|
|
+ StartHeartbeatCheck();
|
|
|
+
|
|
|
+ // 开始接受客户端连接(异步)
|
|
|
+ _listener.BeginAccept(OnClientConnected, null);
|
|
|
+
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"服务已在 {_ipAddress}:{_port} 上启动"));
|
|
|
+ }
|
|
|
+ catch (SocketException ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"启动服务时发生错误: {ex.Message}");
|
|
|
+ if (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
|
|
|
+ {
|
|
|
+ LogHelper.Error("端口已被占用,请更换端口或关闭占用该端口的程序", ex);
|
|
|
+ }
|
|
|
+ else if (ex.SocketErrorCode == SocketError.AddressNotAvailable)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"IP地址 {_ipAddress} 不可用,请检查网络配置", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"TCP服务启动时发生未知错误: {ex.Message}", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Stop()
|
|
|
+ {
|
|
|
+ _isRunning = false;
|
|
|
+ _listener.Shutdown(SocketShutdown.Both);
|
|
|
+ _listener?.Close();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnClientConnected(IAsyncResult ar)
|
|
|
+ {
|
|
|
+ if (!_isRunning)
|
|
|
+ return;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Socket clientSocket = _listener.EndAccept(ar);
|
|
|
+ string ipAddress = (clientSocket.RemoteEndPoint as IPEndPoint)?.Address?.ToString();
|
|
|
+ var equipmentData = App.Config.Equipments.FirstOrDefault(c => c.IpAddress == ipAddress);
|
|
|
+ if (equipmentData != null)
|
|
|
+ {
|
|
|
+ ClientState client = new ClientState(clientSocket, ipAddress, equipmentData.SerialNo);
|
|
|
+ // 添加到连接列表
|
|
|
+ _connectedClients.TryAdd(client.IpAddress, client);
|
|
|
+ // 开始异步接收数据
|
|
|
+ clientSocket.BeginReceive(client.Buffer, 0, client.Buffer.Length, SocketFlags.None, OnDataReceived, client);
|
|
|
+ // 触发客户端连接事件
|
|
|
+ ClientConnected?.Invoke(this, new ClientConnectedEventArgs(clientSocket, ipAddress));
|
|
|
+ }
|
|
|
+ // 继续接受新连接
|
|
|
+ _listener.BeginAccept(OnClientConnected, null);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ Console.WriteLine($"Error accepting client: {ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void StartHeartbeatCheck()
|
|
|
+ {
|
|
|
+ ThreadPool.QueueUserWorkItem(act =>
|
|
|
+ {
|
|
|
+ while (_isRunning)
|
|
|
+ {
|
|
|
+ Thread.Sleep(TimeSpan.FromSeconds(5)); // 每5秒检测一次
|
|
|
+
|
|
|
+ foreach (var client in _connectedClients.ToArray())
|
|
|
+ {
|
|
|
+ if ((DateTime.UtcNow - client.Value.LastActiveTime).TotalSeconds > 15)
|
|
|
+ {
|
|
|
+ SafeCloseClient(client.Value);
|
|
|
+ DebugMessageReceived?.Invoke(this,
|
|
|
+ new DebugMessageReceivedEventArgs($"心跳超时,强制断开", ipAddress: client.Value.IpAddress));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private async void OnDataReceived(IAsyncResult ar)
|
|
|
+ {
|
|
|
+ var state = (ClientState)ar.AsyncState;
|
|
|
+ if (state == null || state.ClientSocket == null || !state.ClientSocket.Connected)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ int bytesRead = state.ClientSocket.EndReceive(ar);
|
|
|
+ if (bytesRead > 0)
|
|
|
+ {
|
|
|
+ // 将接收到的数据添加到缓冲区
|
|
|
+ state.ReceiveBuffer.Write(state.Buffer, 0, bytesRead);
|
|
|
+
|
|
|
+ // 处理缓冲区中的所有数据包
|
|
|
+ while (state.ReceiveBuffer.Length > 0)
|
|
|
+ {
|
|
|
+ byte packetType = state.ReceiveBuffer.PeekByte();
|
|
|
+
|
|
|
+ if (packetType == 0xC0) // 心跳包
|
|
|
+ {
|
|
|
+ ProcessHeartbeatPacket(state);
|
|
|
+ }
|
|
|
+ else if (packetType == 0x30) // 数据包
|
|
|
+ {
|
|
|
+ bool processed = await ProcessDataPacket(state);
|
|
|
+ if (!processed) break; // 数据包不完整,等待更多数据
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 未知包类型,跳过1字节继续检查
|
|
|
+ DebugMessageReceived?.Invoke(this,
|
|
|
+ new DebugMessageReceivedEventArgs($"未知包类型: 0x{packetType:X2}", state.IpAddress));
|
|
|
+ state.ReceiveBuffer.Remove(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 继续接收数据
|
|
|
+ if (state.ClientSocket?.Connected == true)
|
|
|
+ {
|
|
|
+ Array.Clear(state.Buffer, 0, state.Buffer.Length);
|
|
|
+ state.ClientSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length,
|
|
|
+ SocketFlags.None, OnDataReceived, state);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 客户端断开连接
|
|
|
+ DebugMessageReceived?.Invoke(this,
|
|
|
+ new DebugMessageReceivedEventArgs((bytesRead == 0 ? "设备主动断开连接" : "连接异常或错误") + $"({bytesRead})", state.IpAddress));
|
|
|
+ SafeCloseClient(state);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (SocketException sex)
|
|
|
+ {
|
|
|
+ HandleSocketException(sex, state);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ var message = $"接收数据时错误: {ex.Message}";
|
|
|
+ LogHelper.Error(message, ex);
|
|
|
+ SafeCloseClient(state);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void HandleSocketException(SocketException sex, ClientState client)
|
|
|
+ {
|
|
|
+ string message;
|
|
|
+
|
|
|
+ switch (sex.SocketErrorCode)
|
|
|
+ {
|
|
|
+ case SocketError.ConnectionReset:
|
|
|
+ message = "设备强制断开连接 (Connection Reset)";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SocketError.OperationAborted:
|
|
|
+ message = "操作被中止";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SocketError.ConnectionAborted:
|
|
|
+ message = "连接被中止";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SocketError.TimedOut:
|
|
|
+ message = "连接超时";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SocketError.Shutdown:
|
|
|
+ message = "连接已关闭";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SocketError.NetworkReset:
|
|
|
+ message = "网络连接被重置";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SocketError.HostUnreachable:
|
|
|
+ message = "主机不可达";
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ message = $"Socket错误: {sex.SocketErrorCode} - {sex.Message}";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ DebugMessageReceived?.Invoke(this,
|
|
|
+ new DebugMessageReceivedEventArgs(message, client.IpAddress));
|
|
|
+ LogHelper.Error(message, sex);
|
|
|
+ SafeCloseClient(client);
|
|
|
+ }
|
|
|
+ private void ProcessHeartbeatPacket(ClientState client)
|
|
|
+ {
|
|
|
+ // 心跳包固定长度为2字节: 0xC0 + 0x00
|
|
|
+ if (client.ReceiveBuffer.Length < 2)
|
|
|
+ return; // 等待更多数据
|
|
|
+
|
|
|
+ byte[] heartBeatData = new byte[2];
|
|
|
+ client.ReceiveBuffer.Read(heartBeatData, 0, 2);
|
|
|
+
|
|
|
+ client.LastActiveTime = DateTime.UtcNow;
|
|
|
+ RespondHeartbeat(heartBeatData, client.IpAddress, client.ClientSocket);
|
|
|
+
|
|
|
+ HeartbeatReceived?.Invoke(this, new HeartbeatReceviedEventArgs(client.IpAddress));
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task<bool> ProcessDataPacket(ClientState client)
|
|
|
+ {
|
|
|
+ // 检查是否有足够的数据读取长度信息
|
|
|
+ if (client.ReceiveBuffer.Length < 5) // 至少需要包类型 + 最小长度信息
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // 窥探前10个字节来解析长度
|
|
|
+ byte[] peekData = new byte[Math.Min(client.ReceiveBuffer.Length, 10)];
|
|
|
+ int peeked = client.ReceiveBuffer.Peek(peekData, 0, peekData.Length);
|
|
|
+
|
|
|
+ // 解析剩余长度
|
|
|
+ (int byteLength, int remainingLength) = GetRemainingLength(peekData);
|
|
|
+ if (byteLength == 0 || remainingLength == 0)
|
|
|
+ {
|
|
|
+ // 长度解析失败,可能是数据损坏,跳过1字节
|
|
|
+ client.ReceiveBuffer.Remove(1);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算完整包长度
|
|
|
+ int totalPacketLength = 1 + byteLength + remainingLength;
|
|
|
+
|
|
|
+ // 检查是否收到完整包
|
|
|
+ if (client.ReceiveBuffer.Length < totalPacketLength)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // 读取完整数据包
|
|
|
+ byte[] packetData = new byte[totalPacketLength];
|
|
|
+ client.ReceiveBuffer.Read(packetData, 0, totalPacketLength);
|
|
|
+
|
|
|
+ // 提取事件类型和有效载荷
|
|
|
+ int payloadStart = 1 + byteLength;
|
|
|
+ if (payloadStart >= packetData.Length)
|
|
|
+ {
|
|
|
+ DebugMessageReceived?.Invoke(this,
|
|
|
+ new DebugMessageReceivedEventArgs($"数据异常", client.IpAddress));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ byte eventType = packetData[payloadStart];
|
|
|
+ byte[] payload = new byte[remainingLength];
|
|
|
+ Buffer.BlockCopy(packetData, payloadStart, payload, 0, remainingLength);
|
|
|
+
|
|
|
+ // 处理数据包
|
|
|
+ await ProcessEventByType(eventType, payload, client);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 根据事件类型处理数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="eventType"></param>
|
|
|
+ /// <param name="payload"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task ProcessEventByType(byte eventType, byte[] payload, ClientState client)
|
|
|
+ {
|
|
|
+ switch (eventType)
|
|
|
+ {
|
|
|
+ case 0x01:
|
|
|
+ await ProcessSyncParameters(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x06:
|
|
|
+ await ProcessDetectionStatus(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x07:
|
|
|
+ await ProcessFaultData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x08:
|
|
|
+ await ProcessAlarmData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x09:
|
|
|
+ await ProcessDetectionData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x10:
|
|
|
+ await ProcessClockData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x11:
|
|
|
+ await ProcessUpgradedData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x12:
|
|
|
+ await ProcessEncoderDirectionData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x13:
|
|
|
+ await ProcessTwistFactorData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x0A:
|
|
|
+ await ProcessOpenOrClosedRealtimeData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x0B:
|
|
|
+ await ProcessRealTimeData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x0D:
|
|
|
+ await ProcessLiveStreamData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x0C:
|
|
|
+ await ProcessTurnLiveStreamData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x0E:
|
|
|
+ await ProcessDetectionRawResultData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x0F:
|
|
|
+ await ProcessDetectionRawData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x14:
|
|
|
+ await ProcessSystemResetData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x15:
|
|
|
+ await ProcessSetAbsolutePositionData(payload, client);
|
|
|
+ break;
|
|
|
+ case 0x16:
|
|
|
+ await ProcessSerialNoData(payload, client);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 设置实时位置
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task ProcessSetAbsolutePositionData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var resetSystemData = ReceiveSetAbsolutePositionData(buffer);
|
|
|
+ if (resetSystemData != null)
|
|
|
+ {
|
|
|
+ // 设置当前实时位置应答
|
|
|
+ SetAbsolutePositionDataReceived?.Invoke(this,
|
|
|
+ new SetAbsolutePositionDataReceivedEventArgs(client.IpAddress, resetSystemData));
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 主板复位
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task ProcessSystemResetData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var resetSystemData = ReceiveResetSystemData(buffer);
|
|
|
+ if (resetSystemData != null)
|
|
|
+ {
|
|
|
+ // 主板复位结果
|
|
|
+ ResetSystemDataReceived?.Invoke(this,
|
|
|
+ new ResetSystemDataReceivedEventArgs(client.IpAddress, resetSystemData));
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task ProcessDetectionRawData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ await Task.Run(() =>
|
|
|
+ {
|
|
|
+ var detectionRawData = ReceiveDetectionRawData(buffer);
|
|
|
+ if (detectionRawData != null)
|
|
|
+ {
|
|
|
+ // 处理检测原始数据
|
|
|
+ DetectionRawDataReceived?.Invoke(this,
|
|
|
+ new DetectionRawDataReceivedEventArgs(client.IpAddress, detectionRawData));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessDetectionRawResultData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ await Task.Run(() =>
|
|
|
+ {
|
|
|
+ var detectionRawResultData = ReceiveDetectionRawResultData(buffer);
|
|
|
+ if (detectionRawResultData != null)
|
|
|
+ {
|
|
|
+ DetectionRawDataResultReceived?.Invoke(this,
|
|
|
+ new DetectionRawDataResultReceivedEventArgs(client.IpAddress, detectionRawResultData));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessTurnLiveStreamData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var liveStreamStatus = ReceiveTurnLiveStreamData(buffer);
|
|
|
+ if (liveStreamStatus > 0)
|
|
|
+ {
|
|
|
+ // 开启/关闭结果,0=成功,>0=失败-原因码
|
|
|
+ LogHelper.Error($"开启/关闭实时流数据失败,原因码:{liveStreamStatus}");
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessLiveStreamData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ await Task.Run(() =>
|
|
|
+ {
|
|
|
+ var liveStreamData = ReceiveLiveStreamDataModel(buffer);
|
|
|
+ if (liveStreamData != null && liveStreamData.Data.Any())
|
|
|
+ {
|
|
|
+ Console.WriteLine($"接收实时流数据: {liveStreamData.ToString()}");
|
|
|
+ // 触发事件
|
|
|
+ LiveStreamReceived?.Invoke(this,
|
|
|
+ new LiveStreamReceivedEventArgs(client.IpAddress, liveStreamData));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task ProcessRealTimeData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ await Task.Run(() =>
|
|
|
+ {
|
|
|
+ var realTimeData = ReceiveRealTimeData(buffer);
|
|
|
+ if (realTimeData != null)
|
|
|
+ {
|
|
|
+ // 触发实时数据接收事件
|
|
|
+ RealTimeDataReceived?.Invoke(this,
|
|
|
+ new RealTimeDataReceivedEventArgs(client.IpAddress, realTimeData));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessOpenOrClosedRealtimeData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var openOrClosed = ReceiveOpenOrClosedRealtimeData(buffer);
|
|
|
+ if (openOrClosed > 0)
|
|
|
+ {
|
|
|
+ LogHelper.Error("开启或关闭实时数据失败,原因码:" + openOrClosed);
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessTwistFactorData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var twistFactorData = ReceiveTwistFactorData(buffer);
|
|
|
+ if (twistFactorData != null)
|
|
|
+ {
|
|
|
+ var equipmentData = App.Config.Equipments.FirstOrDefault(c => c.IpAddress == client.IpAddress);
|
|
|
+ if (equipmentData != null && equipmentData.Parameter != null)
|
|
|
+ {
|
|
|
+ // 处理判伤捻距系数数据
|
|
|
+ equipmentData.Parameter.TwistFactor = twistFactorData.TwistFactor;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessEncoderDirectionData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var encoderDirection = ReceiveEncoderDirectionData(buffer);
|
|
|
+ if (encoderDirection != null)
|
|
|
+ {
|
|
|
+ var equipmentData = App.Config.Equipments.FirstOrDefault(c => c.IpAddress == client.IpAddress);
|
|
|
+ if (equipmentData != null && equipmentData.Parameter != null)
|
|
|
+ {
|
|
|
+ // 处理编码器方向数据
|
|
|
+ equipmentData.Parameter.EncoderDirection = encoderDirection.Direction;
|
|
|
+ // 编码器方向结果返回事件
|
|
|
+ EncoderDirectionResultReceived?.Invoke(this,
|
|
|
+ new EncoderDirectionResultReceivedEventArgs(client.IpAddress, encoderDirection.Direction));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessClockData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var clockData = ReceiveClockData(buffer);
|
|
|
+ if (clockData != null)
|
|
|
+ {
|
|
|
+ ClockResultReceived?.Invoke(this,
|
|
|
+ new ClockResultReceivedEventArgs(client.IpAddress, clockData.Time));
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessDetectionData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var detectionData = ReceiveDetectionData(buffer);
|
|
|
+ if (detectionData != null)
|
|
|
+ {
|
|
|
+ // 回复检测结果确认
|
|
|
+ if (SendDetectionConfirm(detectionData.StartTime, detectionData.EndTime, client.SerialNo, client.ClientSocket))
|
|
|
+ {
|
|
|
+ if (detectionData.DamageCount <= 0)
|
|
|
+ {
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"检测结果未发现损伤,本次结果不记录",
|
|
|
+ serialNo: client.SerialNo));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 发送获取原始数据请求
|
|
|
+ SendGetDetectionRawData(client.SerialNo, client.ClientSocket);
|
|
|
+ // 处理检测数据
|
|
|
+ DetectionDataReceived?.Invoke(this,
|
|
|
+ new DetectionDataReceivedEventArgs(client.IpAddress, detectionData));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessFaultData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var faultData = ReceiveFaultData(buffer);
|
|
|
+ if (faultData != null)
|
|
|
+ {
|
|
|
+ // 处理故障数据
|
|
|
+ FaultDataReceived?.Invoke(this, new FaultDataReceivedEventArgs(client.IpAddress, faultData));
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ private async Task ProcessAlarmData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ var alarmData = ReceiveAlarmData(buffer);
|
|
|
+ if (alarmData != null)
|
|
|
+ {
|
|
|
+ //处理报警数据
|
|
|
+ AlarmDataReceived?.Invoke(this, new AlarmDataReceivedEventArgs(client.IpAddress, alarmData));
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+
|
|
|
+ }
|
|
|
+ private async Task ProcessSyncParameters(byte[] data, ClientState client)
|
|
|
+ {
|
|
|
+ var (serialNo, parametersData) = ReceiveSyncParameters(data);
|
|
|
+ if (parametersData != null)
|
|
|
+ {
|
|
|
+ var equipmentData = App.Config.Equipments.FirstOrDefault(c => c.IpAddress == client.IpAddress);
|
|
|
+ if (equipmentData != null)
|
|
|
+ {
|
|
|
+ equipmentData.SerialNo = serialNo;
|
|
|
+ equipmentData.Parameter = parametersData;
|
|
|
+
|
|
|
+ await Task.Run(() =>
|
|
|
+ {
|
|
|
+ lock (App.Config.Equipments)
|
|
|
+ {
|
|
|
+ ConfigHelper.SetEquipment(equipmentData);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private async Task ProcessDetectionStatus(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ byte code = ReceiveStartOrStopDetectionResultData(buffer);
|
|
|
+ if (code == 0)
|
|
|
+ {
|
|
|
+ // 启动/停止检测结果,0=成功,>0=失败-原因码
|
|
|
+ DetectionStatusResultReceived?.Invoke(this,
|
|
|
+ new DetectionStatusResultReceivedEventArgs(client.IpAddress, code));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LogHelper.Error($"启动/停止检测结果失败,原因码:{code}");
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ public async Task ProcessUpgradedData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ byte code = ReceiveUpgradedResultData(buffer);
|
|
|
+
|
|
|
+ // 程序更新请求,0=成功,>0=拒绝-原因码
|
|
|
+ UpgradedRequestResultReceived?.Invoke(this,
|
|
|
+ new UpgradedResultReceivedEventArgs(client.IpAddress, code));
|
|
|
+
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ public byte ReceiveTurnLiveStreamData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ return bytes[0];
|
|
|
+ }
|
|
|
+ public byte ReceiveOpenOrClosedRealtimeData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ return bytes[0]; // 开启/关闭结果,0=成功,>0=失败-原因码
|
|
|
+ }
|
|
|
+ public LiveStreamDataModel ReceiveLiveStreamDataModel(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var liveStreamData = new LiveStreamDataModel()
|
|
|
+ {
|
|
|
+ SensorCount = bytes[0],
|
|
|
+ SampleCount = byteTransform.TransUInt16(bytes, 1)
|
|
|
+ };
|
|
|
+
|
|
|
+ var data = bytes.Skip(3).ToArray(); // 跳过前3个字节
|
|
|
+ liveStreamData.Data = ParseSensorData(data, liveStreamData.SensorCount, liveStreamData.SampleCount);
|
|
|
+ return liveStreamData;
|
|
|
+ }
|
|
|
+
|
|
|
+ public TwistFactorDataModel ReceiveTwistFactorData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var twistFactorData = new TwistFactorDataModel
|
|
|
+ {
|
|
|
+ Type = bytes[0],
|
|
|
+ TwistFactor = byteTransform.TransSingle(bytes, 1) // 判伤捻距系数
|
|
|
+ };
|
|
|
+ return twistFactorData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送获取编码器方向请求
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendGetEncoderDirectionData(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0x00); // 操作,0 = 获取编码器方向,1 = 设置编码器方向
|
|
|
+ ms.WriteByte(0x01); // 编码器方向,1=正向,2=反向
|
|
|
+ byte[] buffer = CreateData(0x12, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"获取设备编码器方向", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送获取编码器方向数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送设置编码器方向数据命令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="direction"></param>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="stream"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendSetEncoderDirectionData(EncoderDirection direction, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0x01); // 操作,0 = 获取编码器方向,1 = 设置编码器方向
|
|
|
+ ms.WriteByte((byte)direction); // 编码器方向,1=正向,2=反向
|
|
|
+ byte[] buffer = CreateData(0x12, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"设置设备编码器方向", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送设置编码器方向数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送检测结果原始数据请求
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="clientSocket"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool SendGetDetectionRawData(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0); // 数据类型,0=正常,1=报警,2=故障
|
|
|
+ WriteBytes(ms, (short)2048); // 单包数据大小,单位:Byte
|
|
|
+ ms.WriteByte(0x00); // 传输速度控制,单位:KB/s(B/ms),为0则不控速
|
|
|
+ byte[] buffer = CreateData(0x0E, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"获取检测结果原始数据", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送获取编码器方向数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收获取原始数据结果
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public DetectionRawResultDataModel ReceiveDetectionRawResultData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var detectionRawResultData = new DetectionRawResultDataModel
|
|
|
+ {
|
|
|
+ Code = bytes[0],
|
|
|
+ Timestamp = byteTransform.TransInt32(bytes, 1),
|
|
|
+ SamplingStep = byteTransform.TransSingle(bytes, 5),
|
|
|
+ StartAbsolutePosition = byteTransform.TransSingle(bytes, 9),
|
|
|
+ EndAbsolutePosition = byteTransform.TransSingle(bytes, 13),
|
|
|
+ SensorCount = bytes[17]
|
|
|
+ };
|
|
|
+ return detectionRawResultData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取原始数据包
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public DetectionRawDataModel ReceiveDetectionRawData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var detectionRawData = new DetectionRawDataModel
|
|
|
+ {
|
|
|
+ PacketNumber = byteTransform.TransUInt32(bytes, 0),
|
|
|
+ TotalPackets = byteTransform.TransUInt32(bytes, 4),
|
|
|
+ DataLength = byteTransform.TransUInt16(bytes, 8),
|
|
|
+ Data = bytes.Skip(10).ToArray() // 跳过前10个字节
|
|
|
+ };
|
|
|
+
|
|
|
+ return detectionRawData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送开启实时流数据命令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="isOpen">是否开启</param>
|
|
|
+ /// <param name="serialNo">设备序列号</param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendTurnLiveStreamData(bool isOpen, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte((byte)(isOpen ? 1 : 0)); // 0=关闭,1=开启
|
|
|
+ byte[] buffer = CreateData(0x0C, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"{(isOpen ? "开启" : "关闭")}设备实时流", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送开启实时流数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送获取判伤捻距系数数据命令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendGetTwistFactorData(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0x00); // 操作,0=获取判伤捻距系数,1=设置判伤捻距系数
|
|
|
+ WriteBytes(ms, 0); // 判伤捻距系数
|
|
|
+ byte[] buffer = CreateData(0x13, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this,
|
|
|
+ new DebugMessageReceivedEventArgs($"获取设备判伤捻距系数", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送获取判伤捻距系数数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 设置判伤捻距系数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="twistFactor"></param>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="stream"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendSetTwistFactorData(float twistFactor, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0x01); // 操作,0=获取判伤捻距系数,1=设置判伤捻距系数
|
|
|
+ WriteBytes(ms, twistFactor); // 判伤捻距系数
|
|
|
+ byte[] buffer = CreateData(0x13, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"设置设备判伤捻距系数", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送设置判伤捻距系数数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 返回编码器方向
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public EncoderDirectionDataModel ReceiveEncoderDirectionData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var encoderDirection = new EncoderDirectionDataModel
|
|
|
+ {
|
|
|
+ Code = bytes[0],
|
|
|
+ Type = bytes[1],
|
|
|
+ Direction = (EncoderDirection)bytes[2] // 编码器方向,1=正向,2=反向
|
|
|
+ };
|
|
|
+ return encoderDirection;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收返回系统时钟数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public ClockDataModel ReceiveClockData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ ClockDataModel clockData = new ClockDataModel
|
|
|
+ {
|
|
|
+ Code = bytes[0],
|
|
|
+ Type = bytes[1],
|
|
|
+ Time = byteTransform.TransInt32(bytes, 2)
|
|
|
+ };
|
|
|
+ return clockData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 主板复位应答
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public ResetSystemDataModel ReceiveResetSystemData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var resetSystemData = new ResetSystemDataModel
|
|
|
+ {
|
|
|
+ Code = bytes[0]
|
|
|
+ };
|
|
|
+ return resetSystemData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 设置当前实时位置应答
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public SetAbsolutePositionDataModel ReceiveSetAbsolutePositionData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ var setAbsolutePositionData = new SetAbsolutePositionDataModel
|
|
|
+ {
|
|
|
+ Code = bytes[0]
|
|
|
+ };
|
|
|
+ return setAbsolutePositionData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送获取时钟数据命令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="stream"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendGetClockData(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0x00); // 操作,0=获取时钟,1=设置时钟
|
|
|
+ WriteBytes(ms, 0);// 设置时间戳
|
|
|
+ byte[] buffer = CreateData(0x10, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"获取设备时钟", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送获取时钟数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送设置时钟数据命令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="timestamp">时间戳</param>
|
|
|
+ /// <param name="serialNo">序列号</param>
|
|
|
+ /// <param name="stream">网络数据流</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendSetClockData(int timestamp, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(0x01); // 操作,0=获取时钟,1=设置时钟
|
|
|
+ WriteBytes(ms, timestamp);// 设置时间戳
|
|
|
+ byte[] buffer = CreateData(0x10, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"设置设备时钟", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送设置时钟数据命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收实时数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public RealTimeDataModel ReceiveRealTimeData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ RealTimeDataModel realTimeData = new RealTimeDataModel
|
|
|
+ {
|
|
|
+ Status = (RunningStatus)bytes[0],
|
|
|
+ Speed = byteTransform.TransSingle(bytes, 1),
|
|
|
+ AbsolutePosition = byteTransform.TransSingle(bytes, 5),
|
|
|
+ Position = byteTransform.TransSingle(bytes, 9)
|
|
|
+ };
|
|
|
+ return realTimeData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收检测结果
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public DetectionDataModel ReceiveDetectionData(byte[] buffer)
|
|
|
+ {
|
|
|
+ var verifyData = GetVerifyDataAndCheckCaption(buffer);
|
|
|
+ if (!verifyData.IsValid)
|
|
|
+ {
|
|
|
+ LogHelper.Error("接收检测结果时验证码校验失败");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ var data = verifyData.Data;
|
|
|
+ DetectionDataModel detectionData = new DetectionDataModel
|
|
|
+ {
|
|
|
+ StartTime = byteTransform.TransInt32(data, 0),
|
|
|
+ EndTime = byteTransform.TransInt32(data, 4),
|
|
|
+ StartPoint = byteTransform.TransSingle(data, 8),
|
|
|
+ EndPoint = byteTransform.TransSingle(data, 12),
|
|
|
+ DetectionLength = byteTransform.TransSingle(data, 16),
|
|
|
+ DetectedSpeed = byteTransform.TransSingle(data, 20),
|
|
|
+ DamageCount = byteTransform.TransInt16(data, 24),
|
|
|
+ Damages = new List<DamageModel>()
|
|
|
+ };
|
|
|
+ for (int i = 0; i < detectionData.DamageCount; i++)
|
|
|
+ {
|
|
|
+ int offset = 26 + i * 10; // 每个损伤数据占8字节
|
|
|
+ if (offset + 10 > data.Length) break; // 防止越界
|
|
|
+ var damageData = new DamageModel
|
|
|
+ {
|
|
|
+ RopeNumber = data[offset],
|
|
|
+ DamagePoint = byteTransform.TransSingle(data, offset + 1),
|
|
|
+ DamageValue = byteTransform.TransSingle(data, offset + 5),
|
|
|
+ DamageLevel = (DamageLevel)data[offset + 9]
|
|
|
+ };
|
|
|
+ detectionData.Damages.Add(damageData);
|
|
|
+ }
|
|
|
+ return detectionData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收损伤信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public AlarmDataModel ReceiveAlarmData(byte[] buffer)
|
|
|
+ {
|
|
|
+ var verifyData = GetVerifyDataAndCheckCaption(buffer);
|
|
|
+ if (!verifyData.IsValid)
|
|
|
+ {
|
|
|
+ LogHelper.Error("接收同步参数时验证码校验失败");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ var data = verifyData.Data;
|
|
|
+ AlarmDataModel alarmData = new AlarmDataModel
|
|
|
+ {
|
|
|
+ RopeNumber = data[1],
|
|
|
+ DamagePosition = byteTransform.TransSingle(data, 2),
|
|
|
+ DamageValue = byteTransform.TransSingle(data, 6),
|
|
|
+ DamageLevel = (DamageLevel)data[10]
|
|
|
+ };
|
|
|
+ return alarmData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收故障信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public FaultDataModel ReceiveFaultData(byte[] buffer)
|
|
|
+ {
|
|
|
+ var verifyData = GetVerifyDataAndCheckCaption(buffer);
|
|
|
+ if (!verifyData.IsValid)
|
|
|
+ {
|
|
|
+ LogHelper.Error("接收设备故障时验证码校验失败");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ FaultDataModel faultData = new FaultDataModel();
|
|
|
+ var data = verifyData.Data;
|
|
|
+ faultData.FaultType = (FaultType)data[0];
|
|
|
+
|
|
|
+ return faultData;
|
|
|
+ }
|
|
|
+ public byte ReceiveStartOrStopDetectionResultData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ return bytes[0];
|
|
|
+ }
|
|
|
+ public byte ReceiveUpgradedResultData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ return bytes[0];
|
|
|
+ }
|
|
|
+ public byte ReceiveChangeSerialNoResultData(byte[] buffer)
|
|
|
+ {
|
|
|
+ (string serialNo, byte[] bytes) = GetSerialNoAndData(buffer);
|
|
|
+ return bytes[0];
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 回复心跳
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private void RespondHeartbeat(byte[] buffer, string ipAddress, Socket clientSocket)
|
|
|
+ {
|
|
|
+ if (buffer[1] == 0x00)
|
|
|
+ {
|
|
|
+ byte[] response = new byte[] { 0xD0, 0x00 };
|
|
|
+ clientSocket.Send(response); // 直接使用Socket发送
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private async Task ProcessSerialNoData(byte[] buffer, ClientState client)
|
|
|
+ {
|
|
|
+ byte code = ReceiveChangeSerialNoResultData(buffer);
|
|
|
+ if (code == 0)
|
|
|
+ {
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"修改设备序列号成功", serialNo: client.SerialNo));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LogHelper.Error($"修改设备序列号结果失败,原因码:{code}");
|
|
|
+ }
|
|
|
+ await Task.CompletedTask;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 接收同步参数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public (string SerialNo, ParameterModel Parameter) ReceiveSyncParameters(byte[] buffer)
|
|
|
+ {
|
|
|
+ ParameterModel parameterData = new ParameterModel();
|
|
|
+ var verifyData = GetVerifyDataAndCheckCaption(buffer);
|
|
|
+ if (!verifyData.IsValid)
|
|
|
+ {
|
|
|
+ LogHelper.Error("接收同步参数时验证码校验失败");
|
|
|
+ return (null, null);
|
|
|
+ }
|
|
|
+ byte[] data = verifyData.Data;
|
|
|
+ int index = 0;
|
|
|
+
|
|
|
+ #region 主板软件版本号
|
|
|
+ short versionLength = data[index]; index += 1;
|
|
|
+ if (data.Length - index < versionLength)
|
|
|
+ return (null, null);
|
|
|
+
|
|
|
+ parameterData.MainBoardSoftwareVersion = Encoding.ASCII.GetString(data.Skip(index).Take(versionLength).ToArray());
|
|
|
+ index += versionLength;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 基础参数
|
|
|
+ parameterData.SensorCount = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.SamplingStep = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ parameterData.FrequencyDivisionFactor = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.TimeDomainFrequency = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 判伤参数
|
|
|
+ parameterData.DamageThreshold = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.ScrapUpperLimit = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.FrontMagnetLength = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.BackMagnetLength = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.ValueCoefficient = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 零点位参数
|
|
|
+ parameterData.EffectiveStrokeLength = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ parameterData.ZeroPositionCorrectionDuration = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.ZeroPositionCorrectionOffset = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 报警参数
|
|
|
+ parameterData.WarningValue = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ parameterData.AlarmValue = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ parameterData.SoundLightAlarmAutoResetMode = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 钢丝绳信息
|
|
|
+ parameterData.WireRopeType = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.WireRopeCount = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.WireRopeLength = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ parameterData.WireRopeDiameter = byteTransform.TransSingle(data, index); index += 4;
|
|
|
+ parameterData.WireRopeStrandCount = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ parameterData.WireRopeStrandWireCount = byteTransform.TransInt16(data, index); index += 2;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ return (verifyData.SerialNo, parameterData);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送同步参数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="parameterData"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendSyncParameters(ParameterModel parameters, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ // Basic parameters
|
|
|
+ WriteBytes(ms, parameters.SensorCount);
|
|
|
+ WriteBytes(ms, parameters.SamplingStep);
|
|
|
+ WriteBytes(ms, parameters.FrequencyDivisionFactor);
|
|
|
+ WriteBytes(ms, parameters.TimeDomainFrequency);
|
|
|
+
|
|
|
+ // Damage judgment parameters
|
|
|
+ WriteBytes(ms, parameters.DamageThreshold);
|
|
|
+ WriteBytes(ms, parameters.ScrapUpperLimit);
|
|
|
+ WriteBytes(ms, parameters.FrontMagnetLength);
|
|
|
+ WriteBytes(ms, parameters.BackMagnetLength);
|
|
|
+ WriteBytes(ms, parameters.ValueCoefficient);
|
|
|
+
|
|
|
+ // Zero position parameters
|
|
|
+ WriteBytes(ms, parameters.EffectiveStrokeLength);
|
|
|
+ WriteBytes(ms, parameters.ZeroPositionCorrectionDuration);
|
|
|
+ WriteBytes(ms, parameters.ZeroPositionCorrectionOffset);
|
|
|
+
|
|
|
+ // Alarm parameters
|
|
|
+ WriteBytes(ms, parameters.WarningValue);
|
|
|
+ WriteBytes(ms, parameters.AlarmValue);
|
|
|
+ WriteBytes(ms, (ushort)parameters.SoundLightAlarmAutoResetMode);
|
|
|
+
|
|
|
+ // Wire rope info
|
|
|
+ WriteBytes(ms, parameters.WireRopeType);
|
|
|
+ WriteBytes(ms, parameters.WireRopeCount);
|
|
|
+ WriteBytes(ms, parameters.WireRopeLength);
|
|
|
+ WriteBytes(ms, parameters.WireRopeDiameter);
|
|
|
+ WriteBytes(ms, parameters.WireRopeStrandCount);
|
|
|
+ WriteBytes(ms, parameters.WireRopeStrandWireCount);
|
|
|
+
|
|
|
+ var buffer = CreateData(0x02, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"同步设备参数", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送同步参数时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送开始或停止检测命令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="isStart">是否开始</param>
|
|
|
+ /// <param name="serialNo">设备序列号</param>
|
|
|
+ /// <param name="clientSocket">数据流</param>
|
|
|
+ public bool SendStartOrStopDetection(bool isStart, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte((byte)(isStart ? 1 : 0)); // 0=停止检测,1=开始检测
|
|
|
+ byte[] buffer = CreateData(0x06, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"{(isStart ? "开始" : "停止")}设备检测", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送开始或停止检测命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送修改设备序列号请求
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo">设备序列号</param>
|
|
|
+ /// <param name="clientSocket">数据流</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendSerialNoRequest(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected || serialNo.IsNullOrEmpty())
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ byte[] serialNoBytes = Encoding.UTF8.GetBytes(serialNo);
|
|
|
+ ms.WriteByte((byte)serialNoBytes.Length); // 序列号长度
|
|
|
+ ms.Write(serialNoBytes, 0, serialNoBytes.Length); // 序列号
|
|
|
+ byte[] buffer = CreateData(0x16, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"请求修改设备序列号", serialNo: null));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送设备序列号请求命令时错误", ex);
|
|
|
+ return false;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送程序更新请求
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo">设备序列号</param>
|
|
|
+ /// <param name="clientSocket">数据流</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendUpgradeRequest(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(1);
|
|
|
+ byte[] buffer = CreateData(0x11, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"发起程序更新请求", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送程序更新请求命令时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送开始或停止实时数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="isOpen">是否开启</param>
|
|
|
+ /// <param name="serialNo">序列号</param>
|
|
|
+ /// <param name="clientSocket"></param>
|
|
|
+ public void SendOpenOrClosedRealtimeData(bool isOpen, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return;
|
|
|
+
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte((byte)(isOpen ? 1 : 0)); // 0=关闭,1=开启
|
|
|
+ byte[] buffer = CreateData(0x06, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"{(isOpen ? "开启" : "停止")}设备实时数据", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送开始或停止实时数据命令时错误", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void SafeCloseClient(ClientState client)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(client.ClientSocket, client.IpAddress));
|
|
|
+ _connectedClients.TryRemove(client.IpAddress, out _);
|
|
|
+ if (client.ClientSocket?.Connected == true)
|
|
|
+ {
|
|
|
+ client.ClientSocket?.Shutdown(SocketShutdown.Both);
|
|
|
+ client.ClientSocket?.Close();
|
|
|
+ client.ClientSocket?.Dispose();
|
|
|
+ client.ClientSocket = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ Console.WriteLine($"关闭Socket时错误: {ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void WriteBytes(MemoryStream ms, dynamic value)
|
|
|
+ {
|
|
|
+ var bytes = byteTransform.TransByte(value);
|
|
|
+ ms.Write(bytes, 0, bytes.Length);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送检测结果确认
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="parameterData"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendDetectionConfirm(int startTime, int endTime, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ WriteBytes(ms, startTime);
|
|
|
+ WriteBytes(ms, endTime);
|
|
|
+
|
|
|
+ byte[] buffer = CreateData(0x09, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"确认设备检测结果", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送检测结果确认时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送主板复位请求
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="serialNo"></param>
|
|
|
+ /// <param name="clientSocket"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendResetSystemData(string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ byte[] buffer = CreateData(0x14, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"发送主板复位请求", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送主板复位请求时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 发送设置当前实时位置
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool SendRealTimeAbsolutePositionData(float absolutePosition, string serialNo, Socket clientSocket)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (clientSocket == null || !clientSocket.Connected)
|
|
|
+ return false;
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ ms.WriteByte(1);// 1=设置当前实时位置
|
|
|
+ WriteBytes(ms, absolutePosition);
|
|
|
+ byte[] buffer = CreateData(0x15, ms.ToArray(), serialNo);
|
|
|
+ DebugMessageReceived?.Invoke(this, new DebugMessageReceivedEventArgs($"发送设置当前实时位置请求", serialNo: serialNo));
|
|
|
+ clientSocket.Send(buffer);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error("发送设置当前实时位置请求时错误", ex);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取数据并验证验证码
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="buffer">数据</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private VerifyDataModel GetVerifyDataAndCheckCaption(byte[] buffer)
|
|
|
+ {
|
|
|
+ VerifyDataModel verifyData = new VerifyDataModel() { Password = PASSWORD };
|
|
|
+ // 使用Span直接操作内存
|
|
|
+ Span<byte> span = buffer.AsSpan();
|
|
|
+
|
|
|
+ // 移除事件类型
|
|
|
+ span = span.Slice(1);
|
|
|
+
|
|
|
+ // 读取序列号长度
|
|
|
+ if (span.IsEmpty) return verifyData;
|
|
|
+ int serialNoLength = span[0];
|
|
|
+
|
|
|
+ // 读取序列号
|
|
|
+ if (span.Length - 1 < serialNoLength) return verifyData;
|
|
|
+ verifyData.SerialNo = SoftBasic.GetAsciiStringRender(span.Slice(1, serialNoLength).ToArray());
|
|
|
+ span = span.Slice(1 + serialNoLength);
|
|
|
+
|
|
|
+ // 读取随机码
|
|
|
+ if (span.Length < 4) return verifyData;
|
|
|
+ verifyData.RandomCode = byteTransform.TransUInt32(span.ToArray(), 0);
|
|
|
+ span = span.Slice(4);
|
|
|
+
|
|
|
+ // 读取验证码长度
|
|
|
+ if (span.IsEmpty) return verifyData;
|
|
|
+ int captchaLength = span[0];
|
|
|
+
|
|
|
+ // 验证验证码
|
|
|
+ if (span.Length - 1 < captchaLength) return verifyData;
|
|
|
+ verifyData.Captcha = SoftBasic.AsciiBytesToBytes(span.Slice(1, captchaLength).ToArray());
|
|
|
+
|
|
|
+ // 截取剩余数据
|
|
|
+ verifyData.Data = span.Slice(captchaLength + 1).ToArray();
|
|
|
+
|
|
|
+ // 校验验证码
|
|
|
+ verifyData.IsValid = VerifyCaptcha(verifyData);
|
|
|
+
|
|
|
+ return verifyData;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 验证码校验
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private static bool VerifyCaptcha(VerifyDataModel verifyData)
|
|
|
+ {
|
|
|
+ byte[] computedHash;
|
|
|
+ using (var md5 = MD5.Create())
|
|
|
+ {
|
|
|
+ computedHash = md5.ComputeHash(Encoding.UTF8.GetBytes(verifyData.SerialNo + verifyData.Password + verifyData.RandomCode));
|
|
|
+ }
|
|
|
+ var buffer = verifyData.Captcha;
|
|
|
+ for (int i = 0; i < 16; i++)
|
|
|
+ {
|
|
|
+ if (buffer[i] != computedHash[i])
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ ///<summary>
|
|
|
+ ///创建数据验证码
|
|
|
+ ///</summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ protected byte[] CreateData(byte eventType, byte[] data, string serialNo)
|
|
|
+ {
|
|
|
+ using (var md5 = MD5.Create())
|
|
|
+ {
|
|
|
+ using (var ms = new MemoryStream())
|
|
|
+ {
|
|
|
+ // 1. 预先计算所有字段的长度
|
|
|
+ uint randomCode = (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
|
+ byte[] randomCodeBytes = byteTransform.TransByte(randomCode);
|
|
|
+ byte[] hash = md5.ComputeHash(Encoding.ASCII.GetBytes(serialNo + PASSWORD + randomCode));
|
|
|
+ byte[] captcha = SoftBasic.BytesToAsciiBytes(hash);
|
|
|
+
|
|
|
+ // 2. 正确计算剩余长度(关键修正点)
|
|
|
+ // 剩余长度 = 事件类型(1) + 序列号长度(1) + 序列号数据 + 随机码 + 验证码长度(1) + 验证码 + 用户数据
|
|
|
+ short remainingLength = (short)(
|
|
|
+ 1 + // eventType
|
|
|
+ randomCodeBytes.Length + // 随机码(固定4字节)
|
|
|
+ 1 + captcha.Length + // 验证码(长度字节 + 数据)
|
|
|
+ data.Length // 用户数据
|
|
|
+ );
|
|
|
+
|
|
|
+ // 3. 写入头部(0x30 + 剩余长度)
|
|
|
+ ms.WriteByte(0x30);
|
|
|
+ if (remainingLength <= 127)
|
|
|
+ {
|
|
|
+ ms.WriteByte((byte)remainingLength); // 单字节表示
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 假设byteTransform.TransByte将short转为2字节大端序
|
|
|
+ byte[] remainingLengthBytes = byteTransform.TransByte(remainingLength);
|
|
|
+ ms.Write(remainingLengthBytes, 0, remainingLengthBytes.Length);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 写入各字段(保持原逻辑)
|
|
|
+ ms.WriteByte(eventType);
|
|
|
+ ms.Write(randomCodeBytes, 0, randomCodeBytes.Length);
|
|
|
+ ms.WriteByte((byte)captcha.Length);
|
|
|
+ ms.Write(captcha, 0, captcha.Length);
|
|
|
+ ms.Write(data, 0, data.Length);
|
|
|
+
|
|
|
+ return ms.ToArray();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public ushort[][] ParseSensorData(byte[] data, int sensorCount, int sampleCount)
|
|
|
+ {
|
|
|
+ // 检查数据长度是否匹配
|
|
|
+ int expectedLength = sensorCount * sampleCount;
|
|
|
+ if (data.Length != expectedLength)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"数据长度不匹配。预期 {expectedLength} 字节,实际 {data.Length} 字节。");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化结果列表,每个传感器的数据存储在一个单独的 ushort[]
|
|
|
+ ushort[][] sensorDataList = new ushort[sampleCount][];
|
|
|
+ for (int i = 0; i < sampleCount; i++)
|
|
|
+ {
|
|
|
+ sensorDataList[i] = new ushort[sensorCount];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析数据
|
|
|
+ for (int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
|
|
|
+ {
|
|
|
+ for (int sensorIndex = 0; sensorIndex < sensorCount; sensorIndex++)
|
|
|
+ {
|
|
|
+ // 计算数据在字节数组中的位置
|
|
|
+ int dataIndex = (sampleIndex * sensorCount) + sensorIndex;
|
|
|
+ // 将 byte 转换为 ushort(直接赋值,因为 byte 可以隐式转换为 ushort)
|
|
|
+ sensorDataList[sampleIndex][sensorIndex] = data[dataIndex];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sensorDataList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取剩余长度
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="bytes"></param>
|
|
|
+ /// <param name="startIndex"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static (int BytesConsumed, int Length) GetRemainingLength(byte[] bytes)
|
|
|
+ {
|
|
|
+ if (bytes == null || bytes.Length < 2) return (0, 0);
|
|
|
+
|
|
|
+ int index = 1; // 跳过包类型字节
|
|
|
+ int multiplier = 1;
|
|
|
+ int value = 0;
|
|
|
+ byte encodedByte;
|
|
|
+ int bytesConsumed = 0;
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if (index >= bytes.Length) return (0, 0);
|
|
|
+
|
|
|
+ encodedByte = bytes[index];
|
|
|
+ value += (encodedByte & 0x7F) * multiplier;
|
|
|
+ multiplier *= 128;
|
|
|
+ index++;
|
|
|
+ bytesConsumed++;
|
|
|
+
|
|
|
+ if (multiplier > 128 * 128 * 128) // 防止溢出
|
|
|
+ return (0, 0);
|
|
|
+
|
|
|
+ } while ((encodedByte & 0x80) != 0 && bytesConsumed < 4); // 最多4字节长度
|
|
|
+
|
|
|
+ return (bytesConsumed, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static (string SerialNo, byte[] Bytes) GetSerialNoAndData(byte[] buffer)
|
|
|
+ {
|
|
|
+ // 使用Span直接操作内存
|
|
|
+ Span<byte> span = buffer.AsSpan();
|
|
|
+
|
|
|
+ // 移除事件类型
|
|
|
+ span = span.Slice(1);
|
|
|
+
|
|
|
+ // 读取序列号长度
|
|
|
+ if (span.IsEmpty) return (null, null);
|
|
|
+ int serialNoLength = span[0];
|
|
|
+
|
|
|
+ // 读取序列号
|
|
|
+ if (span.Length - 1 < serialNoLength) return (null, null);
|
|
|
+
|
|
|
+ var serialNo = SoftBasic.GetAsciiStringRender(span.Slice(1, serialNoLength).ToArray());
|
|
|
+ buffer = span.Slice(1 + serialNoLength).ToArray();
|
|
|
+
|
|
|
+ return (serialNo, buffer);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ _isRunning = false;
|
|
|
+ Thread.Sleep(100);
|
|
|
+ if (_listener != null)
|
|
|
+ {
|
|
|
+ if (_listener.Connected)
|
|
|
+ {
|
|
|
+ _listener.Shutdown(SocketShutdown.Both);
|
|
|
+ }
|
|
|
+ _listener.Close();
|
|
|
+ _listener.Dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (SocketException ex) when (ex.SocketErrorCode == SocketError.NotConnected)
|
|
|
+ {
|
|
|
+ _listener?.Dispose();
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"停止服务时发生异常: {ex.Message}", ex);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ _listener = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|