Files
hoodFieldOfView/头罩视野slove/头罩视野/Views/RecordDate.xaml.cs
2026-04-24 17:47:59 +08:00

387 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Win32;
using Modbus.Device;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using .Services.Data;
using static .TestDataStore;
namespace .Views
{
/// <summary>
/// RecordDate.xaml 的交互逻辑
/// </summary>
///
public partial class RecordDate : Page
{
private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
private System.Timers.Timer? _plcReadTimer;
// 表跟数据存储列表
private List<dynamic> LeftEyeDataList = new List<dynamic>();
private List<dynamic> RightEyeDataList = new List<dynamic>();
// 配置和你PLC地址完全对应 左目
private const int LeftEyeStartAddress = 1362; // D1362
private const int ChannelCount = 72; // 72个通道
private const int RegistersPerChannel = 2; // 每个通道2个寄存器Float
//右目
private const int RightEyeStartAddress = 1218; // D1218
// 长按清除用
private bool _isClearPressed = false;
private Thread _clearThread;
private List<ushort> leftEyeDataList;
public RecordDate()
{
InitializeComponent();
DynamicHeader();
// 2. 调用(名字和上面的变量一致)
// 2. 启动定时器定时读取数据每100ms读一次
//StartPlcReadTimer(100);
//// 判断连接
if (!ModbusHelper.IsConnected)
{
MessageBox.Show("未连接");
return;
}
}
//动态生成表头
void DynamicHeader()
{
// 2. 循环生成 64 个 ch 列
for (int i = 1; i <= ChannelCount; i++)
{
dataGrid1.Columns.Add(new DataGridTextColumn
{
Header = $"ch.{i}",
Binding = new System.Windows.Data.Binding($"Ch{i}")
});
dataGrid2.Columns.Add(new DataGridTextColumn
{
Header = $"ch.{i}",
Binding = new System.Windows.Data.Binding($"Ch{i}")
});
}
}
public void StopPlcTimer()
{
if (_plcReadTimer != null)
{
_plcReadTimer.Stop();
_plcReadTimer.Dispose();
_plcReadTimer = null;
}
}
//定时读取 PLC 数据
public void StartPlcReadTimer(int intervalMs)
{
// 防止重复创建
if (_plcReadTimer != null && _plcReadTimer.Enabled)
return;
_plcReadTimer = new System.Timers.Timer(intervalMs);
_plcReadTimer.Elapsed += ReadPlcData;
_plcReadTimer.Start();
}
private void ReadPlcData(object? sender, ElapsedEventArgs e)
{
// 左通道
ReadPlcDataGeneric(
slaveAddress: 1,
startAddress: LeftEyeStartAddress,
count: (ushort)(ChannelCount * RegistersPerChannel),
dataList: LeftEyeDataList,
dataGrid: dataGrid1);
// 右通道
ReadPlcDataGeneric(
slaveAddress: 1,
startAddress: RightEyeStartAddress,
count: (ushort)(ChannelCount * RegistersPerChannel),
dataList: RightEyeDataList,
dataGrid: dataGrid2);
}
private void ReadPlcDataGeneric(int slaveAddress, int startAddress, ushort count, List<dynamic> dataList, DataGrid dataGrid)
{
throw new NotImplementedException();
}
/// <summary>
/// 读取PLC HoldingRegisters 并更新到列表和DataGrid
/// <param name="slaveAddress">设备站号一般是1</param>
/// <param name="startAddress">起始地址</param>
/// <param name="count">寄存器总数</param>
/// <param name="dataList">数据缓存列表</param>
/// <param name="dataGrid">要更新的DataGrid控件</param>
/// 通用PLC读取方法左右通道通用
/// </summary>
private void ReadPlcDataGeneric(
byte slaveAddress,
ushort startAddress,
ushort count,
List<ushort> dataList,
DataGrid dataGrid)
{
if (_modbusMaster == null || !ModbusHelper.TcpClient.Connected)
return;
try
{
// 读取寄存器
ushort[] registers = _modbusMaster.ReadHoldingRegisters(
slaveAddress: slaveAddress,
startAddress: startAddress,
numberOfPoints: count);
// 先把变量存为局部变量,解决闭包问题
var regCopy = registers;
var listCopy = dataList;
var gridCopy = dataGrid;
// 交给UI线程更新数据和表格
Dispatcher.Invoke(() =>
{
AddPlcDataRow(regCopy, listCopy, gridCopy);
});
}
catch (Exception ex)
{
Console.WriteLine($"PLC读取失败: {ex.Message}");
}
}
/// <summary>
/// 把PLC数据添加到动态表格
/// </summary>
private void AddPlcDataRow(ushort[] registers, List<ushort> dataList, DataGrid dg)
{
// 清空旧数据,防止重复
dataList.Clear();
// 把PLC数据存入列表
dataList.AddRange(registers);
// 构建动态行适配你原来的ExpandoObject逻辑
List<dynamic> rows = new List<dynamic>();
for (int i = 0; i < registers.Length; i++)
{
dynamic row = new System.Dynamic.ExpandoObject();
var dict = (IDictionary<string, object>)row;
// 固定列:编号、时间、数值
dict["Id"] = i + 1;
dict["Time"] = DateTime.Now.ToString("HH:mm:ss");
dict["Value"] = registers[i];
rows.Add(row);
}
// 更新DataGrid
dg.ItemsSource = null;
dg.ItemsSource = rows;
}
//左右目面积调用方法
private void AddPlcDataRow(List<dynamic> leftEyeDataList, List<dynamic> RightEyeDataList)
{
leftEyeDataList = ModbusHelper.RemoveOutliers(leftEyeDataList);
RightEyeDataList = ModbusHelper.RemoveOutliers(RightEyeDataList);
//左目视野面积
GlobalData.LeftEyeArea = ModbusHelper.CalculateEyeArea(leftEyeDataList,
80,
120
);
//右目视野面积
GlobalData.RightEyeArea = ModbusHelper.CalculateEyeArea(RightEyeDataList,
80,
120
);
//双目视野面积
GlobalData.BinocularArea = ModbusHelper.CalcBinocularArea(leftEyeDataList, RightEyeDataList, 80, 120);
//// 总视野面积
GlobalData.TotalEyeArea = GlobalData.LeftEyeArea + GlobalData.RightEyeArea - GlobalData.BinocularArea;
//// 空白视野面积
GlobalData.BlankArea = 120 - GlobalData.TotalEyeArea;
//视野保存率
// 左眼平均值数组
double[] leftAvg = ModbusHelper.GetEyeAvgArray(leftEyeDataList);
// 右眼平均值数组
double[] rightAvg = ModbusHelper.GetEyeAvgArray(RightEyeDataList);
double leftLowerAngle = ModbusHelper.CalcLowerAngle(leftAvg, 10);
double rightLowerAngle = ModbusHelper.CalcLowerAngle(rightAvg, 10);
GlobalData.LowerVision = Math.Min(leftLowerAngle, rightLowerAngle);
//视野保存率
GlobalData.VisionRetentionRate = ModbusHelper.CalcVisionRate(GlobalData.LeftEyeArea, GlobalData.RightEyeArea);
}
private List<dynamic> RemoveOutliers(List<dynamic> leftEyeDataList)
{
throw new NotImplementedException();
}
private double CalcLowerAngle(double[] leftAvg, int v)
{
throw new NotImplementedException();
}
//#endregion
// 保存左眼
private void btnSaveLeft_Click(object sender, RoutedEventArgs e)
{
//SaveToCsv(LeftEyeDataList, $"左眼数据_{DateTime.Now:yyyyMMddHHmmss}.csv");
ModbusHelper.SaveToCsv(LeftEyeDataList, $"左眼数据_{DateTime.Now:yyyyMMddHHmmss}.csv");
}
// 保存右眼
private void btnSaveRight_Click(object sender, RoutedEventArgs e)
{
ModbusHelper.SaveToCsv(RightEyeDataList,$"右眼数据_{DateTime.Now:yyyyMMddHHmmss}.csv");
}
//清除
private void btnClear_MouseDown(object sender, MouseButtonEventArgs e)
{
_isClearPressed = true;
_clearThread = new Thread(() =>
{
Thread.Sleep(500); // 长按1秒触发
if (_isClearPressed)
{
Application.Current.Dispatcher.Invoke(() => ClearAllData());
}
});
_clearThread.Start();
}
// 清除所有数据
private void ClearAllData()
{
LeftEyeDataList.Clear();
dataGrid1.Items.Clear();
RightEyeDataList.Clear();
dataGrid2.Items.Clear();
MessageBox.Show("数据已清除");
}
private void btnClear_MouseUp(object sender, MouseButtonEventArgs e)
{
_isClearPressed = false;
_clearThread?.Join(100); // 等待线程结束最多100毫秒然后强制结束
}
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
_plcReadTimer?.Stop();
_plcReadTimer?.Dispose();
//_modbusMaster?.Dispose();
//ModbusHelper.TcpClient?.Close();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
}
private void GoHome(object s, RoutedEventArgs e) => NavigationService.Content = null;
private void GoTest(object s, RoutedEventArgs e) => NavigationService.Content = new Views.PageTest();
private void GoRecord(object s, RoutedEventArgs e) => NavigationService.Content = new Views.RecordDate();
private void GoView(object s, RoutedEventArgs e) => NavigationService.Content = new Views.RecordPage();
internal void StartPlcTimer()
{
throw new NotImplementedException();
}
//NavigationService.Navigate(new Views.RecordDate()); 页面相互跳转
}
//// 公开定时器(让别的页面能访问)
//public System.Timers.Timer PlcReadTimer;
// // 公开:启动定时器
// public void StartRecordTimer()
// {
// if (PlcReadTimer == null)
// {
// PlcReadTimer = new System.Timers.Timer(100);
// PlcReadTimer.Elapsed += ReadPlcData; // 你的PLC读取方法
// PlcReadTimer.Start();
// }
// }
// // 公开:停止定时器
// public void StopRecordTimer()
// {
// if (PlcReadTimer != null)
// {
// PlcReadTimer.Stop();
// PlcReadTimer.Dispose();
// PlcReadTimer = null;
// }
// }
// // 你的PLC读取方法
// private void ReadPlcData(object sender, System.Timers.ElapsedEventArgs e)
// {
// // 你原来的逻辑
// }
// 找到 RecordDate 页面实例 页面调用和停止
//var recordPage = Application.Current.MainWindow
// .FindName("MainFrame") as Frame
// ?.Content as RecordDate;
//// 找到了就调用
//if (recordPage != null)
//{
// recordPage.StartRecordTimer(); // 启动
// // recordPage.StopRecordTimer(); // 停止
//}
}