设置色彩模式后不重启连接

This commit is contained in:
zqm
2025-10-28 16:43:18 +08:00
parent 2aa69ee0a8
commit bfbe7696f3
2 changed files with 304 additions and 133 deletions

View File

@@ -466,7 +466,7 @@ namespace JoyD.Windows.CS.Toprie
return false;
}
}
/// <summary>
/// 初始化设备管理器
/// </summary>
@@ -474,16 +474,16 @@ namespace JoyD.Windows.CS.Toprie
private bool Initialize()
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 开始执行初始化");
// 在设计模式下,跳过实际初始化,直接返回成功
if (IsDesignMode)
{
{
Log("设计模式下跳过实际初始化,模拟初始化成功");
_isInitialized = true;
_connectionStatus = ConnectionStatus.Connected;
return true;
}
// 双重检查锁定模式,确保线程安全的初始化
if (_isInitialized)
{
@@ -500,111 +500,110 @@ namespace JoyD.Windows.CS.Toprie
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 已被其他线程初始化,直接返回成功");
return true;
}
try
{
// 清理旧资源(如果有)
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 清理旧资源");
CleanupResources();
// 初始化设备ID列表和相关变量
_deviceIds = new List<string>();
_currentDeviceId = -1;
// 保留默认设备IP不要重置为空字符串
// _deviceIp = string.Empty; // 注释掉这行避免IP地址被清空
_connectionStatus = ConnectionStatus.Disconnected;
_currentReconnectAttempt = 0;
Log("开始SDK初始化...");
// 首先检查网络可用性
if (!IsNetworkAvailable())
{
Log("网络不可用,初始化暂缓");
return false;
}
// 更新状态为连接中
UpdateConnectionStatus(ConnectionStatus.Connecting, "正在初始化设备连接");
// 首先调用SDK静态初始化方法 - 这是连接成功的关键步骤!
// 添加重试机制,增强初始化可靠性
int initResult = -1;
int maxInitRetries = 2;
for (int retry = 0; retry <= maxInitRetries; retry++)
{
try
// 清理旧资源(如果有)
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 清理旧资源");
CleanupResources();
// 初始化设备ID列表和相关变量
_deviceIds = new List<string>();
_currentDeviceId = -1;
// 保留默认设备IP不要重置为空字符串
// _deviceIp = string.Empty; // 注释掉这行避免IP地址被清空
_connectionStatus = ConnectionStatus.Disconnected;
_currentReconnectAttempt = 0;
Log("开始SDK初始化...");
// 首先检查网络可用性
if (!IsNetworkAvailable())
{
if (retry > 0)
{
Log($"SDK初始化重试 {retry}/{maxInitRetries}");
Thread.Sleep(300); // 重试前等待一小段时间
}
initResult = A8SDK.SDK_initialize();
if (initResult == 0)
{
break; // 成功,跳出循环
}
Log($"SDK静态初始化失败返回值: {initResult}");
Log("网络不可用,初始化暂缓");
return false;
}
catch (Exception initEx)
// 更新状态为连接中
UpdateConnectionStatus(ConnectionStatus.Connecting, "正在初始化设备连接");
// 首先调用SDK静态初始化方法 - 这是连接成功的关键步骤!
// 添加重试机制,增强初始化可靠性
int initResult = -1;
int maxInitRetries = 2;
for (int retry = 0; retry <= maxInitRetries; retry++)
{
Log($"SDK初始化异常: {initEx.Message},堆栈: {initEx.StackTrace}");
try
{
if (retry > 0)
{
Log($"SDK初始化重试 {retry}/{maxInitRetries}");
Thread.Sleep(300); // 重试前等待一小段时间
}
initResult = A8SDK.SDK_initialize();
if (initResult == 0)
{
break; // 成功,跳出循环
}
Log($"SDK静态初始化失败返回值: {initResult}");
}
catch (Exception initEx)
{
Log($"SDK初始化异常: {initEx.Message},堆栈: {initEx.StackTrace}");
}
}
if (initResult != 0)
{
Log($"SDK静态初始化失败所有重试均未成功返回值: {initResult}");
_isInitialized = false;
return false;
}
Log("SDK静态初始化成功");
// 设置默认配置参数
_maxReconnectAttempts = 15; // 增加最大重连次数
_isAutoReconnectEnabled = true;
_isInitialized = true;
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 初始化成功_isInitialized设为true");
// 更新状态为已连接
UpdateConnectionStatus(ConnectionStatus.Connected, "SDK初始化成功");
// 连接成功后,停止自动重连(如果正在运行)
StopAutoReconnect();
// 启动图像接收
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 连接成功,启动图像接收");
StartImageReceiving();
return true;
}
if (initResult != 0)
catch (Exception ex)
{
Log($"SDK静态初始化失败,所有重试均未成功,返回值: {initResult}");
Log($"SDK初始化失败: {ex.Message},堆栈: {ex.StackTrace}");
_isInitialized = false;
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 初始化异常_isInitialized保持false: {ex.Message}");
OnConnectionException(new ConnectionExceptionEventArgs(ex, "初始化设备管理器失败"));
// 更新状态为断开
UpdateConnectionStatus(ConnectionStatus.Disconnected, "初始化失败", ex);
return false;
}
Log("SDK静态初始化成功");
// 设置默认配置参数
_maxReconnectAttempts = 15; // 增加最大重连次数
_isAutoReconnectEnabled = true;
_isInitialized = true;
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 初始化成功_isInitialized设为true");
// 更新状态为已连接
UpdateConnectionStatus(ConnectionStatus.Connected, "SDK初始化成功");
// 连接成功后,停止自动重连(如果正在运行)
StopAutoReconnect();
// 启动图像接收
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 连接成功,启动图像接收");
StartImageReceiving();
return true;
}
catch (Exception ex)
{
Log($"SDK初始化失败: {ex.Message},堆栈: {ex.StackTrace}");
_isInitialized = false;
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 初始化异常_isInitialized保持false: {ex.Message}");
OnConnectionException(new ConnectionExceptionEventArgs(ex, "初始化设备管理器失败"));
// 更新状态为断开
UpdateConnectionStatus(ConnectionStatus.Disconnected, "初始化失败", ex);
return false;
}
finally
{
// 确保在异常情况下也能清理资源
if (!_isInitialized && _connectionStatus == ConnectionStatus.Connecting)
finally
{
UpdateConnectionStatus(ConnectionStatus.Disconnected, "初始化未完成");
// 确保在异常情况下也能清理资源
if (!_isInitialized && _connectionStatus == ConnectionStatus.Connecting)
{
UpdateConnectionStatus(ConnectionStatus.Disconnected, "初始化未完成");
}
}
}
}
}
/// <summary>
/// 清理所有资源,确保安全释放
/// </summary>
@@ -2251,6 +2250,16 @@ namespace JoyD.Windows.CS.Toprie
// 即使获取失败,仍尝试设置新值
}
// 将PaletteType枚举转换为int类型
int paletteValue = (int)paletteType;
// 检查新的色彩模式是否与当前值相同,如果相同则不需要设置
if (originalValue == paletteValue)
{
Log($"当前色彩模式已为目标值,无需设置");
return true;
}
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
@@ -2263,9 +2272,7 @@ namespace JoyD.Windows.CS.Toprie
continue;
}
// 将PaletteType枚举转换为int类型并发送命令
// 按照SDK文档中的参数映射白热(0)、黑热(1)、铁红(2)、熔岩(3)、彩虹(4)、铁灰(5)、红热(6)、彩虹2(7)
int paletteValue = (int)paletteType;
// 已在循环外部计算paletteValue避免重复计算
// 直接设置色彩模式,不再在每次尝试中读取原始值
_a8Sdk.Color_plate = paletteValue;
@@ -2276,6 +2283,11 @@ namespace JoyD.Windows.CS.Toprie
// 减少读取验证避免嵌套UDP命令
// 信任SDK的设置操作不再额外验证
Log($"色彩模式设置成功: {paletteType} (值: {paletteValue})");
// 移除图像接收重启逻辑,因为色彩模式不影响图像接收
// 仅保留短暂延迟确保设置生效
Thread.Sleep(200); // 给设备处理时间
return true;
// 注释掉需要再次读取验证的代码避免嵌套UDP命令

View File

@@ -22,6 +22,9 @@ namespace JoyD.Windows.CS.Toprie
private const string CMD_HEAD = "+CMD";
private const int DISCOVERY_UDP_PORT = 18889;
private const int SEARCH_DEVICE_MAX_NUM = 99;
// 日志文件路径
private static readonly string LogFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log.txt");
// 命令类型枚举
private enum CMD_TYPE
@@ -460,7 +463,7 @@ namespace JoyD.Windows.CS.Toprie
}
}
set
{
{;
try
{
// 使用SDK格式设置快门校正时间: ip:param_mode,param_value$
@@ -483,68 +486,224 @@ namespace JoyD.Windows.CS.Toprie
}
private int _lastKnownColorPlate = 0; // 保存最后已知的色板值
private readonly object _colorPlateLock = new object(); // 线程锁,确保日志记录的线程安全
/// <summary>
/// 静态日志写入方法
/// </summary>
/// <param name="message">日志消息</param>
public static void Log(string message)
{
try
{
// 确保日志目录存在
string logDirectory = Path.GetDirectoryName(LogFilePath);
if (!Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
// 写入日志,不添加额外时间戳(因为原始消息已包含时间戳)
File.AppendAllText(LogFilePath, message + Environment.NewLine);
// 同时输出到控制台
Console.WriteLine(message);
}
catch (Exception ex)
{
// 如果日志写入失败,至少输出到控制台
Console.WriteLine($"[日志写入失败] {ex.Message}");
}
}
public int Color_plate
{
get
{
try
lock (_colorPlateLock)
{
// 使用SDK格式获取色板: ip:param_mode,param_value$
string command = $"{deviceIp}:{(int)CMD_TYPE.GET_PARAMETER},{(int)PARAM_TYPE.COLOR_PLATE}$";
if (SendCommand(command, out string response))
try
{
int parsedValue = ParseResponseValue(response);
if (parsedValue != 0 || response != null) // 确保至少解析成功或有响应
const int maxRetries = 3;
int retryCount = 0;
bool success = false;
int resultValue = _lastKnownColorPlate;
while (retryCount < maxRetries && !success)
{
_lastKnownColorPlate = parsedValue;
return parsedValue;
retryCount++;
// 使用SDK格式获取色板: ip:param_mode,param_value$
string command = $"{deviceIp}:{(int)CMD_TYPE.GET_PARAMETER},{(int)PARAM_TYPE.COLOR_PLATE}$";
Log($"[色彩模式读取] 开始获取色彩模式值{(retryCount > 1 ? " ( " + retryCount + "/" + maxRetries + ")" : "")},发送命令: {command}");
if (SendCommand(command, out string response))
{
Log($"[色彩模式读取] 收到响应: {response}");
try
{
int parsedValue = ParseResponseValue(response);
if (response != null && parsedValue != -1) // 确保响应有效且解析成功
{
Log($"[色彩模式读取] 解析成功,当前值: {parsedValue},上一次值: {_lastKnownColorPlate}");
_lastKnownColorPlate = parsedValue;
resultValue = parsedValue;
success = true;
}
else if (retryCount < maxRetries)
{
Log($"[色彩模式读取] 解析失败或响应无效,将重试...");
System.Threading.Thread.Sleep(200); // 短暂延迟后重试
}
else
{
Log($"[色彩模式读取] 解析失败或响应无效,返回上次已知值: {_lastKnownColorPlate}");
}
}
catch (Exception ex)
{
if (retryCount < maxRetries)
{
Log($"[色彩模式读取] 解析异常: {ex.Message},将重试...");
System.Threading.Thread.Sleep(200); // 短暂延迟后重试
}
else
{
Log($"[色彩模式读取] 解析异常: {ex.Message},返回上次已知值: {_lastKnownColorPlate}");
}
}
}
else if (retryCount < maxRetries)
{
Log($"[色彩模式读取] 命令发送失败或超时,将重试...");
System.Threading.Thread.Sleep(200); // 短暂延迟后重试
}
else
{
Log($"[色彩模式读取] 命令发送失败或超时,返回上次已知值: {_lastKnownColorPlate}");
}
}
Log($"成功读取当前色彩模式值: {resultValue}"); // 添加一致的成功日志
return resultValue;
}
catch (Exception ex)
{
Log($"[色彩模式读取异常] {ex.Message},返回上次已知值: {_lastKnownColorPlate}");
return _lastKnownColorPlate;
}
Console.WriteLine("获取色板失败,返回上次已知值");
return _lastKnownColorPlate; // 返回上次已知值
}
catch (Exception ex)
{
Console.WriteLine($"获取色板异常: {ex.Message},返回上次已知值");
return _lastKnownColorPlate;
}
}
set
{
try
lock (_colorPlateLock)
{
// 使用SDK格式设置色板: ip:param_mode,param_value$
string command = $"{deviceIp}:{(int)CMD_TYPE.SET_COLOR_PLATE},{value}$";
bool success = SendCommand(command, out string response);
if (success && response != null)
try
{
// 验证响应是否包含成功标记
bool responseValid = response.Contains("+RET:") &&
(!response.Contains("error") || !response.Contains("失败"));
int currentValue = GetColor_plateWithoutLock();
Log($"[色彩模式设置] 开始设置色彩模式值为: {value},当前值: {currentValue}");
if (responseValid)
// 如果值相同,不需要设置
if (currentValue == value)
{
Console.WriteLine($"设置色板成功: {value}");
_lastKnownColorPlate = value; // 更新最后已知值
Log($"[色彩模式设置] 当前色彩模式已为目标值,无需设置");
return;
}
// 使用SDK格式设置色板: ip:param_mode,param_value$
string command = $"{deviceIp}:{(int)CMD_TYPE.SET_COLOR_PLATE},{value}$";
Log($"[色彩模式设置] 发送命令: {command}");
bool success = SendCommand(command, out string response);
if (success && response != null)
{
Log($"[色彩模式设置] 收到响应: {response}");
// 验证响应是否包含成功标记
bool responseValid = response.Contains("+RET:") &&
(!response.Contains("error") && !response.Contains("失败"));
if (responseValid)
{
Log($"[色彩模式设置成功] 从 {_lastKnownColorPlate} 变更为 {value}");
_lastKnownColorPlate = value; // 更新最后已知值
// 验证设置是否生效
Log($"[色彩模式设置] 验证设置是否生效...");
int validatedValue = GetColor_plateWithoutLock();
if (validatedValue == value)
{
Log($"[色彩模式设置] 验证成功,当前值确认为: {validatedValue}");
// 设置成功后重启图像接收以避免卡顿
Log($"[色彩模式设置] 设置成功后重启图像接收以避免卡顿");
SafeRestartImageReceiving();
}
else
{
Log($"[色彩模式设置] 验证失败,实际值: {validatedValue},期望值: {value}");
}
}
else
{
Log($"[色彩模式设置失败] 响应验证失败: {response}");
}
}
else
{
Console.WriteLine($"设置色板响应验证失败: {response}");
Log($"[色彩模式设置失败] 命令发送失败或超时响应为null: {success}");
}
}
else
catch (Exception ex)
{
Console.WriteLine($"设置色板失败: 命令发送失败或超时");
Log($"[色彩模式设置异常] {ex.Message}");
}
}
catch (Exception ex)
}
}
/// <summary>
/// 不带锁获取色彩模式,避免在设置后验证时出现死锁
/// </summary>
private int GetColor_plateWithoutLock()
{
try
{
string command = $"{deviceIp}:{(int)CMD_TYPE.GET_PARAMETER},{(int)PARAM_TYPE.COLOR_PLATE}$";
if (SendCommand(command, out string response))
{
Console.WriteLine($"设置色板异常: {ex.Message}");
return ParseResponseValue(response);
}
}
catch (Exception ex)
{
Log($"[GetColor_plateWithoutLock异常] {ex.Message}");
}
return _lastKnownColorPlate;
}
/// <summary>
/// 安全地重启图像接收,避免重复停止和启动
/// </summary>
private void SafeRestartImageReceiving()
{
try
{
// 注意V8类不直接管理图像接收和连接检查
// 这个方法被Color_plate属性调用主要是为了在设置色彩模式后提供稳定的过渡时间
Log("执行色彩模式变更后的稳定处理");
// 添加短暂延迟以确保设备有时间处理色彩模式变更
System.Threading.Thread.Sleep(300);
Log("色彩模式变更后的稳定处理完成");
}
catch (Exception ex)
{
Log($"色彩模式变更后稳定处理过程中发生异常: {ex.Message}");
}
}
public int Mirror_mode
@@ -2146,6 +2305,6 @@ namespace JoyD.Windows.CS.Toprie
Console.WriteLine($"获取图像数据失败: {ex.Message}");
return new byte[0];
}
}
}
}
}
}