diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs index aa822b0..8e925b3 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs @@ -205,6 +205,7 @@ namespace JoyD.Windows.CS.Toprie if (_isReceivingImage) { _deviceManager.StopImageReceiving(); + _deviceManager.StopTemperatureDataReceiving(); _isReceivingImage = false; } } @@ -224,7 +225,9 @@ namespace JoyD.Windows.CS.Toprie if (_deviceManager.ConnectionStatus == ConnectionStatus.Connected) { _deviceManager.StopImageReceiving(); + _deviceManager.StopTemperatureDataReceiving(); _deviceManager.StartImageReceiving(); + _deviceManager.StartTemperatureDataReceiving(); _isReceivingImage = true; // 恢复检测后,启动连接检查以确保连接正常 @@ -503,6 +506,7 @@ namespace JoyD.Windows.CS.Toprie Console.WriteLine("Camera开始使用HTTP方式接收图像"); // 直接调用HTTP方式的图像接收 _deviceManager.StartImageReceiving(); + _deviceManager.StartTemperatureDataReceiving(); _isReceivingImage = true; } } diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs index 830af27..cf6c206 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs @@ -69,6 +69,25 @@ namespace JoyD.Windows.CS.Toprie Fusion5 // 融合5,对应SDK参数6 } + /// + /// 温度模式枚举 + /// + public enum TemperatureMode + { + /// + /// 摄氏度 + /// + Celsius, + /// + /// 华氏度 + /// + Fahrenheit, + /// + /// 开尔文 + /// + Kelvin + } + /// /// 连接状态改变事件参数 /// @@ -242,6 +261,14 @@ namespace JoyD.Windows.CS.Toprie private Thread _imageReconnectThread; private Stream _imageStream; + // 温度数据接收相关字段 + private Thread _temperatureReceiveThread; + private TcpClient _temperatureTcpClient; + private NetworkStream _temperatureStream; + private bool _isReceivingTemperatureData = false; + private ManualResetEvent _stopTemperatureEvent; + private const int TEMPERATURE_TCP_PORT = 7682; // 温度数据TCP端口 + /// /// 项目路径属性 /// 用于设置控件存取数据文件的目录 @@ -610,6 +637,10 @@ namespace JoyD.Windows.CS.Toprie // 启动图像接收 Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 连接成功,启动图像接收"); StartImageReceiving(); + + // 启动温度数据接收 + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 启动温度数据接收"); + StartTemperatureDataReceiving(); return true; } @@ -645,6 +676,8 @@ namespace JoyD.Windows.CS.Toprie StopAutoReconnect(); StopHeartbeat(); StopConnectionCheck(); + // 停止温度数据接收 + StopTemperatureDataReceiving(); // 安全释放SDK实例 A8SDK oldSdk = Interlocked.Exchange(ref _a8Sdk, null); @@ -802,6 +835,377 @@ namespace JoyD.Windows.CS.Toprie #endregion 私有方法 + #region 温度数据处理方法 + + /// + /// 获取温度补偿值 + /// + /// 温度补偿值 + private float GetTemperatureCompensationValue() + { + try + { + if (_connectionStatus == ConnectionStatus.Connected && _a8Sdk != null) + { + float compensationValue = _a8Sdk.Comp_temp; + Log($"获取温度补偿值: {compensationValue}"); + return compensationValue; + } + } + catch (Exception ex) + { + Log($"获取温度补偿值异常: {ex.Message}"); + } + return 0.0f; + } + + /// + /// 开始接收温度数据 + /// + public void StartTemperatureDataReceiving() + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 开始执行"); + + // 在设计模式下,跳过实际的温度数据接收 + if (IsDesignMode) + { + Log("设计模式下跳过实际的温度数据接收"); + return; + } + + lock (_lockObject) + { + // 检查对象是否已被释放 + if (_isDisposed) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 对象已释放,忽略操作"); + return; + } + + // 检查连接状态 + if (_connectionStatus != ConnectionStatus.Connected) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 连接未建立,无法开始温度数据接收"); + return; + } + } + + Log("开始使用TCP方式接收温度数据"); + try + { + // 确保之前的连接已关闭 + StopTemperatureDataReceiving(); + + // 重置停止事件 + _stopTemperatureEvent = new ManualResetEvent(false); + lock (_lockObject) + { + _isReceivingTemperatureData = true; + } + + // 创建并启动温度数据接收线程 + _temperatureReceiveThread = new Thread(ReceiveTemperatureDataWithTcp) + { + IsBackground = true, + Name = "TemperatureReceiveThread" + }; + _temperatureReceiveThread.Start(); + } + catch (Exception ex) + { + // 记录异常 + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 异常: {ex.Message}"); + lock (_lockObject) + { + _isReceivingTemperatureData = false; + } + + // 如果连接状态异常,触发异常事件 + OnConnectionException(new ConnectionExceptionEventArgs(ex, "启动温度数据接收失败")); + } + finally + { + // 确保方法执行完成时记录日志 + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 执行完成"); + } + } + + /// + /// 停止接收温度数据 + /// + public void StopTemperatureDataReceiving() + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 开始执行"); + + if (_isDisposed) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 对象已释放,跳过操作"); + return; + } + + try + { + // 线程安全地更新状态 + lock (_lockObject) + { + _isReceivingTemperatureData = false; + } + + // 通知线程停止 + ManualResetEvent stopEvent = null; + lock (_lockObject) + { + stopEvent = _stopTemperatureEvent; + } + + if (stopEvent != null) + { + try + { + stopEvent.Set(); + } + catch (ObjectDisposedException) + { + // 忽略已释放的事件 + } + } + + // 等待线程结束 + Thread temperatureThread = null; + lock (_lockObject) + { + temperatureThread = _temperatureReceiveThread; + } + + if (temperatureThread != null && temperatureThread.IsAlive) + { + temperatureThread.Join(1000); // 等待最多1秒 + Log("温度接收线程已停止"); + } + + // 关闭TCP客户端和流 + NetworkStream stream = null; + TcpClient client = null; + + lock (_lockObject) + { + stream = _temperatureStream; + client = _temperatureTcpClient; + _temperatureStream = null; + _temperatureTcpClient = null; + } + + if (stream != null) + { + try + { + stream.Close(); + } + catch (Exception) + {} + } + + if (client != null) + { + try + { + client.Close(); + } + catch (Exception) + {} + } + } + catch (Exception ex) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 异常: {ex.Message}"); + } + finally + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 执行完成"); + } + } + + /// + /// 使用TCP接收温度数据 + /// + private void ReceiveTemperatureDataWithTcp() + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 开始执行"); + + try + { + // 创建TCP客户端并连接到设备的温度数据端口 + _temperatureTcpClient = new TcpClient(); + _temperatureTcpClient.ReceiveTimeout = 5000; + _temperatureTcpClient.SendTimeout = 5000; + + IAsyncResult result = _temperatureTcpClient.BeginConnect(_deviceIp, TEMPERATURE_TCP_PORT, null, null); + bool connected = result.AsyncWaitHandle.WaitOne(3000, true); + + if (!connected || !_temperatureTcpClient.Connected) + { + Log("温度数据TCP连接失败,超时"); + return; + } + + _temperatureTcpClient.EndConnect(result); + Log("温度数据TCP连接成功"); + + // 获取网络流 + _temperatureStream = _temperatureTcpClient.GetStream(); + _temperatureStream.ReadTimeout = 5000; + + byte[] buffer = new byte[8192]; // 温度数据缓冲区 + List temperatureDataAccumulator = new List(); + + // 发送开始温度数据传输的命令 + byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n"); + _temperatureStream.Write(startCommand, 0, startCommand.Length); + _temperatureStream.Flush(); + + Log("已发送开始温度数据传输命令,开始接收温度数据"); + + while (!_stopTemperatureEvent.WaitOne(0)) + { + try + { + // 检查连接状态 + if (!_temperatureTcpClient.Connected) + { + Log("温度数据TCP连接已断开"); + break; + } + + // 读取数据 + int bytesRead = _temperatureStream.Read(buffer, 0, buffer.Length); + if (bytesRead > 0) + { + // 将读取的数据添加到累积器 + byte[] receivedBytes = new byte[bytesRead]; + Array.Copy(buffer, receivedBytes, bytesRead); + temperatureDataAccumulator.AddRange(receivedBytes); + + // 处理累积的数据 + ProcessReceivedTemperatureData(temperatureDataAccumulator); + } + } + catch (TimeoutException) + { + // 超时异常,继续尝试读取 + Log("温度数据接收超时,继续尝试"); + } + catch (IOException ex) + { + Log($"温度数据接收IO异常: {ex.Message}"); + break; + } + catch (Exception ex) + { + Log($"温度数据接收异常: {ex.Message}"); + // 非致命异常,继续尝试 + } + } + } + catch (Exception ex) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 严重异常: {ex.Message}"); + } + finally + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 执行完成"); + + // 确保状态正确更新 + lock (_lockObject) + { + _isReceivingTemperatureData = false; + } + + // 清理资源 + StopTemperatureDataReceiving(); + } + } + + /// + /// 处理接收到的温度数据 + /// + /// 累积的温度数据 + private void ProcessReceivedTemperatureData(List dataAccumulator) + { + const int TEMPERATURE_DATA_FRAME_SIZE = 256 * 192 * 2; // 假设分辨率为256x192,每个温度值2字节 + + try + { + // 检查是否有足够的数据构成完整的温度数据帧 + while (dataAccumulator.Count >= TEMPERATURE_DATA_FRAME_SIZE) + { + // 提取一帧温度数据 + byte[] temperatureFrame = dataAccumulator.GetRange(0, TEMPERATURE_DATA_FRAME_SIZE).ToArray(); + dataAccumulator.RemoveRange(0, TEMPERATURE_DATA_FRAME_SIZE); + + // 获取温度补偿值 + float compensationValue = GetTemperatureCompensationValue(); + + // 创建温度数据对象 + TemperatureData temperatureData = new TemperatureData(temperatureFrame, compensationValue); + + // 触发温度数据接收事件 + OnTemperatureReceived(new TemperatureReceivedEventArgs(temperatureData, temperatureFrame, compensationValue)); + } + } + catch (Exception ex) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ProcessReceivedTemperatureData() - 异常: {ex.Message}"); + // 清空累积器,重新开始 + dataAccumulator.Clear(); + } + } + + /// + /// 触发温度数据接收事件 + /// + /// 事件参数 + protected virtual void OnTemperatureReceived(TemperatureReceivedEventArgs e) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 开始执行"); + + // 检查参数有效性 + if (e == null) + { + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 参数为空,跳过事件触发"); + return; + } + + // 获取事件处理程序的快照,避免在多线程环境中出现竞态条件 + EventHandler handler = TemperatureReceived; + + // 检查是否有订阅者 + if (handler != null) + { + // 获取所有订阅的委托,单独处理每个处理器 + Delegate[] invocationList = handler.GetInvocationList(); + + foreach (Delegate d in invocationList) + { + try + { + // 安全地转换并调用每个处理器 + EventHandler invoker = (EventHandler)d; + invoker(this, e); + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 成功触发一个事件处理器: {d.Method.Name}"); + } + catch (Exception ex) + { + // 捕获单个事件处理器的异常,确保其他处理器仍能被调用 + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 事件处理器异常: {ex.Message}"); + } + } + } + + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 执行完成"); + } + + #endregion 温度数据处理方法 + #region 公共事件 /// @@ -818,6 +1222,11 @@ namespace JoyD.Windows.CS.Toprie /// 图像数据接收事件 /// public event EventHandler ImageReceived; + + /// + /// 温度数据接收事件 + /// + public event EventHandler TemperatureReceived; #endregion 公共事件 @@ -1669,6 +2078,9 @@ namespace JoyD.Windows.CS.Toprie { _isReceivingImages = false; } + + // 同步停止温度数据接收 + StopTemperatureDataReceiving(); // 通知线程停止 ManualResetEvent stopEvent = null; @@ -2405,6 +2817,25 @@ namespace JoyD.Windows.CS.Toprie set { _currentPaletteType = value; } } + /// + /// 当前温度模式 + /// + public TemperatureMode CurrentTemperatureMode { get; set; } = TemperatureMode.Celsius; + + /// + /// 是否正在接收温度数据 + /// + public bool IsReceivingTemperatureData + { + get + { + lock (_lockObject) + { + return _isReceivingTemperatureData; + } + } + } + /// /// 获取或设置当前视频模式 /// @@ -4663,5 +5094,295 @@ namespace JoyD.Windows.CS.Toprie } #endregion IDisposable 实现 + + #region 温度相关辅助类 + + /// + /// 温度数据事件参数类 + /// + public class TemperatureReceivedEventArgs : EventArgs + { + /// + /// 温度数据对象 + /// + public TemperatureData TemperatureData { get; private set; } + + /// + /// 原始温度数据字节数组 + /// + public byte[] RawData { get; private set; } + + /// + /// 温度补偿值 + /// + public float CompensationValue { get; private set; } + + /// + /// 构造函数 + /// + /// 温度数据对象 + /// 原始温度数据 + /// 温度补偿值 + public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue) + { + TemperatureData = temperatureData; + RawData = rawData; + CompensationValue = compensationValue; + } + } + + /// + /// 温度数据类,用于存储和处理温度数据 + /// + public class TemperatureData + { + /// + /// 温度数据数组 + /// + public float[,] Data { get; private set; } + + /// + /// 温度数据的宽度(像素) + /// + public int Width { get; private set; } + + /// + /// 温度数据的高度(像素) + /// + public int Height { get; private set; } + + /// + /// 温度补偿值 + /// + public float CompensationValue { get; private set; } + + /// + /// 最大温度值 + /// + public float MaxTemperature { get; private set; } + + /// + /// 最小温度值 + /// + public float MinTemperature { get; private set; } + + /// + /// 平均温度值 + /// + public float AverageTemperature { get; private set; } + + /// + /// 构造函数 + /// + /// 原始温度数据字节数组 + /// 温度补偿值 + public TemperatureData(byte[] rawData, float compensationValue) + { + // 假设分辨率为256x192 + Width = 256; + Height = 192; + CompensationValue = compensationValue; + + // 初始化温度数据数组 + Data = new float[Height, Width]; + + // 解析原始数据 + ParseRawData(rawData); + + // 计算温度统计信息 + CalculateStatistics(); + } + + /// + /// 解析原始温度数据 + /// + /// 原始温度数据字节数组 + private void ParseRawData(byte[] rawData) + { + try + { + // 假设每个温度值由2字节表示 + for (int i = 0; i < Height; i++) + { + for (int j = 0; j < Width; j++) + { + int index = (i * Width + j) * 2; + if (index + 1 < rawData.Length) + { + // 读取2字节数据并转换为温度值 + short rawTempValue = (short)((rawData[index + 1] << 8) | rawData[index]); + + // 转换为实际温度值(假设温度值为原始值除以某个系数) + // 这里使用一个示例转换公式,实际转换方式需要根据设备的数据格式确定 + float temperature = rawTempValue / 100.0f + CompensationValue; + + Data[i, j] = temperature; + } + } + } + } + catch (Exception ex) + { + // 记录异常但不抛出,确保即使解析出错也能继续执行 + Console.WriteLine($"解析温度数据异常: {ex.Message}"); + } + } + + /// + /// 计算温度统计信息 + /// + private void CalculateStatistics() + { + if (Data == null || Data.Length == 0) + { + MaxTemperature = MinTemperature = AverageTemperature = 0.0f; + return; + } + + float sum = 0.0f; + MaxTemperature = float.MinValue; + MinTemperature = float.MaxValue; + int validCount = 0; + + for (int i = 0; i < Height; i++) + { + for (int j = 0; j < Width; j++) + { + float temp = Data[i, j]; + // 跳过无效温度值 + if (!float.IsNaN(temp) && !float.IsInfinity(temp)) + { + sum += temp; + MaxTemperature = Math.Max(MaxTemperature, temp); + MinTemperature = Math.Min(MinTemperature, temp); + validCount++; + } + } + } + + // 计算平均温度 + AverageTemperature = validCount > 0 ? sum / validCount : 0.0f; + } + + /// + /// 获取指定区域的温度数据 + /// + /// 区域左上角X坐标 + /// 区域左上角Y坐标 + /// 区域宽度 + /// 区域高度 + /// 区域温度数据,如果参数无效则返回null + public TemperatureData GetRegionData(int x, int y, int width, int height) + { + // 验证参数 + if (x < 0 || y < 0 || width <= 0 || height <= 0 || + x + width > Width || y + height > Height) + { + return null; + } + + // 创建区域温度数据数组 + float[,] regionData = new float[height, width]; + + // 复制区域数据 + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + regionData[i, j] = Data[y + i, x + j]; + } + } + + // 创建新的温度数据对象 + TemperatureData result = new TemperatureData(); + result.Width = width; + result.Height = height; + result.CompensationValue = CompensationValue; + result.Data = regionData; + result.CalculateStatistics(); + + return result; + } + + /// + /// 获取指定坐标的温度值(摄氏度) + /// + /// X坐标 + /// Y坐标 + /// 温度值,如果坐标无效则返回NaN + public float GetTemperatureAt(int x, int y) + { + if (x < 0 || x >= Width || y < 0 || y >= Height) + { + return float.NaN; + } + return Data[y, x]; + } + + /// + /// 将温度数据转换为指定的温度模式 + /// + /// 目标温度模式 + /// 转换后的温度数据副本 + public TemperatureData ConvertTo(TemperatureMode mode) + { + // 创建新的温度数据对象 + TemperatureData result = new TemperatureData(); + result.Width = Width; + result.Height = Height; + result.CompensationValue = CompensationValue; + result.Data = new float[Height, Width]; + + // 根据目标模式进行转换 + switch (mode) + { + case TemperatureMode.Celsius: + // 如果当前已经是摄氏度,直接复制数据 + for (int i = 0; i < Height; i++) + { + for (int j = 0; j < Width; j++) + { + result.Data[i, j] = Data[i, j]; + } + } + break; + + case TemperatureMode.Fahrenheit: + // 摄氏度转华氏度: F = C * 9/5 + 32 + for (int i = 0; i < Height; i++) + { + for (int j = 0; j < Width; j++) + { + result.Data[i, j] = Data[i, j] * 9.0f / 5.0f + 32.0f; + } + } + break; + + case TemperatureMode.Kelvin: + // 摄氏度转开尔文: K = C + 273.15 + for (int i = 0; i < Height; i++) + { + for (int j = 0; j < Width; j++) + { + result.Data[i, j] = Data[i, j] + 273.15f; + } + } + break; + } + + // 重新计算统计信息 + result.CalculateStatistics(); + + return result; + } + + /// + /// 私有构造函数,用于内部创建 + /// + private TemperatureData() + {} + } + + #endregion 温度相关辅助类 } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs new file mode 100644 index 0000000..e60b3bd --- /dev/null +++ b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Toprie +{ + /// + /// 温度数据模型类,用于存储和处理红外热像仪采集的温度数据 + /// + public class TemperatureData + { + /// + /// 温度数据矩阵 + /// 格式: [行][列] + /// + public float[,] TemperatureMatrix { get; private set; } + + /// + /// 温度数据的宽度(列数) + /// + public int Width { get; private set; } + + /// + /// 温度数据的高度(行数) + /// + public int Height { get; private set; } + + /// + /// 温度采集时间戳 + /// + public DateTime Timestamp { get; set; } + + /// + /// 最低温度值 + /// + public float MinTemperature { get; private set; } + + /// + /// 最高温度值 + /// + public float MaxTemperature { get; private set; } + + /// + /// 平均温度值 + /// + public float AverageTemperature { get; private set; } + + /// + /// 根据原始数据创建温度数据实例 + /// + /// 原始温度数据(每个温度点为2字节) + /// 温度矩阵宽度 + /// 温度矩阵高度 + /// 温度补偿值(从sdk_get_comp_temp获取) + public TemperatureData(byte[] rawData, int width, int height, float compensationValue = 0) + { + if (rawData == null) + throw new ArgumentNullException(nameof(rawData)); + + if (width <= 0 || height <= 0) + throw new ArgumentException("宽度和高度必须大于0"); + + Width = width; + Height = height; + TemperatureMatrix = new float[height, width]; + Timestamp = DateTime.Now; + + ParseRawData(rawData, compensationValue); + CalculateStatistics(); + } + + /// + /// 解析原始温度数据 + /// + /// 原始温度数据 + /// 温度补偿值 + private void ParseRawData(byte[] rawData, float compensationValue) + { + // 按照SDK文档,温度数据为每个点2字节,摄氏温度=(H*256+L)/10 + // 需要考虑数据分布逻辑:先发送第一行奇数列,再发送第一行偶数列,接着第二行奇数列,依此类推 + int dataIndex = 0; + + // 处理奇数列 + for (int row = 0; row < Height; row++) + { + for (int col = 0; col < Width; col += 2) + { + if (dataIndex + 1 < rawData.Length) + { + // 按照SDK文档计算温度值:摄氏温度=(H*256+L)/10 + // 这里假设H是高位字节,L是低位字节 + int highByte = rawData[dataIndex]; + int lowByte = rawData[dataIndex + 1]; + float temperature = (highByte * 256 + lowByte) / 10.0f; + + // 应用温度补偿值 + temperature += compensationValue; + + TemperatureMatrix[row, col] = temperature; + dataIndex += 2; + } + } + } + + // 处理偶数列 + dataIndex = 0; // 重置索引,重新遍历 + for (int row = 0; row < Height; row++) + { + for (int col = 1; col < Width; col += 2) + { + if (dataIndex + 1 < rawData.Length) + { + int highByte = rawData[dataIndex]; + int lowByte = rawData[dataIndex + 1]; + float temperature = (highByte * 256 + lowByte) / 10.0f; + + // 应用温度补偿值 + temperature += compensationValue; + + TemperatureMatrix[row, col] = temperature; + dataIndex += 2; + } + } + } + } + + /// + /// 计算温度统计信息 + /// + private void CalculateStatistics() + { + float sum = 0; + float min = float.MaxValue; + float max = float.MinValue; + int count = 0; + + for (int row = 0; row < Height; row++) + { + for (int col = 0; col < Width; col++) + { + float temp = TemperatureMatrix[row, col]; + sum += temp; + min = Math.Min(min, temp); + max = Math.Max(max, temp); + count++; + } + } + + MinTemperature = min; + MaxTemperature = max; + AverageTemperature = count > 0 ? sum / count : 0; + } + + /// + /// 获取指定区域内的温度统计信息 + /// + /// 起始行 + /// 起始列 + /// 结束行 + /// 结束列 + /// 区域温度统计信息 + public RegionTemperatureStats GetRegionStatistics(int startRow, int startCol, int endRow, int endCol) + { + // 参数验证和边界检查 + startRow = Math.Max(0, startRow); + startCol = Math.Max(0, startCol); + endRow = Math.Min(Height - 1, endRow); + endCol = Math.Min(Width - 1, endCol); + + if (startRow > endRow || startCol > endCol) + return new RegionTemperatureStats(0, 0, 0, 0); + + float sum = 0; + float min = float.MaxValue; + float max = float.MinValue; + int count = 0; + + for (int row = startRow; row <= endRow; row++) + { + for (int col = startCol; col <= endCol; col++) + { + float temp = TemperatureMatrix[row, col]; + sum += temp; + min = Math.Min(min, temp); + max = Math.Max(max, temp); + count++; + } + } + + float avg = count > 0 ? sum / count : 0; + return new RegionTemperatureStats(min, max, avg, count); + } + + /// + /// 将温度矩阵转换为字节数组(用于保存或传输) + /// + /// 温度数据的字节数组表示 + public byte[] ToByteArray() + { + // 创建一个包含所有必要信息的字节数组 + // 包括宽度、高度、时间戳和温度数据 + int headerSize = 4 + 4 + 8; // width(4) + height(4) + timestamp(8) + int dataSize = Width * Height * 4; // 每个温度值使用4字节float + byte[] result = new byte[headerSize + dataSize]; + + // 写入头信息 + Buffer.BlockCopy(BitConverter.GetBytes(Width), 0, result, 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Height), 0, result, 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Timestamp.Ticks), 0, result, 8, 8); + + // 写入温度数据 + int dataIndex = headerSize; + for (int row = 0; row < Height; row++) + { + for (int col = 0; col < Width; col++) + { + byte[] tempBytes = BitConverter.GetBytes(TemperatureMatrix[row, col]); + Buffer.BlockCopy(tempBytes, 0, result, dataIndex, 4); + dataIndex += 4; + } + } + + return result; + } + + /// + /// 从字节数组创建TemperatureData实例 + /// + /// 包含温度数据的字节数组 + /// TemperatureData实例 + public static TemperatureData FromByteArray(byte[] data) + { + if (data == null || data.Length < 16) // 至少需要头信息的长度 + throw new ArgumentException("无效的数据格式"); + + int width = BitConverter.ToInt32(data, 0); + int height = BitConverter.ToInt32(data, 4); + long ticks = BitConverter.ToInt64(data, 8); + DateTime timestamp = new DateTime(ticks); + + // 验证数据完整性 + int expectedSize = 16 + width * height * 4; + if (data.Length != expectedSize) + throw new ArgumentException("数据长度不匹配"); + + // 创建温度矩阵 + float[,] matrix = new float[height, width]; + int dataIndex = 16; + + for (int row = 0; row < height; row++) + { + for (int col = 0; col < width; col++) + { + matrix[row, col] = BitConverter.ToSingle(data, dataIndex); + dataIndex += 4; + } + } + + // 创建TemperatureData实例 + TemperatureData tempData = new TemperatureData(); + tempData.Width = width; + tempData.Height = height; + tempData.TemperatureMatrix = matrix; + tempData.Timestamp = timestamp; + tempData.CalculateStatistics(); + + return tempData; + } + + /// + /// 私有构造函数,用于FromByteArray方法 + /// + private TemperatureData() + { } + } + + /// + /// 区域温度统计信息 + /// + public struct RegionTemperatureStats + { + /// + /// 区域最低温度 + /// + public float MinTemperature { get; } + + /// + /// 区域最高温度 + /// + public float MaxTemperature { get; } + + /// + /// 区域平均温度 + /// + public float AverageTemperature { get; } + + /// + /// 统计的温度点数量 + /// + public int PointCount { get; } + + /// + /// 构造函数 + /// + /// 最低温度 + /// 最高温度 + /// 平均温度 + /// 温度点数量 + public RegionTemperatureStats(float minTemp, float maxTemp, float avgTemp, int count) + { + MinTemperature = minTemp; + MaxTemperature = maxTemp; + AverageTemperature = avgTemp; + PointCount = count; + } + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureReceivedEventArgs.cs b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureReceivedEventArgs.cs new file mode 100644 index 0000000..849d4f5 --- /dev/null +++ b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureReceivedEventArgs.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Toprie +{ + /// + /// 温度数据接收事件参数类 + /// 用于在接收到温度数据时传递相关信息 + /// + public class TemperatureReceivedEventArgs : EventArgs + { + /// + /// 温度数据对象 + /// + public TemperatureData TemperatureData { get; private set; } + + /// + /// 原始温度数据(可选,用于调试或特殊处理) + /// + public byte[] RawData { get; private set; } + + /// + /// 温度补偿值 + /// + public float CompensationValue { get; private set; } + + /// + /// 构造函数 + /// + /// 解析后的温度数据对象 + public TemperatureReceivedEventArgs(TemperatureData temperatureData) + { + TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData)); + RawData = null; + CompensationValue = 0; + } + + /// + /// 构造函数(包含原始数据和补偿值) + /// + /// 解析后的温度数据对象 + /// 原始温度数据 + /// 温度补偿值 + public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue) + { + TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData)); + RawData = rawData; + CompensationValue = compensationValue; + } + + /// + /// 获取温度统计摘要信息 + /// + public string GetStatisticsSummary() + { + return $"温度统计 - 最低: {TemperatureData.MinTemperature:F2}°C, " + + $"最高: {TemperatureData.MaxTemperature:F2}°C, " + + $"平均: {TemperatureData.AverageTemperature:F2}°C, " + + $"数据点: {TemperatureData.Width}x{TemperatureData.Height} ({TemperatureData.Width * TemperatureData.Height}), " + + $"采集时间: {TemperatureData.Timestamp:yyyy-MM-dd HH:mm:ss.fff}"; + } + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj b/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj index 817a1a5..b4eb9e6 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj @@ -73,6 +73,8 @@ + +