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 { /// /// RecordDate.xaml 的交互逻辑 /// /// public partial class RecordDate : Page { private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster; private System.Timers.Timer? _plcReadTimer; // 表跟数据存储列表 private List LeftEyeDataList = new List(); private List RightEyeDataList = new List(); // 配置:和你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 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; //这个时候开始计算 AddPlcDataRow(LeftEyeDataList, RightEyeDataList); } } //定时读取 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 dataList, DataGrid dataGrid) { throw new NotImplementedException(); } /// /// 读取PLC HoldingRegisters 并更新到列表和DataGrid /// 设备站号(一般是1) /// 起始地址 /// 寄存器总数 /// 数据缓存列表 /// 要更新的DataGrid控件 /// 通用PLC读取方法(左右通道通用) /// private void ReadPlcDataGeneric( byte slaveAddress, ushort startAddress, ushort count, List 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}"); } } /// /// 把PLC数据添加到动态表格 /// private void AddPlcDataRow(ushort[] registers, List dataList, DataGrid dg) { // 清空旧数据,防止重复 dataList.Clear(); // 把PLC数据存入列表 dataList.AddRange(registers); // 构建动态行(适配你原来的ExpandoObject逻辑) List rows = new List(); for (int i = 0; i < registers.Length; i++) { dynamic row = new System.Dynamic.ExpandoObject(); var dict = (IDictionary)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 leftEyeDataList, List RightEyeDataList) { leftEyeDataList = ModbusHelper.RemoveOutliers(leftEyeDataList); RightEyeDataList = ModbusHelper.RemoveOutliers(RightEyeDataList); //左目视野面积 GlobalData.LeftEyeArea = ModbusHelper.CalculateEyeArea(leftEyeDataList, 12, 140 ); //右目视野面积 GlobalData.RightEyeArea = ModbusHelper.CalculateEyeArea(RightEyeDataList, 12, 140 ); //双目视野面积 GlobalData.BinocularArea = ModbusHelper.CalcBinocularArea(leftEyeDataList, RightEyeDataList, 12, 140); //// 总视野面积 GlobalData.TotalEyeArea = GlobalData.LeftEyeArea + GlobalData.RightEyeArea - GlobalData.BinocularArea; //// 空白视野面积 GlobalData.BlankArea = 140 - GlobalData.TotalEyeArea; //视野保存率 // 左眼平均值数组 double[] leftAvg = ModbusHelper.GetEyeAvgArray(leftEyeDataList); // 右眼平均值数组 double[] rightAvg = ModbusHelper.GetEyeAvgArray(RightEyeDataList); double leftLowerAngle = ModbusHelper.CalcLowerAngle(leftAvg, 12); double rightLowerAngle = ModbusHelper.CalcLowerAngle(rightAvg, 12); //下方视野 GlobalData.LowerVision = Math.Min(leftLowerAngle, rightLowerAngle); //视野保存率 GlobalData.VisionRetentionRate = ModbusHelper.CalcVisionRate(GlobalData.LeftEyeArea, GlobalData.RightEyeArea); //打印数值显示在系统上面 System.Diagnostics.Debug.WriteLine("左目视野面积" + GlobalData.LeftEyeArea); System.Diagnostics.Debug.WriteLine("右目视野面积" + GlobalData.RightEyeArea); System.Diagnostics.Debug.WriteLine("双目视野面积" + GlobalData.BinocularArea); System.Diagnostics.Debug.WriteLine("总视野面积" + GlobalData.TotalEyeArea); System.Diagnostics.Debug.WriteLine("下方视野" + GlobalData.LowerVision); System.Diagnostics.Debug.WriteLine("视野保存率" + GlobalData.VisionRetentionRate); } private List RemoveOutliers(List 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()); 页面相互跳转 } }