diff --git a/DeviceAdapter/DeviceAdapter.cs b/DeviceAdapter/DeviceAdapter.cs index a4a0bde..35e05dd 100644 --- a/DeviceAdapter/DeviceAdapter.cs +++ b/DeviceAdapter/DeviceAdapter.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; //using System.Collections.Generic; //using System.Linq; //using System.Text; @@ -228,6 +230,7 @@ namespace Mesnac.DeviceAdapter /// 1成功,2为通讯成功,设备未返回,3为发送失败 byte Device_SendHeartPack(); + Task Device_SendHeartPackAsync(CancellationToken cancellationToken = default); /// /// 获取自报数据 /// diff --git a/HighWayAssemble/App.config b/HighWayAssemble/App.config index 2ff0ef7..906dfec 100644 --- a/HighWayAssemble/App.config +++ b/HighWayAssemble/App.config @@ -9,7 +9,7 @@ - + diff --git a/HighWayAssemble/HighWayAssemble.csproj b/HighWayAssemble/HighWayAssemble.csproj index 86c8731..167ef6d 100644 --- a/HighWayAssemble/HighWayAssemble.csproj +++ b/HighWayAssemble/HighWayAssemble.csproj @@ -38,6 +38,9 @@ cloud_computing_128px_1222169_easyicon.net.ico + + + dll\CatLib.Core.dll diff --git a/HighWayAssemble/Main/EventSystem.cs b/HighWayAssemble/Main/EventSystem.cs index f1d1b2c..f9a0aaf 100644 --- a/HighWayAssemble/Main/EventSystem.cs +++ b/HighWayAssemble/Main/EventSystem.cs @@ -11,6 +11,7 @@ // public static string GetMesEquipList = "GetMesEquipList"; public static string UpdateMesListInfo = "UpdateMesListInfo"; + public static string updateEquipListInfoasyc = "updateEquipListInfoasyc"; public static string updateEquipListInfo = "updateEquipListInfo"; public static string updateSensorListInfo = "updateSensorListInfo"; diff --git a/HighWayAssemble/Main/FrmDisplayControl.cs b/HighWayAssemble/Main/FrmDisplayControl.cs index 54c1667..f6eb447 100644 --- a/HighWayAssemble/Main/FrmDisplayControl.cs +++ b/HighWayAssemble/Main/FrmDisplayControl.cs @@ -137,6 +137,7 @@ namespace HighWayAssemble App.TriggerHalt(EventSystem.AppClosed); App.Off(EventSystem.UpdateViewList); App.Off(EventSystem.UpdateMesListInfo); + App.Off(EventSystem.updateEquipListInfoasyc); App.Off(EventSystem.updateEquipListInfo); App.Off(EventSystem.updateSensorListInfo); App.Off(EventSystem.MessageBox); @@ -161,6 +162,11 @@ namespace HighWayAssemble { view.UpdateMesListView(mesinfo); }); + App.On(EventSystem.updateEquipListInfoasyc, (DeviceInfo state) => + { + view.equipState(state.m_iDeviceId.ToString(), state.m_ConnectState); + + }); App.On(EventSystem.updateEquipListInfo, (List state) => { for (int i = 0; i < state.Count; i++) diff --git a/HighWayAssemble/Main/FrmDisplayModel.cs b/HighWayAssemble/Main/FrmDisplayModel.cs index 1f67499..298b60f 100644 --- a/HighWayAssemble/Main/FrmDisplayModel.cs +++ b/HighWayAssemble/Main/FrmDisplayModel.cs @@ -329,8 +329,14 @@ namespace HighWayAssemble //发送传感器 m_EquipClient.SensorInfo(SoftInfo.SensorList); m_EquipClient.Init(); - //设备状态回调 - m_EquipClient.RecEquipState(async (state) => + m_EquipClient.RecEquipStateasyc(async (state) => + { + App.TriggerHalt(EventSystem.updateEquipListInfoasyc, state); + + + }); + //设备状态回调 + m_EquipClient.RecEquipState(async (state) => { App.TriggerHalt(EventSystem.updateEquipListInfo, state); for (int i = 0; i < state.Count; i++) diff --git a/HighWayAssemble/Protocol/MesHttpClient.cs b/HighWayAssemble/Protocol/MesHttpClient.cs index 2d8f52a..486c0df 100644 --- a/HighWayAssemble/Protocol/MesHttpClient.cs +++ b/HighWayAssemble/Protocol/MesHttpClient.cs @@ -45,7 +45,7 @@ namespace HighWayAssemble.Protocol } catch (Exception ex) { - FrmDisplayView.LogInfo.Error("ERROR: " + ex.Message); + FrmDisplayView.LogInfo.Fatal("MES接口连接异常: " + ex.Message); } } @@ -63,7 +63,7 @@ namespace HighWayAssemble.Protocol } catch (Exception ex) { - FrmDisplayView.LogInfo.Error("ERROR: " + ex.Message); + FrmDisplayView.LogInfo.Fatal("MES接口调用异常: " + ex.Message); return null; } } diff --git a/Highway.Assemble.EquipClient/ConcurrentDeviceHeartbeatManager.cs b/Highway.Assemble.EquipClient/ConcurrentDeviceHeartbeatManager.cs new file mode 100644 index 0000000..8c10fa3 --- /dev/null +++ b/Highway.Assemble.EquipClient/ConcurrentDeviceHeartbeatManager.cs @@ -0,0 +1,238 @@ +using log4net.Core; +using Mesnac.DeviceAdapter.RFly_I160; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Highway.Assemble.EquipClient +{ + using Highway.Assemble.common; + using Mesnac.DeviceAdapterNet; + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + + public class DeviceHeartbeatManager : IDisposable + { + private readonly ConcurrentDictionary _deviceTokens = + new ConcurrentDictionary(); + + private List _deviceIds; + private readonly SemaphoreSlim _concurrencySemaphore; + private readonly int _heartbeatIntervalMs; + private readonly int _timeoutMs; + private readonly ILogger _logger; + private readonly Func _createHeartbeatMessage; + private readonly Func> _sendMessageAsync; + private readonly Action _handleResult; + private Timer _heartbeatTimer; + private bool _isDisposed; + + public DeviceHeartbeatManager( + int maxConcurrentDevices = 10, + int heartbeatIntervalMs = 2000, + int timeoutMs = 2000, + ILogger logger = null, + Func createHeartbeatMessage = null, + Func> sendMessageAsync = null, + Action handleResult = null) + { + _concurrencySemaphore = new SemaphoreSlim(maxConcurrentDevices); + _heartbeatIntervalMs = heartbeatIntervalMs; + _timeoutMs = timeoutMs; + _logger = logger ?? new NullLogger(); + _createHeartbeatMessage = createHeartbeatMessage ?? CreateDefaultHeartbeatMessage; + _sendMessageAsync = sendMessageAsync ?? ((id, msg) => Task.FromResult(false)); + _handleResult = handleResult ?? ((id, result) => { }); + } + + public void StartMonitoring(List deviceIds) + { + if (_heartbeatTimer != null) + throw new InvalidOperationException("Heartbeat manager is already running."); + + _deviceIds = deviceIds; + + // 创建定时器,使用固定间隔触发心跳周期 + _heartbeatTimer = new Timer( + callback: ExecuteHeartbeatCycle, + state: null, + dueTime: 0, + period: _heartbeatIntervalMs); + } + + public void StopMonitoring() + { + if (_heartbeatTimer == null) + return; + + _heartbeatTimer.Dispose(); + _heartbeatTimer = null; + + // 取消所有正在执行的设备任务 + foreach (var cts in _deviceTokens.Values) + { + cts.Cancel(); + cts.Dispose(); + } + _deviceTokens.Clear(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + StopMonitoring(); + _concurrencySemaphore.Dispose(); + } + + _isDisposed = true; + } + + private async void ExecuteHeartbeatCycle(object state) + { + try + { + var cycleStartTime = DateTime.UtcNow; + _logger.Debug($"Starting heartbeat cycle at {cycleStartTime:O}"); + + // 为每个设备创建独立的取消令牌 + var deviceTasks = new List(); + foreach (var deviceId in _deviceIds) + { + var cts = new CancellationTokenSource(); + _deviceTokens.AddOrUpdate(deviceId.m_iDeviceId.ToString(), cts, (key, oldValue) => { oldValue.Dispose(); return cts; }); + + deviceTasks.Add(SendHeartbeatAsync(deviceId.m_iDeviceId.ToString(), cts.Token)); + } + + // 并发执行所有设备的心跳任务 + await Task.WhenAll(deviceTasks); + + var cycleDuration = (DateTime.UtcNow - cycleStartTime).TotalMilliseconds; + _logger.Debug($"Heartbeat cycle completed in {cycleDuration:F2}ms"); + } + catch (OperationCanceledException) + { + _logger.Info("Heartbeat cycle was canceled."); + } + catch (Exception ex) + { + _logger.Error($"Exception in heartbeat cycle: {ex.Message}"); + } + } + + private async Task SendHeartbeatAsync(string deviceId, CancellationToken cancellationToken) + { + await _concurrencySemaphore.WaitAsync(cancellationToken); + + try + { + var startTime = DateTime.UtcNow; + _logger.Debug($"Sending heartbeat to device {deviceId} at {startTime:O}"); + + var message = _createHeartbeatMessage(deviceId); + var result = await SendWithTimeoutAsync(deviceId, message, cancellationToken); + + _handleResult(deviceId, result); + + var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; + _logger.Debug($"Heartbeat to device {deviceId} processed in {elapsed:F2}ms"); + } + catch (OperationCanceledException) + { + _handleResult(deviceId, 2); // 操作取消 + } + catch (Exception ex) + { + _logger.Error($"Exception sending heartbeat to device {deviceId}: {ex.Message}"); + _handleResult(deviceId, 2); // 发生异常 + } + finally + { + _concurrencySemaphore.Release(); + + // 清理完成的任务令牌 + if (_deviceTokens.TryGetValue(deviceId, out var cts) && !cts.IsCancellationRequested) + { + cts.Dispose(); + _deviceTokens.TryRemove(deviceId, out _); + } + } + } + + private async Task SendWithTimeoutAsync(string deviceId, MessagePack message, CancellationToken cancellationToken) + { + using (var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) + { + timeoutCts.CancelAfter(_timeoutMs); + + try + { + var sendTask = _sendMessageAsync(deviceId, message); + var completedTask = await Task.WhenAny(sendTask, Task.Delay(Timeout.Infinite, timeoutCts.Token)); + + if (completedTask == sendTask) + { + return await sendTask ? (byte)1 : (byte)2; + } + + _logger.Warn($"Heartbeat to device {deviceId} timed out after {_timeoutMs}ms"); + return 0; // 超时 + } + catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested) + { + _logger.Warn($"Heartbeat to device {deviceId} timed out after {_timeoutMs}ms"); + return 0; // 超时 + } + } + } + + private MessagePack CreateDefaultHeartbeatMessage(string deviceId) + { + return new MessagePack + { + m_pData = new byte[9] { 0xAA, 0x55, 0x00, 0x90, 0x90, 0x0D, 0x00, 0x00, 0x0D } + }; + } + } + + // 简单的日志接口实现 + public interface ILogger + { + void Debug(string message); + void Info(string message); + void Warn(string message); + void Error(string message); + } + + public class NullLogger : ILogger + { + public void Debug(string message) { } + public void Info(string message) { } + public void Warn(string message) { } + public void Error(string message) { } + } + + // 消息包结构 + public class MessagePack + { + public byte[] m_pData { get; set; } + } +} diff --git a/Highway.Assemble.EquipClient/EquipClient.cs b/Highway.Assemble.EquipClient/EquipClient.cs index 527d369..ae9db79 100644 --- a/Highway.Assemble.EquipClient/EquipClient.cs +++ b/Highway.Assemble.EquipClient/EquipClient.cs @@ -19,6 +19,9 @@ namespace Highway.Assemble.EquipClient public Action> EquipStateAction; + public Action EquipStateActionasyc; + + public Action> ReadDataAction; public Action> RecSendDataAction; @@ -129,15 +132,242 @@ namespace Highway.Assemble.EquipClient LogInfo.Info("设备信息表为空!"); return; } + m_bgwDeviceDetect.DoWork += bgwDeviceDetect_DoWork; m_bgwDeviceDetect.RunWorkerAsync(this); } + //private void test() + //{ + // // 创建心跳管理器实例 + // var manager = new DeviceHeartbeatManager( + // maxConcurrentDevices: 10, // 最大并发设备数 + // heartbeatIntervalMs: 2000, // 心跳间隔(毫秒) + // timeoutMs: 2000, // 超时时间(毫秒) + // sendMessageAsync: async (deviceId, message) => + // { + // // 实际发送心跳包的逻辑 + // try + // { + // // 这里调用你的通信服务发送消息 + // return await YourCommunicationService.SendAsync(deviceId, message); + // } + // catch + // { + // return false; + // } + // }, + // handleResult: (deviceId, result) => + // { + // // 处理心跳结果 + // switch (result) + // { + // case 0: Console.WriteLine($"Device {deviceId} timed out"); break; + // case 1: Console.WriteLine($"Device {deviceId} is online"); break; + // case 2: Console.WriteLine($"Device {deviceId} communication error"); break; + // } + // } + // ); + + // // 添加设备进行监控 + + // manager.StartMonitoring(m_DeviceInfoList); + + // // 稍后停止监控 + // // manager.StopMonitoring(); + //} + + private async void bgwDeviceDetect_DoWork(object sender, DoWorkEventArgs e) + { + BackgroundWorker backgroundworker = sender as BackgroundWorker; + CancellationTokenSource cts = new CancellationTokenSource(); + const int DETECTION_INTERVAL_MS = 30000; // 检测间隔1分钟 + + try + { + // 记录下一次检测的时间点 + DateTime nextDetectionTime = DateTime.Now.AddMilliseconds(DETECTION_INTERVAL_MS); + + while (!ExitEvent.WaitOne(0, exitContext: false)) + { + try + { + Console.WriteLine(DateTime.Now+"开始执行设备检测"); + // 执行设备检测 + await PerformDeviceDetection(cts.Token); + + + } + catch (OperationCanceledException) + { + // 任务被取消,退出循环 + break; + } + catch (Exception ex) + { + LogInfo.Error("设备检测过程中发生异常: " + ex.Message); + } + + // 计算距离下一次检测的剩余时间 + TimeSpan timeToNextDetection = nextDetectionTime - DateTime.Now; + + // 如果剩余时间为正,则等待 + if (timeToNextDetection > TimeSpan.Zero) + { + await Task.Delay(timeToNextDetection, cts.Token); + } + + // 设置下一次检测时间点 + nextDetectionTime = DateTime.Now.AddMilliseconds(DETECTION_INTERVAL_MS); + } + + LogInfo.Info("设备检测线程正常退出"); + ExitEvent.Reset(); + e.Cancel = true; + } + catch (OperationCanceledException) + { + LogInfo.Info("设备检测线程被取消"); + } + catch (Exception ex) + { + LogInfo.Error("设备检测线程异常:" + ex.Message); + // 异常发生后等待一段时间再继续 + await Task.Delay(30000); + } + finally + { + cts.Cancel(); + cts.Dispose(); + } + } + + // 执行所有设备的检测 + private async Task PerformDeviceDetection(CancellationToken cancellationToken) + { + var tasks = new List(); + SemaphoreSlim semaphore = new SemaphoreSlim(m_DeviceInfoList.Count); // 限制最多5个并发任务 + + foreach (var item in m_DeviceInfoList) + { + await semaphore.WaitAsync(cancellationToken); + + tasks.Add(Task.Factory.StartNew(async () => + { + try + { + await HandleDeviceConnection(item); + // 更新设备状态 + + EquipStateActionasyc?.Invoke(item); + } + catch (OperationCanceledException) + { + // 任务被取消 + } + catch (Exception ex) + { + LogInfo.Error($"处理设备 {item.m_strConnectStr} 时出错: {ex.Message}"); + } + finally + { + semaphore.Release(); + } + }, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap()); + } + + // 等待所有任务完成 + await Task.WhenAll(tasks); + } + + // 其余方法保持不变... + + // 将设备连接处理逻辑提取为单独的方法 + private async Task HandleDeviceConnection(DeviceInfo item) + { + IDeviceAdapter pDeviceAdapter = item.m_IDeviceAdapter; + + if (pDeviceAdapter == null) + { + item.m_ConnectState = 0; + return; + } + if (item.m_iDeviceId == 10001) + { + + } + switch (item.m_ConnectState) + { + case 0: // 未连接状态 + if (await RunOnThreadPool(() => pDeviceAdapter.Device_Init_Id((CommType)item.m_iConnectMode, item.m_strConnectStr, item.m_iDeviceId))) + { + if (await RunOnThreadPool(() => pDeviceAdapter.Device_Connect())) + { + // 管理事件订阅,避免重复订阅 + pDeviceAdapter.RecvIdentifyDataEvent -= RecvIdentifyData_Instance; + pDeviceAdapter.RecvIdentifyDataEvent += RecvIdentifyData_Instance; + + item.m_ConnectState = await GetConnectionStateFromHeartbeat(pDeviceAdapter); + } + else + { + item.m_ConnectState = 0; + } + } + else + { + item.m_ConnectState = 0; + } + break; + + case 1: // 已连接状态 + item.m_ConnectState = await GetConnectionStateFromHeartbeat(pDeviceAdapter); + break; + + case 2: // 连接异常状态 + int heartbeatResult = await GetConnectionStateFromHeartbeat(pDeviceAdapter); + if (heartbeatResult == 2) + { + item.m_ConnectState = 0; + await RunOnThreadPool(() => item.m_IDeviceAdapter.Device_Destroy()); + } + else if (heartbeatResult == 1) + { + item.m_ConnectState = 1; + } + else + { + item.m_ConnectState = 0; + await RunOnThreadPool(() => item.m_IDeviceAdapter.Device_Destroy()); + } + break; + } + } + + // 将心跳检测逻辑提取为单独的方法 + private async Task GetConnectionStateFromHeartbeat(IDeviceAdapter adapter) + { + return await adapter.Device_SendHeartPackAsync(); + } + + // 替代 Task.Run 的辅助方法,兼容 .NET Framework 4.6.1 + private Task RunOnThreadPool(Func func) + { + return Task.Factory.StartNew(func, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + // 替代 Task.Run 的辅助方法,兼容 .NET Framework 4.6.1 + private Task RunOnThreadPool(Action action) + { + return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + /// /// 监听设备数据事件 /// /// /// - private void bgwDeviceDetect_DoWork(object sender, DoWorkEventArgs e) + private void bgwDeviceDetect_DoWork(object sender, DoWorkEventArgs e ,string test) { BackgroundWorker backgroundworker = sender as BackgroundWorker; while (true) @@ -229,7 +459,7 @@ namespace Highway.Assemble.EquipClient }); } DetectEvent.Reset(); - DetectEvent.WaitOne(120000, exitContext: false); + DetectEvent.WaitOne(60000, exitContext: false); } catch (Exception ex) { @@ -722,6 +952,11 @@ namespace Highway.Assemble.EquipClient EquipStateAction = action; } + public void RecEquipStateasyc(Action action) + { + EquipStateActionasyc = action; + } + public void RecGetData(Action action) { RecGetDataAction = action; diff --git a/Highway.Assemble.EquipClient/Highway.Assemble.EquipClient.csproj b/Highway.Assemble.EquipClient/Highway.Assemble.EquipClient.csproj index b9a473b..13be077 100644 --- a/Highway.Assemble.EquipClient/Highway.Assemble.EquipClient.csproj +++ b/Highway.Assemble.EquipClient/Highway.Assemble.EquipClient.csproj @@ -49,6 +49,7 @@ + @@ -63,6 +64,10 @@ {514b888f-4d0d-4406-9396-5235a7bed7bf} Highway.Assemble.Common + + {786B9D51-D67A-4235-B082-78E9CF4FCFB6} + Mesnac.DeviceAdapter.RFly_I160 + \ No newline at end of file diff --git a/Highway.Assemble.EquipClient/IEquipClient.cs b/Highway.Assemble.EquipClient/IEquipClient.cs index 2322d7c..753ddae 100644 --- a/Highway.Assemble.EquipClient/IEquipClient.cs +++ b/Highway.Assemble.EquipClient/IEquipClient.cs @@ -27,6 +27,8 @@ namespace Highway.Assemble.EquipClient void RecEquipState(Action> action); + void RecEquipStateasyc(Action action); + void ReadData(int num, byte filterMembank, ushort filterWordPtr, ushort filterWordCnt, byte[] filterData, byte Membank, ushort WordPtr, ushort WordCnt); void RetReadData(Action> action); diff --git a/Mesnac.DeviceAdapter.Fuchs/FuchsDevice.cs b/Mesnac.DeviceAdapter.Fuchs/FuchsDevice.cs index 6f41768..ca33439 100644 --- a/Mesnac.DeviceAdapter.Fuchs/FuchsDevice.cs +++ b/Mesnac.DeviceAdapter.Fuchs/FuchsDevice.cs @@ -4,6 +4,7 @@ using System.ComponentModel; //using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; namespace Mesnac.DeviceAdapter.Fuchs { @@ -1508,6 +1509,11 @@ namespace Mesnac.DeviceAdapter.Fuchs throw new NotImplementedException(); } + public Task Device_SendHeartPackAsync(CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + //public List TagInventoryTimePeriod(byte Antenna, int time) //{ // List t = new List { }; diff --git a/Mesnac.DeviceAdapter.HWKC_81600/HWKC_81600Device.cs b/Mesnac.DeviceAdapter.HWKC_81600/HWKC_81600Device.cs index fc267d4..352a232 100644 --- a/Mesnac.DeviceAdapter.HWKC_81600/HWKC_81600Device.cs +++ b/Mesnac.DeviceAdapter.HWKC_81600/HWKC_81600Device.cs @@ -4,6 +4,7 @@ using System.Configuration; //using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; namespace Mesnac.DeviceAdapter.HWKC_81600 { @@ -784,6 +785,11 @@ namespace Mesnac.DeviceAdapter.HWKC_81600 { throw new NotImplementedException(); } + + public Task Device_SendHeartPackAsync(CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } #endregion } } diff --git a/Mesnac.DeviceAdapter.RFly_I160/BgTcpClient.cs b/Mesnac.DeviceAdapter.RFly_I160/BgTcpClient.cs index 59f3ddc..34017c2 100644 --- a/Mesnac.DeviceAdapter.RFly_I160/BgTcpClient.cs +++ b/Mesnac.DeviceAdapter.RFly_I160/BgTcpClient.cs @@ -284,7 +284,7 @@ namespace Mesnac.DeviceAdapter.RFly_I160 m_ClientSock.Blocking = false; m_ClientSock.Send(tmp, 0, 0); bResult = true; - Console.WriteLine("Connected!"); + //Console.WriteLine("Connected!"); } else { @@ -297,12 +297,12 @@ namespace Mesnac.DeviceAdapter.RFly_I160 if (e.NativeErrorCode.Equals(10035)) { bResult = true; - Console.WriteLine("Still Connected, but the Send would block"); + //Console.WriteLine("Still Connected, but the Send would block"); } else { bResult = false; - Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode); + //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode); } } finally diff --git a/Mesnac.DeviceAdapter.RFly_I160/Properties/_system~.ini b/Mesnac.DeviceAdapter.RFly_I160/Properties/_system~.ini deleted file mode 100644 index e69de29..0000000 diff --git a/Mesnac.DeviceAdapter.RFly_I160/RFly_I160Device.cs b/Mesnac.DeviceAdapter.RFly_I160/RFly_I160Device.cs index ea9af36..a1f5236 100644 --- a/Mesnac.DeviceAdapter.RFly_I160/RFly_I160Device.cs +++ b/Mesnac.DeviceAdapter.RFly_I160/RFly_I160Device.cs @@ -1,12 +1,13 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Configuration; using System.Linq; -using System.Text; //using System.Threading.Tasks; using System.Runtime.InteropServices; +using System.Text; using System.Threading; -using System.Configuration; -using System.Collections; +using System.Threading.Tasks; namespace Mesnac.DeviceAdapter.RFly_I160 { @@ -34,7 +35,10 @@ namespace Mesnac.DeviceAdapter.RFly_I160 private Semaphore m_GlobalSem = new Semaphore(1, 1); private bool m_GetHeartSuccessful = false; - private Semaphore m_GetHeartSem = new Semaphore(0, 100000); + private Semaphore m_GetHeartSem = new Semaphore(0, 100000); + + //private ManualResetEvent m_GetHeartSem = new ManualResetEvent(false); + private Semaphore m_MulEpcSem = new Semaphore(0, 100000); private Semaphore m_StopSem = new Semaphore(0, 100000); @@ -272,6 +276,94 @@ namespace Mesnac.DeviceAdapter.RFly_I160 return true; } + + public async Task Device_SendHeartPackAsync(CancellationToken cancellationToken = default) + { + try + { + + // 使用 ManualResetEventSlim 替代 SemaphoreSlim,支持异步等待 + await Task.Factory.StartNew( + () => m_GlobalSem.WaitOne(), + cancellationToken, + TaskCreationOptions.None, + TaskScheduler.Default + ); + + // 创建心跳包 + var messagePack = new MessagePack + { + m_pData = new byte[9] { 0xAA, 0x55, 0x00, 0x90, 0x90, 0x0D, 0x00, 0x00, 0x0D } + }; + + // 检查通信服务 + if (m_ICommunicateService == null) + { + LogInfo.Error("Communication service is not initialized."); + return 2; // 通讯连接器失败或网络故障 + } + + // 发送心跳包 + bool sendSuccess = await Task.Factory.StartNew( + () => m_ICommunicateService.SendMessage(messagePack), + cancellationToken, + TaskCreationOptions.None, + TaskScheduler.Default + ); + + if (!sendSuccess) + { + LogInfo.Warn("Failed to send heartbeat message."); + return 2; // 通讯连接器失败或网络故障 + } + // 使用 WaitHandle.WaitOne 的超时机制 + var waitTask = Task.Factory.StartNew( + () => m_GetHeartSem.WaitOne(2000, false), + cancellationToken, + TaskCreationOptions.None, + TaskScheduler.Default + ); + + // 不需要第二个超时,直接等待任务完成 + await waitTask; + + if (waitTask.Result) + { + LogInfo.Debug("Heartbeat response received successfully."); + return 1; // 通讯连接和读写器都正常 + } + else + { + // 处理超时的情况 + LogInfo.Warn("Heartbeat response timed out after 2000ms."); + return 0; // 或者抛出异常,取决于你的需求 + } + + + } + catch (OperationCanceledException) + { + LogInfo.Info("Heartbeat operation was canceled."); + return 2; + } + catch (Exception ex) + { + LogInfo.Error($"Exception in Device_SendHeartPackAsync: {ex.Message}"); + return 2; // 发生异常,返回通讯故障 + } + finally + { + // 确保信号量总是被释放 + try + { + m_GlobalSem.Release(); + } + catch (ApplicationException) + { + LogInfo.Error("Global semaphore was already released."); + } + } + } public byte Device_SendHeartPack() { byte iResult = 0; diff --git a/Mesnac.DeviceAdapter.RFly_I160/_system~.ini b/Mesnac.DeviceAdapter.RFly_I160/_system~.ini deleted file mode 100644 index e69de29..0000000