diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.Designer.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.Designer.cs index a27acbe..7cba02f 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.Designer.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.Designer.cs @@ -15,12 +15,25 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.imageBox = new System.Windows.Forms.PictureBox(); + this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); + this.colorModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.whiteHotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.blackHotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ironRedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.lavaToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.rainbowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ironGrayToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.redHotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.rainbow2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.imageBox)).BeginInit(); + this.contextMenuStrip1.SuspendLayout(); this.SuspendLayout(); // // imageBox // + this.imageBox.ContextMenuStrip = this.contextMenuStrip1; this.imageBox.Dock = System.Windows.Forms.DockStyle.Fill; this.imageBox.Location = new System.Drawing.Point(0, 0); this.imageBox.Name = "imageBox"; @@ -29,6 +42,86 @@ this.imageBox.TabIndex = 0; this.imageBox.TabStop = false; // + // contextMenuStrip1 + // + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.colorModeToolStripMenuItem}); + this.contextMenuStrip1.Name = "contextMenuStrip1"; + this.contextMenuStrip1.Size = new System.Drawing.Size(161, 48); + // + // colorModeToolStripMenuItem + // + this.colorModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.whiteHotToolStripMenuItem, + this.blackHotToolStripMenuItem, + this.ironRedToolStripMenuItem, + this.lavaToolStripMenuItem, + this.rainbowToolStripMenuItem, + this.ironGrayToolStripMenuItem, + this.redHotToolStripMenuItem, + this.rainbow2ToolStripMenuItem}); + this.colorModeToolStripMenuItem.Name = "colorModeToolStripMenuItem"; + this.colorModeToolStripMenuItem.Size = new System.Drawing.Size(160, 22); + this.colorModeToolStripMenuItem.Text = "色彩模式"; + // + // rainbowToolStripMenuItem + // + this.rainbowToolStripMenuItem.Name = "rainbowToolStripMenuItem"; + this.rainbowToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.rainbowToolStripMenuItem.Text = "彩虹"; + this.rainbowToolStripMenuItem.Click += new System.EventHandler(this.rainbowToolStripMenuItem_Click); + // + // ironRedToolStripMenuItem + // + this.ironRedToolStripMenuItem.Name = "ironRedToolStripMenuItem"; + this.ironRedToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.ironRedToolStripMenuItem.Text = "铁红"; + this.ironRedToolStripMenuItem.Click += new System.EventHandler(this.ironRedToolStripMenuItem_Click); + // + // lavaToolStripMenuItem + // + this.lavaToolStripMenuItem.Name = "lavaToolStripMenuItem"; + this.lavaToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.lavaToolStripMenuItem.Text = "熔岩"; + this.lavaToolStripMenuItem.Click += new System.EventHandler(this.lavaToolStripMenuItem_Click); + // + // ironGrayToolStripMenuItem + // + this.ironGrayToolStripMenuItem.Name = "ironGrayToolStripMenuItem"; + this.ironGrayToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.ironGrayToolStripMenuItem.Text = "铁灰"; + this.ironGrayToolStripMenuItem.Click += new System.EventHandler(this.ironGrayToolStripMenuItem_Click); + // + // redHotToolStripMenuItem + // + this.redHotToolStripMenuItem.Name = "redHotToolStripMenuItem"; + this.redHotToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.redHotToolStripMenuItem.Text = "红热"; + this.redHotToolStripMenuItem.Click += new System.EventHandler(this.redHotToolStripMenuItem_Click); + // + // rainbow2ToolStripMenuItem + // + this.rainbow2ToolStripMenuItem.Name = "rainbow2ToolStripMenuItem"; + this.rainbow2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.rainbow2ToolStripMenuItem.Text = "彩虹2"; + this.rainbow2ToolStripMenuItem.Click += new System.EventHandler(this.rainbow2ToolStripMenuItem_Click); + // + // whiteHotToolStripMenuItem + // + this.whiteHotToolStripMenuItem.Name = "whiteHotToolStripMenuItem"; + this.whiteHotToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.whiteHotToolStripMenuItem.Text = "白热"; + this.whiteHotToolStripMenuItem.Click += new System.EventHandler(this.whiteHotToolStripMenuItem_Click); + // + // blackHotToolStripMenuItem + // + this.blackHotToolStripMenuItem.Name = "blackHotToolStripMenuItem"; + this.blackHotToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.blackHotToolStripMenuItem.Text = "黑热"; + this.blackHotToolStripMenuItem.Click += new System.EventHandler(this.blackHotToolStripMenuItem_Click); + // + // 已移除蓝红菜单项(不在SDK的8种标准色板中) + // // Camera // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); @@ -38,6 +131,7 @@ this.Size = new System.Drawing.Size(512, 384); this.Load += new System.EventHandler(this.Camera_Load); ((System.ComponentModel.ISupportInitialize)(this.imageBox)).EndInit(); + this.contextMenuStrip1.ResumeLayout(false); this.ResumeLayout(false); } @@ -45,5 +139,15 @@ #endregion private System.Windows.Forms.PictureBox imageBox; + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem colorModeToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem whiteHotToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem blackHotToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem ironRedToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem lavaToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem rainbowToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem ironGrayToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem redHotToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem rainbow2ToolStripMenuItem; } } diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs index b052b60..3eea4bc 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs @@ -853,6 +853,162 @@ namespace JoyD.Windows.CS.Toprie } } + #region 色彩模式切换方法 + + /// + /// 白热色彩模式 + /// + private void whiteHotToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到白热色彩模式"); + _deviceManager.SetPaletteType(PaletteType.WhiteHot); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到白热色彩模式失败: {ex.Message}"); + } + } + + /// + /// 黑热色彩模式 + /// + private void blackHotToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到黑热色彩模式"); + _deviceManager.SetPaletteType(PaletteType.BlackHot); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到黑热色彩模式失败: {ex.Message}"); + } + } + + /// + /// 铁红色彩模式 + /// + private void ironRedToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到铁红色彩模式"); + _deviceManager.SetPaletteType(PaletteType.IronRed); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到铁红色彩模式失败: {ex.Message}"); + } + } + + /// + /// 熔岩色彩模式 + /// + private void lavaToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到熔岩色彩模式"); + _deviceManager.SetPaletteType(PaletteType.Lava); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到熔岩色彩模式失败: {ex.Message}"); + } + } + + /// + /// 彩虹色彩模式 + /// + private void rainbowToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到彩虹色彩模式"); + _deviceManager.SetPaletteType(PaletteType.Rainbow); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到彩虹色彩模式失败: {ex.Message}"); + } + } + + /// + /// 铁灰色彩模式 + /// + private void ironGrayToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到铁灰色彩模式"); + _deviceManager.SetPaletteType(PaletteType.IronGray); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到铁灰色彩模式失败: {ex.Message}"); + } + } + + /// + /// 红热色彩模式 + /// + private void redHotToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到红热色彩模式"); + _deviceManager.SetPaletteType(PaletteType.RedHot); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到红热色彩模式失败: {ex.Message}"); + } + } + + /// + /// 彩虹2色彩模式 + /// + private void rainbow2ToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + if (_deviceManager != null) + { + Console.WriteLine("切换到彩虹2色彩模式"); + _deviceManager.SetPaletteType(PaletteType.Rainbow2); + } + } + catch (Exception ex) + { + Console.WriteLine($"切换到彩虹2色彩模式失败: {ex.Message}"); + } + } + + #endregion + /// /// 清理资源 /// diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs index 0d8b01e..3d356ba 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs @@ -37,6 +37,22 @@ namespace JoyD.Windows.CS.Toprie Fusion } + /// + /// 色彩模式枚举 + /// 对应SDK文档中的8种色板模式:白热、黑热、铁红、熔岩、彩虹、铁灰、红热、彩虹2 + /// + public enum PaletteType + { + WhiteHot, // 白热,对应SDK参数0 + BlackHot, // 黑热,对应SDK参数1 + IronRed, // 铁红,对应SDK参数2 + Lava, // 熔岩,对应SDK参数3 + Rainbow, // 彩虹,对应SDK参数4 + IronGray, // 铁灰,对应SDK参数5 + RedHot, // 红热,对应SDK参数6 + Rainbow2 // 彩虹2,对应SDK参数7 + } + /// /// 连接状态改变事件参数 /// @@ -1711,6 +1727,32 @@ namespace JoyD.Windows.CS.Toprie CurrentImageMode = mode; } + /// + /// 设置色彩模式 + /// + /// 色彩模式 + public void SetPaletteType(PaletteType paletteType) + { + try + { + if (_a8Sdk != null) + { + // 将PaletteType枚举转换为int类型并发送命令 + // 按照SDK文档中的参数映射:白热(0)、黑热(1)、铁红(2)、熔岩(3)、彩虹(4)、铁灰(5)、红热(6)、彩虹2(7) + int paletteValue = (int)paletteType; + + // 尝试设置色彩模式 + _a8Sdk.Color_plate = paletteValue; + Console.WriteLine($"色彩模式设置成功: {paletteType} (值: {paletteValue})"); + } + } + catch (Exception ex) + { + Console.WriteLine($"设置色彩模式失败: {ex.Message}"); + // 发生异常时可以考虑恢复到之前的设置或记录错误 + } + } + /// /// 发送模式切换命令 /// diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj b/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj index fdd4ec2..817a1a5 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj @@ -73,6 +73,7 @@ + diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/UdpCommunicationManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/UdpCommunicationManager.cs new file mode 100644 index 0000000..615d5f5 --- /dev/null +++ b/Windows/CS/Framework4.0/Toprie/Toprie/UdpCommunicationManager.cs @@ -0,0 +1,341 @@ +using System; +using System.Collections.Generic; +using System.Net.Sockets; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace JoyD.Windows.CS.Toprie +{ + /// + /// UDP通信管理器,负责管理所有UDP通信,实现请求-响应匹配和状态管理 + /// 防止异步数据相互影响 + /// + public class UdpCommunicationManager : IDisposable + { + // 单例实例 + private static readonly UdpCommunicationManager _instance = new UdpCommunicationManager(); + + // 命令队列 + private readonly Queue _requestQueue = new Queue(); + + // 请求映射表,用于匹配请求和响应 + private readonly Dictionary _activeRequests = new Dictionary(); + + // 锁对象,保护共享资源 + private readonly object _queueLock = new object(); + private readonly object _requestLock = new object(); + + // UDP客户端实例 + private UdpClient _udpClient; + + // 工作线程 + private Thread _workerThread; + private bool _isRunning; + + // 信号量,用于通知工作线程有新请求 + private AutoResetEvent _requestAvailable = new AutoResetEvent(false); + + // 默认端口 + private const int DEFAULT_UDP_PORT = 18890; + + // 请求超时时间(毫秒) + private const int DEFAULT_TIMEOUT = 500; + + /// + /// 获取UdpCommunicationManager的单例实例 + /// + public static UdpCommunicationManager Instance => _instance; + + /// + /// 私有构造函数,初始化UDP通信管理器 + /// + private UdpCommunicationManager() + { + Initialize(); + } + + /// + /// 初始化UDP通信管理器 + /// + private void Initialize() + { + try + { + // 创建UDP客户端 + _udpClient = new UdpClient(); + _udpClient.Client.ReceiveTimeout = DEFAULT_TIMEOUT; + + // 启动工作线程 + _isRunning = true; + _workerThread = new Thread(ProcessRequests); + _workerThread.IsBackground = true; + _workerThread.Start(); + + Console.WriteLine("UDP通信管理器已初始化"); + } + catch (Exception ex) + { + Console.WriteLine($"UDP通信管理器初始化失败: {ex.Message}"); + } + } + + /// + /// 处理请求队列的工作线程函数 + /// + private void ProcessRequests() + { + while (_isRunning) + { + // 等待请求可用信号 + _requestAvailable.WaitOne(); + + if (!_isRunning) break; + + UdpRequest request = null; + + // 从队列中获取请求 + lock (_queueLock) + { + if (_requestQueue.Count > 0) + { + request = _requestQueue.Dequeue(); + } + } + + if (request != null) + { + // 处理请求 + ProcessRequest(request); + } + } + } + + /// + /// 处理单个UDP请求 + /// + /// UDP请求对象 + private void ProcessRequest(UdpRequest request) + { + try + { + Console.WriteLine($"处理UDP请求: {request.RequestId}, 目标: {request.TargetIp}:{request.Port}"); + + // 将请求添加到活动请求列表 + lock (_requestLock) + { + _activeRequests[request.RequestId] = request; + } + + // 发送UDP数据报 + _udpClient.Send(request.Data, request.Data.Length, request.TargetIp, request.Port); + Console.WriteLine($"UDP命令已发送: {Encoding.ASCII.GetString(request.Data)}"); + + // 启动异步接收响应 + IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + IAsyncResult ar = _udpClient.BeginReceive(result => + { + try + { + byte[] responseData = _udpClient.EndReceive(result, ref remoteEndPoint); + HandleResponse(request.RequestId, responseData); + } + catch (Exception ex) + { + Console.WriteLine($"接收UDP响应异常: {ex.Message}"); + HandleTimeout(request.RequestId); + } + }, null); + + // 设置超时处理(兼容.NET Framework 4.0) + ThreadPool.QueueUserWorkItem(state => + { + string requestId = (string)state; + Thread.Sleep(request.Timeout); + HandleTimeout(requestId); + }, request.RequestId); + } + catch (Exception ex) + { + Console.WriteLine($"处理UDP请求异常: {ex.Message}"); + request.OnResponse?.Invoke(null, true); // 通知请求失败 + + // 从活动请求列表中移除 + lock (_requestLock) + { + _activeRequests.Remove(request.RequestId); + } + } + } + + /// + /// 处理接收到的UDP响应 + /// + /// 请求ID + /// 响应数据 + private void HandleResponse(string requestId, byte[] responseData) + { + UdpRequest request = null; + + // 查找对应的请求 + lock (_requestLock) + { + if (_activeRequests.TryGetValue(requestId, out request)) + { + _activeRequests.Remove(requestId); + } + } + + if (request != null) + { + Console.WriteLine($"收到UDP响应: {requestId}, 长度: {responseData?.Length ?? 0}"); + request.OnResponse?.Invoke(responseData, false); // 通知请求成功 + } + } + + /// + /// 处理请求超时 + /// + /// 请求ID + private void HandleTimeout(string requestId) + { + UdpRequest request = null; + + // 查找对应的请求 + lock (_requestLock) + { + if (_activeRequests.TryGetValue(requestId, out request)) + { + _activeRequests.Remove(requestId); + } + } + + if (request != null) + { + Console.WriteLine($"UDP请求超时: {requestId}"); + request.OnResponse?.Invoke(null, true); // 通知请求超时 + } + } + + /// + /// 发送UDP请求 + /// + /// 目标IP地址 + /// 要发送的数据 + /// 目标端口,默认为18890 + /// 超时时间(毫秒),默认为500 + /// 包含响应数据的Task + public Task SendRequestAsync(string targetIp, byte[] data, int port = DEFAULT_UDP_PORT, int timeout = DEFAULT_TIMEOUT) + { + var tcs = new TaskCompletionSource(); + string requestId = Guid.NewGuid().ToString(); + + var request = new UdpRequest + { + RequestId = requestId, + TargetIp = targetIp, + Port = port, + Data = data, + Timeout = timeout, + OnResponse = (response, isTimeout) => + { + if (isTimeout) + { + tcs.TrySetResult(null); + } + else + { + tcs.TrySetResult(response); + } + } + }; + + // 将请求添加到队列 + lock (_queueLock) + { + _requestQueue.Enqueue(request); + } + + // 通知工作线程有新请求 + _requestAvailable.Set(); + + return tcs.Task; + } + + /// + /// 同步发送UDP请求 + /// + /// 目标IP地址 + /// 要发送的数据 + /// 目标端口,默认为18890 + /// 超时时间(毫秒),默认为500 + /// 响应数据,如果超时则返回null + public byte[] SendRequest(string targetIp, byte[] data, int port = DEFAULT_UDP_PORT, int timeout = DEFAULT_TIMEOUT) + { + try + { + var task = SendRequestAsync(targetIp, data, port, timeout); + task.Wait(timeout); + return task.Result; + } + catch (Exception ex) + { + Console.WriteLine($"同步发送UDP请求异常: {ex.Message}"); + return null; + } + } + + /// + /// 清理资源 + /// + public void Dispose() + { + _isRunning = false; + _requestAvailable.Set(); // 唤醒工作线程以便它可以退出 + + if (_workerThread != null && _workerThread.IsAlive) + { + _workerThread.Join(1000); // 等待工作线程退出 + } + + if (_udpClient != null) + { + _udpClient.Close(); + _udpClient = null; + } + + if (_requestAvailable != null) + { + _requestAvailable.Dispose(); + _requestAvailable = null; + } + + // 清空请求队列和活动请求 + lock (_queueLock) + { + _requestQueue.Clear(); + } + + lock (_requestLock) + { + _activeRequests.Clear(); + } + + Console.WriteLine("UDP通信管理器已释放"); + } + + /// + /// UDP请求类,封装单个UDP请求的信息 + /// + private class UdpRequest + { + public string RequestId { get; set; } + public string TargetIp { get; set; } + public int Port { get; set; } + public byte[] Data { get; set; } + public int Timeout { get; set; } + public Action OnResponse { get; set; } + } + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs b/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs index e45592e..6fc3661 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; -using System.Net.Sockets; using System.Text; +using System.Net.Sockets; +using System.Net; using System.Threading; using System.IO; using System.Runtime.InteropServices; -using System.Net; +// 导入UDP通信管理器 +using JoyD.Windows.CS.Toprie; namespace JoyD.Windows.CS.Toprie { @@ -187,25 +189,20 @@ namespace JoyD.Windows.CS.Toprie try { - // 修改为UDP协议,与SDK保持一致 - // SDK中使用的是UDP协议(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) - // 端口使用18890,与SDK中的CMD_SERVER_UDP_PORT保持一致 - using (UdpClient udpClient = new UdpClient()) + // 使用UDP通信管理器发送请求 + response = UdpCommunicationManager.Instance.SendRequest(deviceIp, command, 18890, 200); + + if (response != null) { - // 设置接收超时,与SDK中的超时保持一致 - udpClient.Client.ReceiveTimeout = 200; // SDK中普通命令超时为200ms - - // 发送UDP数据报,端口使用18890与SDK保持一致 - udpClient.Send(command, command.Length, deviceIp, 18890); Console.WriteLine($"UDP命令已发送到 {deviceIp}:18890"); - - // 尝试接收响应 - IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - response = udpClient.Receive(ref remoteEndPoint); - Console.WriteLine($"收到UDP命令响应,长度: {response.Length}"); return true; } + else + { + Console.WriteLine($"UDP命令发送后未收到响应或超时"); + return false; + } } catch (Exception ex) { @@ -221,28 +218,23 @@ namespace JoyD.Windows.CS.Toprie try { - // 修改为UDP协议,与SDK保持一致 - // SDK中使用的是UDP协议(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) - // 端口使用18890,与SDK中的CMD_SERVER_UDP_PORT保持一致 - using (UdpClient udpClient = new UdpClient()) + // 使用UDP通信管理器发送请求 + byte[] responseBytes = UdpCommunicationManager.Instance.SendRequest(deviceIp, + Encoding.ASCII.GetBytes(cmd), 18890, 200); + + if (responseBytes != null) { - // 设置接收超时,与SDK中的超时保持一致 - udpClient.Client.ReceiveTimeout = 200; // SDK中普通命令超时为200ms - - // 发送UDP数据报,端口使用18890与SDK保持一致 - byte[] commandBytes = Encoding.ASCII.GetBytes(cmd); - udpClient.Send(commandBytes, commandBytes.Length, deviceIp, 18890); + response = Encoding.ASCII.GetString(responseBytes); Console.WriteLine($"UDP命令已发送: {cmd}"); Console.WriteLine($"目标IP: {deviceIp}:18890"); - - // 尝试接收响应 - IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - byte[] responseBytes = udpClient.Receive(ref remoteEndPoint); - response = Encoding.ASCII.GetString(responseBytes); - Console.WriteLine($"收到UDP命令响应: {response}"); return true; } + else + { + Console.WriteLine($"UDP命令发送后未收到响应或超时: {cmd}"); + return false; + } } catch (Exception ex) @@ -1666,10 +1658,7 @@ namespace JoyD.Windows.CS.Toprie // 使用UDP协议发送心跳命令,与SDK保持一致 public int Heartbeat() { - // 关键修改:与SDK保持一致,使用UDP协议发送心跳命令 - // SDK中使用的是UDP协议(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) - // 之前的实现使用了TCP协议,这是心跳失败的根本原因 - // 端口修改为18890,与SDK中的CMD_SERVER_UDP_PORT保持一致 + // 使用UDP通信管理器进行心跳检测,防止异步数据相互影响 try { // 根据SDK实际实现,心跳命令格式是 +CMD:24$ @@ -1683,71 +1672,47 @@ namespace JoyD.Windows.CS.Toprie Console.WriteLine($"心跳命令: {command}"); Console.WriteLine($"目标IP: {deviceIp}:18890"); - using (UdpClient udpClient = new UdpClient()) + try { - try + // 使用UDP通信管理器发送心跳请求,设置500ms超时 + byte[] responseBytes = UdpCommunicationManager.Instance.SendRequest(deviceIp, + commandBytes, 18890, 500); + + Console.WriteLine("UDP心跳命令已发送,等待响应..."); + + if (responseBytes != null) { - // 注意:SDK中tv_out.tv_sec=50实际表示50秒,这是SDK的实现方式 - // 这里我们设置一个更合理的值500毫秒,既保证能接收到响应,又不会等待太久 - udpClient.Client.ReceiveTimeout = 500; + string response = Encoding.ASCII.GetString(responseBytes); - // 发送UDP数据报,端口使用18890与SDK保持一致 - udpClient.Send(commandBytes, commandBytes.Length, deviceIp, 18890); - Console.WriteLine("UDP心跳命令已发送,等待响应..."); - - // 尝试接收响应 - IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - // 使用BeginReceive和EndReceive进行非阻塞接收,更好地处理超时 - IAsyncResult ar = udpClient.BeginReceive(null, null); - if (ar.AsyncWaitHandle.WaitOne(500)) // 额外的超时检查,双重保险 + Console.WriteLine($"收到UDP心跳响应: {response}"); + // 不使用LINQ的Select方法,避免缺少System.Linq命名空间的问题 + string[] asciiValues = new string[response.Length]; + for (int i = 0; i < response.Length; i++) { - try - { - byte[] responseBytes = udpClient.EndReceive(ar, ref remoteEndPoint); - string response = Encoding.ASCII.GetString(responseBytes); - - Console.WriteLine($"收到UDP心跳响应: {response}"); - // 不使用LINQ的Select方法,避免缺少System.Linq命名空间的问题 - string[] asciiValues = new string[response.Length]; - for (int i = 0; i < response.Length; i++) - { - asciiValues[i] = ((int)response[i]).ToString(); - } - Console.WriteLine($"响应长度: {response.Length} 字节,响应ASCII码: {string.Join(",", asciiValues)}"); - - // SDK要求响应中必须包含 ":ok" 字符串才算成功 - if (!string.IsNullOrEmpty(response) && response.Contains(":ok")) - { - Console.WriteLine("心跳成功: 响应包含':ok'"); - return 1; // 返回1表示成功,与DeviceManager中的heartbeatResult > 0判断一致 - } - else - { - Console.WriteLine($"心跳响应不包含':ok',验证失败。收到的响应: '{response}'"); - } - } - catch (Exception ex) - { - Console.WriteLine($"处理UDP响应时发生异常: {ex.Message}"); - } + asciiValues[i] = ((int)response[i]).ToString(); + } + Console.WriteLine($"响应长度: {response.Length} 字节,响应ASCII码: {string.Join(",", asciiValues)}"); + + // SDK要求响应中必须包含 ":ok" 字符串才算成功 + if (!string.IsNullOrEmpty(response) && response.Contains(":ok")) + { + Console.WriteLine("心跳成功: 响应包含':ok'"); + return 1; // 返回1表示成功,与DeviceManager中的heartbeatResult > 0判断一致 } else { - Console.WriteLine("UDP接收超时,取消接收操作"); - udpClient.Close(); // 关闭以取消接收操作 + Console.WriteLine($"心跳响应不包含':ok',验证失败。收到的响应: '{response}'"); } } - catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut) + else { - // 超时异常,继续重试 - Console.WriteLine("UDP心跳接收超时"); - } - catch (Exception ex) - { - Console.WriteLine($"UDP心跳异常: {ex.Message}"); + Console.WriteLine("UDP心跳未收到响应或超时"); } } + catch (Exception ex) + { + Console.WriteLine($"UDP心跳异常: {ex.Message}"); + } // 如果不是最后一次尝试,短暂延迟后重试 if (retry < 2)