|
|
|
@ -19,6 +19,9 @@ namespace Highway.Assemble.EquipClient
|
|
|
|
|
|
|
|
|
|
|
|
public Action<List<DeviceInfo>> EquipStateAction;
|
|
|
|
public Action<List<DeviceInfo>> EquipStateAction;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Action<DeviceInfo> EquipStateActionasyc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Action<string, List<TagInfo>> ReadDataAction;
|
|
|
|
public Action<string, List<TagInfo>> ReadDataAction;
|
|
|
|
|
|
|
|
|
|
|
|
public Action<string, List<TagInfo>> RecSendDataAction;
|
|
|
|
public Action<string, List<TagInfo>> RecSendDataAction;
|
|
|
|
@ -129,15 +132,242 @@ namespace Highway.Assemble.EquipClient
|
|
|
|
LogInfo.Info("设备信息表为空!");
|
|
|
|
LogInfo.Info("设备信息表为空!");
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_bgwDeviceDetect.DoWork += bgwDeviceDetect_DoWork;
|
|
|
|
m_bgwDeviceDetect.DoWork += bgwDeviceDetect_DoWork;
|
|
|
|
m_bgwDeviceDetect.RunWorkerAsync(this);
|
|
|
|
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<Task>();
|
|
|
|
|
|
|
|
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<byte> GetConnectionStateFromHeartbeat(IDeviceAdapter adapter)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return await adapter.Device_SendHeartPackAsync();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 替代 Task.Run 的辅助方法,兼容 .NET Framework 4.6.1
|
|
|
|
|
|
|
|
private Task<T> RunOnThreadPool<T>(Func<T> 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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// 监听设备数据事件
|
|
|
|
/// 监听设备数据事件
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
/// <param name="e"></param>
|
|
|
|
/// <param name="e"></param>
|
|
|
|
private void bgwDeviceDetect_DoWork(object sender, DoWorkEventArgs e)
|
|
|
|
private void bgwDeviceDetect_DoWork(object sender, DoWorkEventArgs e ,string test)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
BackgroundWorker backgroundworker = sender as BackgroundWorker;
|
|
|
|
BackgroundWorker backgroundworker = sender as BackgroundWorker;
|
|
|
|
while (true)
|
|
|
|
while (true)
|
|
|
|
@ -229,7 +459,7 @@ namespace Highway.Assemble.EquipClient
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DetectEvent.Reset();
|
|
|
|
DetectEvent.Reset();
|
|
|
|
DetectEvent.WaitOne(120000, exitContext: false);
|
|
|
|
DetectEvent.WaitOne(60000, exitContext: false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -722,6 +952,11 @@ namespace Highway.Assemble.EquipClient
|
|
|
|
EquipStateAction = action;
|
|
|
|
EquipStateAction = action;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void RecEquipStateasyc(Action<DeviceInfo> action)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
EquipStateActionasyc = action;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void RecGetData(Action<int, int, int> action)
|
|
|
|
public void RecGetData(Action<int, int, int> action)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
RecGetDataAction = action;
|
|
|
|
RecGetDataAction = action;
|
|
|
|
|