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;
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 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;
//根据不的dg 值 可以算出 左/右目视野面积
}
//private void AddPlcDataRow()
//{
// AddPlcDataRow(LeftEyeDataList);
//}
//左右目面积调用方法
private void AddPlcDataRow(List leftEyeDataList, List 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 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(); // 停止
//}
}