This commit is contained in:
zqm
2025-10-28 13:08:56 +08:00
parent 6da609c10f
commit eb96e4f151
4 changed files with 1469 additions and 384 deletions

View File

@@ -35,7 +35,7 @@ namespace JoyD.Windows.CS.Toprie
// 清空现有日志
try
{
string logFile = Path.Combine(Application.StartupPath, "camera.log");
string logFile = Path.Combine(Application.StartupPath, "log.txt");
if (File.Exists(logFile))
{
File.WriteAllText(logFile, string.Empty);
@@ -571,27 +571,73 @@ namespace JoyD.Windows.CS.Toprie
/// </summary>
private void DeviceManager_ConnectionStatusChanged(object sender, ConnectionStatusChangedEventArgs e)
{
// 确保在UI线程上更新并且检查控件是否已被释放
if (!this.IsDisposed && !this.Disposing)
// 参数验证
if (e == null)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 警告: 接收到空的连接状态变更事件参数");
return;
}
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] 接收连接状态变更事件: {e.Status}");
// 捕获所有可能的异常,确保事件处理器不会崩溃
try
{
// 首先检查控件状态
if (this.IsDisposed || this.Disposing)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放或正在释放跳过UI更新");
return;
}
// 检查事件参数中的状态信息
string statusMessage = $"连接状态变更为: {e.Status}";
if (!string.IsNullOrEmpty(e.DeviceInfo))
{
statusMessage += $" (设备信息: {e.DeviceInfo})";
}
// 线程安全处理 - 确保在UI线程上更新
if (this.InvokeRequired)
{
try
{
// 使用BeginInvoke代替Invoke避免可能的死锁问题
this.BeginInvoke(new Action(() => HandleConnectionStatusChanged(e)));
this.BeginInvoke(new Action<ConnectionStatusChangedEventArgs>(args =>
{
// 再次检查控件状态,防止在异步调用期间控件被释放
if (!this.IsDisposed && !this.Disposing)
{
HandleConnectionStatusChanged(args);
}
catch (ObjectDisposedException)
else
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 异步调用期间控件已释放,跳过处理");
}
}), e);
}
catch (ObjectDisposedException ode)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine("控件已释放跳过UI更新");
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放无法进行UI线程调用: {ode.Message}");
}
catch (InvalidOperationException ioe)
{
// 捕获无效操作异常,通常发生在控件状态异常时
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] UI线程调用无效: {ioe.Message}");
}
}
else
{
// 直接在UI线程上处理
HandleConnectionStatusChanged(e);
}
}
catch (Exception ex)
{
// 捕获所有其他异常,记录并继续
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 处理连接状态变更事件异常: {ex.Message}\n{ex.StackTrace}");
}
}
/// <summary>
@@ -739,35 +785,92 @@ namespace JoyD.Windows.CS.Toprie
/// </summary>
private void DeviceManager_ConnectionException(object sender, ConnectionExceptionEventArgs e)
{
// 确保在UI线程上更新并且检查控件是否已被释放
if (!this.IsDisposed && !this.Disposing)
// 参数验证
if (e == null)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 警告: 接收到空的连接异常事件参数");
return;
}
// 记录详细的异常信息但避免在UI线程上执行耗时操作
string exceptionMessage = e.Exception != null ? e.Exception.Message : "无详细异常信息";
string stackTrace = e.Exception != null ? e.Exception.StackTrace : "无堆栈信息";
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] 接收连接异常事件: {e.Message}\n{exceptionMessage}\n{stackTrace}");
// 捕获所有可能的异常,确保异常处理不会导致程序崩溃
try
{
// 首先检查控件状态
if (this.IsDisposed || this.Disposing)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放或正在释放,跳过异常显示");
return;
}
// 创建用于UI显示的错误消息
string uiErrorMessage = $"连接异常: {e.Message}";
if (string.IsNullOrEmpty(e.Message) && e.Exception != null)
{
uiErrorMessage = $"连接异常: {exceptionMessage}";
}
// 线程安全处理 - 确保在UI线程上更新
if (this.InvokeRequired)
{
try
{
// 使用BeginInvoke在UI线程上显示错误
// 创建局部变量保存错误消息,避免闭包问题
string errorMsg = uiErrorMessage;
// 使用BeginInvoke代替Invoke避免可能的死锁问题
this.BeginInvoke(new Action(() =>
{
// 记录异常日志
Console.WriteLine($"连接异常发生于 {DateTime.Now}: {e.Message}\n{e.Exception.Message}\n{e.Exception.StackTrace}");
ShowError($"连接异常: {e.Message}");
}));
}
catch (ObjectDisposedException)
// 再次检查控件状态,防止在异步调用期间控件被释放
if (!this.IsDisposed && !this.Disposing)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine("控件已释放,跳过异常处理");
try
{
ShowError(errorMsg);
}
catch (Exception showEx)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 显示错误消息异常: {showEx.Message}");
}
}
else
{
// 记录异常日志
Console.WriteLine($"连接异常发生于 {DateTime.Now}: {e.Message}\n{e.Exception.Message}\n{e.Exception.StackTrace}");
ShowError($"连接异常: {e.Message}");
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 异步调用期间控件已释放,跳过错误显示");
}
}));
}
catch (ObjectDisposedException ode)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放无法进行UI线程调用: {ode.Message}");
}
catch (InvalidOperationException ioe)
{
// 捕获无效操作异常,通常发生在控件状态异常时
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] UI线程调用无效: {ioe.Message}");
}
}
else
{
// 直接在UI线程上处理
try
{
ShowError(uiErrorMessage);
}
catch (Exception showEx)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 显示错误消息异常: {showEx.Message}");
}
}
}
catch (Exception ex)
{
// 捕获所有其他异常,记录并继续
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 处理连接异常事件异常: {ex.Message}\n{ex.StackTrace}");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -263,6 +263,18 @@ namespace JoyD.Windows.CS.Toprie
return tcs.Task;
}
/// <summary>
/// UDP请求结果枚举
/// </summary>
public enum RequestResult
{
Success,
Timeout,
NetworkError,
ProcessingError,
InvalidResponse
}
/// <summary>
/// 同步发送UDP请求
/// </summary>
@@ -270,19 +282,131 @@ namespace JoyD.Windows.CS.Toprie
/// <param name="data">要发送的数据</param>
/// <param name="port">目标端口默认为18890</param>
/// <param name="timeout">超时时间毫秒默认为500</param>
/// <param name="response">返回的响应数据</param>
/// <returns>请求结果</returns>
public RequestResult SendRequest(string targetIp, byte[] data, out byte[] response, int port = DEFAULT_UDP_PORT, int timeout = DEFAULT_TIMEOUT)
{
response = null;
try
{
var task = SendRequestAsync(targetIp, data, port, timeout);
bool completed = task.Wait(timeout);
if (completed)
{
response = task.Result;
if (response != null)
{
return RequestResult.Success;
}
return RequestResult.NetworkError;
}
Console.WriteLine($"UDP请求执行超时({timeout}ms)");
return RequestResult.Timeout;
}
catch (TimeoutException)
{
Console.WriteLine($"UDP请求执行超时异常");
return RequestResult.Timeout;
}
catch (Exception ex)
{
Console.WriteLine($"发送UDP请求时发生错误: {ex.Message}");
return RequestResult.ProcessingError;
}
}
/// <summary>
/// 同步发送UDP请求兼容旧版本
/// </summary>
/// <param name="targetIp">目标IP地址</param>
/// <param name="data">要发送的数据</param>
/// <param name="port">目标端口默认为18890</param>
/// <param name="timeout">超时时间毫秒默认为500</param>
/// <returns>响应数据如果超时则返回null</returns>
public byte[] SendRequest(string targetIp, byte[] data, int port = DEFAULT_UDP_PORT, int timeout = DEFAULT_TIMEOUT)
{
SendRequest(targetIp, data, out byte[] response, port, timeout);
return response;
}
/// <summary>
/// 异步发送字符串命令的UDP请求
/// </summary>
/// <param name="targetIp">目标IP地址</param>
/// <param name="command">要发送的命令字符串</param>
/// <param name="port">目标端口默认为18890</param>
/// <param name="timeout">超时时间毫秒默认为500</param>
/// <returns>包含响应字符串的Task</returns>
public Task<string> SendRequestAsync(string targetIp, string command, int port = DEFAULT_UDP_PORT, int timeout = DEFAULT_TIMEOUT)
{
byte[] data = Encoding.ASCII.GetBytes(command);
Task<byte[]> dataTask = SendRequestAsync(targetIp, data, port, timeout);
// 创建一个新的Task用于返回字符串结果
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
dataTask.ContinueWith(task => {
if (task.IsFaulted)
{
tcs.SetException(task.Exception);
}
else if (task.IsCanceled)
{
tcs.SetCanceled();
}
else
{
byte[] result = task.Result;
string stringResult = result != null ? Encoding.ASCII.GetString(result) : null;
tcs.SetResult(stringResult);
}
});
return tcs.Task;
}
/// <summary>
/// 同步发送字符串命令的UDP请求
/// </summary>
/// <param name="targetIp">目标IP地址</param>
/// <param name="command">要发送的命令</param>
/// <param name="timeoutMs">超时时间(毫秒)</param>
/// <param name="response">返回的响应内容</param>
/// <returns>请求结果</returns>
public RequestResult SendRequest(string targetIp, string command, int timeoutMs, out string response)
{
response = null;
try
{
var task = SendRequestAsync(targetIp, data, port, timeout);
task.Wait(timeout);
return task.Result;
var task = SendRequestAsync(targetIp, command, DEFAULT_UDP_PORT, timeoutMs);
bool completed = task.Wait(timeoutMs + 50); // 额外添加50ms作为缓冲
if (completed)
{
response = task.Result;
if (response != null)
{
// 验证响应格式是否符合预期
if (response.Length > 0 && (response.StartsWith("+RET:") || response.Contains(":")))
{
return RequestResult.Success;
}
Console.WriteLine($"命令 '{command}' 收到无效响应: '{response}'");
return RequestResult.InvalidResponse;
}
return RequestResult.NetworkError;
}
Console.WriteLine($"命令 '{command}' 执行超时({timeoutMs}ms)");
return RequestResult.Timeout;
}
catch (TimeoutException)
{
Console.WriteLine($"命令 '{command}' 执行超时异常");
return RequestResult.Timeout;
}
catch (Exception ex)
{
Console.WriteLine($"同步发送UDP请求异常: {ex.Message}");
return null;
Console.WriteLine($"发送命令 '{command}' 时发生错误: {ex.Message}");
return RequestResult.ProcessingError;
}
}

View File

@@ -218,11 +218,11 @@ namespace JoyD.Windows.CS.Toprie
try
{
// 使用UDP通信管理器发送请求
byte[] responseBytes = UdpCommunicationManager.Instance.SendRequest(deviceIp,
Encoding.ASCII.GetBytes(cmd), 18890, 200);
// 使用UDP通信管理器发送请求,获取详细的请求结果
var result = UdpCommunicationManager.Instance.SendRequest(deviceIp,
Encoding.ASCII.GetBytes(cmd), out byte[] responseBytes, 18890, 200);
if (responseBytes != null)
if (result == UdpCommunicationManager.RequestResult.Success && responseBytes != null)
{
response = Encoding.ASCII.GetString(responseBytes);
Console.WriteLine($"UDP命令已发送: {cmd}");
@@ -232,7 +232,25 @@ namespace JoyD.Windows.CS.Toprie
}
else
{
Console.WriteLine($"UDP命令发送后未收到响应或超时: {cmd}");
// 根据不同的结果类型提供更详细的信息
switch (result)
{
case UdpCommunicationManager.RequestResult.Timeout:
Console.WriteLine($"UDP命令 '{cmd}' 发送后超时");
break;
case UdpCommunicationManager.RequestResult.NetworkError:
Console.WriteLine($"UDP命令 '{cmd}' 网络错误");
break;
case UdpCommunicationManager.RequestResult.InvalidResponse:
Console.WriteLine($"UDP命令 '{cmd}' 收到无效响应");
break;
case UdpCommunicationManager.RequestResult.ProcessingError:
Console.WriteLine($"UDP命令 '{cmd}' 处理错误");
break;
default:
Console.WriteLine($"UDP命令 '{cmd}' 发送后未收到有效响应");
break;
}
return false;
}
@@ -464,6 +482,8 @@ namespace JoyD.Windows.CS.Toprie
}
}
private int _lastKnownColorPlate = 0; // 保存最后已知的色板值
public int Color_plate
{
get
@@ -475,14 +495,20 @@ namespace JoyD.Windows.CS.Toprie
if (SendCommand(command, out string response))
{
return ParseResponseValue(response);
int parsedValue = ParseResponseValue(response);
if (parsedValue != 0 || response != null) // 确保至少解析成功或有响应
{
_lastKnownColorPlate = parsedValue;
return parsedValue;
}
return 0; // 默认色板
}
Console.WriteLine("获取色板失败,返回上次已知值");
return _lastKnownColorPlate; // 返回上次已知值
}
catch (Exception ex)
{
Console.WriteLine($"获取色板失败: {ex.Message}");
return 0;
Console.WriteLine($"获取色板异常: {ex.Message},返回上次已知值");
return _lastKnownColorPlate;
}
}
set
@@ -492,18 +518,31 @@ namespace JoyD.Windows.CS.Toprie
// 使用SDK格式设置色板: ip:param_mode,param_value$
string command = $"{deviceIp}:{(int)CMD_TYPE.SET_COLOR_PLATE},{value}$";
if (SendCommand(command, out string response))
bool success = SendCommand(command, out string response);
if (success && response != null)
{
// 验证响应
if (response != null)
// 验证响应是否包含成功标记
bool responseValid = response.Contains("+RET:") &&
(!response.Contains("error") || !response.Contains("失败"));
if (responseValid)
{
Console.WriteLine("设置色板成功");
Console.WriteLine($"设置色板成功: {value}");
_lastKnownColorPlate = value; // 更新最后已知值
}
else
{
Console.WriteLine($"设置色板响应验证失败: {response}");
}
}
else
{
Console.WriteLine($"设置色板失败: 命令发送失败或超时");
}
}
catch (Exception ex)
{
Console.WriteLine($"设置色板失败: {ex.Message}");
Console.WriteLine($"设置色板异常: {ex.Message}");
}
}
}