543 lines
20 KiB
C#
543 lines
20 KiB
C#
using Microsoft.Win32;
|
||
using Modbus.Device;
|
||
using Sunny.UI;
|
||
|
||
//using RecordDateView;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Net;
|
||
using System.Net.Sockets;
|
||
using System.Text;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Controls.Primitives;
|
||
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 System.Windows.Threading;
|
||
using 头罩视野.Services;
|
||
using 头罩视野.Services.Data;
|
||
using static 头罩视野.TestDataStore;
|
||
namespace 头罩视野.Views
|
||
{
|
||
public partial class PageTest : Page
|
||
{
|
||
/// 只加这一个变量
|
||
private CancellationTokenSource? _cts;
|
||
private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
|
||
DispatcherTimer _timer;
|
||
DataChange c = new DataChange();
|
||
Function ma;
|
||
bool isFinished;
|
||
//// 定时采集用
|
||
private DispatcherTimer testTimer;
|
||
// 保存上一条数据(用于去重)
|
||
private TestDataStore.TestRecord? _lastRecord;
|
||
private object btnLeftEye;
|
||
// 表跟数据存储列表
|
||
public List<dynamic> DataList = new List<dynamic>();
|
||
|
||
public PageTest()
|
||
{
|
||
InitializeComponent();
|
||
System.Diagnostics.Debug.WriteLine("页面加载了!111111111");
|
||
_timer = InitDispatcherTimer();
|
||
// 2. 初始化定时器:500毫秒 执行一次
|
||
|
||
testTimer = new DispatcherTimer();
|
||
testTimer.Interval = TimeSpan.FromMilliseconds(500); // 500ms = 0.5秒
|
||
testTimer.Tick += Timer_Tick;
|
||
|
||
//// 判断连接
|
||
if (!ModbusHelper.IsConnected)
|
||
{
|
||
MessageBox.Show("未连接");
|
||
return;
|
||
}
|
||
|
||
}
|
||
//
|
||
// 蓝色亮(蓝色)
|
||
private void LedOn(Ellipse led)
|
||
{
|
||
led.Fill = Brushes.LightSkyBlue;
|
||
}
|
||
|
||
// 灯灭(灰色)
|
||
private void LedOff(Ellipse led)
|
||
{
|
||
led.Fill = Brushes.LightGray;
|
||
}
|
||
|
||
//复位btn
|
||
private void Button_Click_Reset(object sender, RoutedEventArgs e)
|
||
{
|
||
btnLeft.Content = "左眼开";
|
||
btnRight.Content = "右眼开";
|
||
LedOff(led1);
|
||
LedOff(led0);
|
||
ma.BtnClickFunction(Function.ButtonType.复归型, 90);
|
||
}
|
||
//左开眼
|
||
private void Button_Click_left(object sender, RoutedEventArgs e)
|
||
{
|
||
// 切换文案:开是关,关是开
|
||
if (btnLeft.Content.ToString() == "左眼开")
|
||
{
|
||
|
||
|
||
btnLeft.Content = "左眼关";
|
||
LedOn(led0);
|
||
if (btnRight.Content.ToString() == "右眼关")
|
||
{
|
||
btnRight.Content = "右眼开";
|
||
LedOff(led1);
|
||
ma.BtnClickFunction(Function.ButtonType.切换型, 1);
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
btnLeft.Content = "左眼开";
|
||
LedOff(led0);
|
||
}
|
||
ma.BtnClickFunction(Function.ButtonType.切换型, 0);
|
||
//LedOn(led0);
|
||
}
|
||
//右开眼
|
||
private void Button_Click_Right(object sender, RoutedEventArgs e)
|
||
{
|
||
|
||
// 切换文案:左眼开 ↔ 左眼关
|
||
if (btnRight.Content.ToString() == "右眼开")
|
||
{
|
||
btnRight.Content = "右眼关";
|
||
LedOn(led1);
|
||
if (btnLeft.Content.ToString() == "左眼关")
|
||
{
|
||
|
||
btnLeft.Content = "左眼开";
|
||
LedOff(led0);
|
||
ma.BtnClickFunction(Function.ButtonType.切换型, 0);
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
btnRight.Content = "右眼开";
|
||
LedOff(led1);
|
||
|
||
}
|
||
ma.BtnClickFunction(Function.ButtonType.切换型, 1);
|
||
//LedOn(led1);
|
||
}
|
||
|
||
//反转
|
||
private async void Button_Click_ResDown(object sender, MouseButtonEventArgs e)
|
||
{
|
||
await _modbusMaster.WriteSingleCoilAsync(1, 10, true);
|
||
System.Diagnostics.Debug.WriteLine("反转开始");
|
||
}
|
||
|
||
private async void Button_Click_ResUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
await _modbusMaster.WriteSingleCoilAsync(1, 10, false);
|
||
System.Diagnostics.Debug.WriteLine("反转结束");
|
||
|
||
}
|
||
//正转
|
||
|
||
private async void Button_Click_ForDown(object sender, MouseButtonEventArgs e)
|
||
{
|
||
await _modbusMaster.WriteSingleCoilAsync(1, 11, true);
|
||
}
|
||
|
||
private async void Button_Click_ForUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
|
||
await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
|
||
//System.Diagnostics.Debug.WriteLine("正传end");
|
||
}
|
||
// 在 PageTest 类里面
|
||
private RecordDate? GetRecordDatePage()
|
||
{
|
||
// 拿到主窗口
|
||
var mainWin = Application.Current.MainWindow;
|
||
// 假设你全局切换页面的 Frame 名字叫 MainFrame
|
||
var frame = mainWin.FindName("MainFrame") as Frame;
|
||
// 返回 RecordDate 实例
|
||
return frame?.Content as RecordDate;
|
||
}
|
||
//停止btn
|
||
private void Button_Click_Stop(object sender, RoutedEventArgs e)
|
||
{
|
||
ma.BtnClickFunction(Function.ButtonType.复归型, 103);
|
||
ButtonTest.Content = "测试";
|
||
testTimer.Stop();
|
||
|
||
|
||
}
|
||
//测试btn 测试按钮:读取数据,存入共享列表
|
||
private void Button_Click_Test(object sender, RoutedEventArgs e)
|
||
|
||
{
|
||
ma.BtnClickFunction(Function.ButtonType.复归型, 100);
|
||
ButtonTest.Content = "测试中....";
|
||
testTimer.Start();
|
||
|
||
// 1. 读取输入框
|
||
double stepAngle = double.Parse(fbspeed.Text); // 分辨角度 例:10
|
||
//double speed = double.Parse(zdangle.Text); // 转动速度
|
||
int[] lightData = DataList.Cast<int>().ToArray(); // 1. 把DataList(List<dynamic>)转成方法需要的int[]
|
||
// 1. 定义总和变量,初始为0
|
||
double totalArea = 0;//总面积
|
||
double totalBottomViewAngle = 0;//总角度
|
||
// 2. 从0转到180,每 stepAngle 执行一次
|
||
for (double current = stepAngle; current <= 180; current += stepAngle)
|
||
{
|
||
_ = ReadLightBarData();
|
||
|
||
//开始计算视野面积
|
||
//2. 调用CalculateEllipseArea,传入两个参数
|
||
double area = GetArea.CalculateEllipseArea(lightData, _lightPositions);
|
||
totalArea += area;
|
||
double bottomViewAngle = GetArea.CalculateBottomViewAngle(lightData, _lightPositions);
|
||
totalBottomViewAngle += bottomViewAngle;
|
||
}
|
||
UpdateVisionResults(totalArea, totalBottomViewAngle);
|
||
}
|
||
//页面渲染值
|
||
|
||
public void UpdateVisionResults(double area, double BotViAn)
|
||
{
|
||
// 2. 根据按钮状态,把当前面积更新到对应的文本框
|
||
if (btnRight.Content.ToString() == "右眼开" && btnLeft.Content.ToString() == "左眼关")
|
||
{
|
||
zmsyarea.Text = area.ToString("0.00"); // 左目
|
||
}
|
||
else if (btnRight.Content.ToString() == "右眼关" && btnLeft.Content.ToString() == "左眼开")
|
||
{
|
||
ymsyarea.Text = area.ToString("0.00"); // 右目
|
||
}
|
||
else if (btnRight.Content.ToString() == "右眼关" && btnLeft.Content.ToString() == "左眼关")
|
||
{
|
||
smsyarea.Text = area.ToString("0.00"); // 双目
|
||
}
|
||
|
||
// 3. 计算空白区视野面积(双目时才有效)
|
||
if (double.TryParse(smsyarea.Text, out double binocularTotalArea))
|
||
{
|
||
double blankArea = GetArea.GetBlankViewArea(binocularTotalArea);
|
||
kbsyarea.Text = blankArea.ToString("0.00"); // 空白视野面积
|
||
}
|
||
|
||
//// 4. 计算下方视野面积
|
||
int botViAnInt = (int)Math.Round(BotViAn);
|
||
xfsyarea.Text = botViAnInt.ToString("0.0"); // 下方视野
|
||
|
||
// 5. 计算视野保存率(双目)
|
||
if (double.TryParse(smsyarea.Text, out double totalAreaForRate))
|
||
{
|
||
double binocularRate = GetArea.CalcVisionRate(totalAreaForRate);
|
||
sybhl.Text = binocularRate.ToString("0.00"); // 视野保存率
|
||
}
|
||
}
|
||
|
||
//读取灯泡的数据
|
||
|
||
private async Task ReadLightBarData()
|
||
{
|
||
// 无连接直接返回
|
||
if (_modbusMaster == null || !ModbusHelper.TcpClient.Connected)
|
||
return;
|
||
|
||
try
|
||
{
|
||
// 读取灯条寄存器(地址350,长度15)
|
||
ushort[] registers = await _modbusMaster.ReadHoldingRegistersAsync(1, 350, 15);
|
||
|
||
// 每个 ushort 是16位,低位在前
|
||
foreach (ushort reg in registers)
|
||
{
|
||
for (int bit = 0; bit < 16; bit++)
|
||
{
|
||
// 取第bit位的值:0或1
|
||
int lightBit = (reg & (1 << bit)) != 0 ? 1 : 0;
|
||
DataList.Add(lightBit);
|
||
}
|
||
}
|
||
|
||
// 调试:打印转换后的数据长度
|
||
System.Diagnostics.Debug.WriteLine($"灯条二进制数据总长度:{DataList.Count}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"灯条数据读取失败:{ex.Message}");
|
||
//DataList.Clear(); // 出错时清空数据
|
||
}
|
||
}
|
||
private async void Timer_Tick(object sender, EventArgs e)
|
||
|
||
{
|
||
System.Diagnostics.Debug.WriteLine("定时器触发了!" + DateTime.Now);
|
||
// 调用你原来的读取方
|
||
//await ReadAddr262DataAsync();
|
||
|
||
// 组装当前数据
|
||
var data = new TestDataStore.TestRecord
|
||
{
|
||
Date = DateTime.Now.ToString("yyyy-MM-dd"),
|
||
Time = DateTime.Now.ToString("HH:mm:ss"),
|
||
LeftEyeArea = double.TryParse(zmsyarea.Text, out var l) ? l : 0,
|
||
RightEyeArea = double.TryParse(ymsyarea.Text, out var r) ? r : 0,
|
||
BinocularArea = double.TryParse(smsyarea.Text, out var b) ? b : 0,
|
||
LowerVision = double.TryParse(xfsyarea.Text, out var lv) ? lv : 0,
|
||
VisionRetentionRate = double.TryParse(sybhl.Text, out var vr) ? vr : 0
|
||
};
|
||
|
||
// ==================== 去重判断 ====================
|
||
if (_lastRecord != null &&
|
||
data.LeftEyeArea == _lastRecord.LeftEyeArea &&
|
||
data.RightEyeArea == _lastRecord.RightEyeArea &&
|
||
data.BinocularArea == _lastRecord.BinocularArea &&
|
||
data.LowerVision == _lastRecord.LowerVision &&
|
||
data.VisionRetentionRate == _lastRecord.VisionRetentionRate)
|
||
{
|
||
return; // 一样就不添加
|
||
}
|
||
//原来存的数据清空 切换页面会清空
|
||
//TestDataStore.Records.Clear();
|
||
// 不一样 → 插入表格
|
||
TestDataStore.AddNewRecord(data);
|
||
_lastRecord = data;
|
||
}
|
||
|
||
//打印
|
||
|
||
private void Button_Click_Print(object sender, RoutedEventArgs e)
|
||
{
|
||
|
||
ma.BtnClickFunction(Function.ButtonType.复归型, 103);
|
||
|
||
}
|
||
//试样测试
|
||
|
||
|
||
private void TbTest_Checked(object sender, RoutedEventArgs e)
|
||
{
|
||
// 选中 → 试样测试
|
||
|
||
|
||
tbTest.Content = "空白测试";
|
||
|
||
tbTest.Background = System.Windows.Media.Brushes.LightSkyBlue;
|
||
System.Diagnostics.Debug.WriteLine($"1232312312");
|
||
_modbusMaster.WriteSingleCoilAsync(1, 41, true);
|
||
}
|
||
|
||
private void TbTest_Unchecked(object sender, RoutedEventArgs e)
|
||
{
|
||
// 取消 → 空白测试
|
||
|
||
tbTest.Content = "试样测试";
|
||
tbTest.Background = System.Windows.Media.Brushes.LightGray;
|
||
_modbusMaster.WriteSingleCoilAsync(1, 41, false);
|
||
}
|
||
private void Button_Click_home(object sender, RoutedEventArgs e)
|
||
{
|
||
NavigationService.Content = null;
|
||
}
|
||
|
||
|
||
//读取数据
|
||
private DispatcherTimer InitDispatcherTimer()
|
||
{
|
||
var timer = new DispatcherTimer
|
||
{
|
||
Interval = TimeSpan.FromMilliseconds(500)
|
||
};
|
||
timer.Tick += async (s, e) =>
|
||
{
|
||
if (_modbusMaster != null)
|
||
{
|
||
try
|
||
{
|
||
await ReadAddr262DataAsync();
|
||
}
|
||
catch { }
|
||
}
|
||
};
|
||
return timer;
|
||
}
|
||
private List<(int m, int n)> _lightPositions;
|
||
private async System.Threading.Tasks.Task ReadAddr262DataAsync()
|
||
{
|
||
try
|
||
{
|
||
// 创建任务列表
|
||
var tasks = new List<Task>
|
||
{
|
||
//ReadAndUpdateFloatAsync(200, 2, fbspeed, "F2", "°"),
|
||
//ReadAndUpdateFloatAsync(202, 2, dqangle, "F2", "°"),
|
||
//ReadAndUpdateFloatAsync(204, 2, zmsyarea, "F2", "cm²"),
|
||
//ReadAndUpdateFloatAsync(206 ,2, xfsyarea, "F2", " "),
|
||
//ReadAndUpdateFloatAsync(208, 2, smsyarea, "F2", "cm²"),
|
||
//ReadAndUpdateFloatAsync(210 ,2, ymsyarea, "F2", " "),
|
||
ReadAndUpdateFloatRangeAsync(200, 12, "F2", "°"),
|
||
//ReadAndUpdateFloatAsync(424 ,2, kbsyarea, "F2", "cm²"),
|
||
ReadAndUpdateFloatAsync(310, 2, zdangle, "F2", "°/S"),
|
||
//ReadAndUpdateFloatAsync(430 ,2, sybhl, "F2", " "),
|
||
|
||
//前1从站地址,后1是长度
|
||
|
||
|
||
};
|
||
|
||
await Task.WhenAll(tasks);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ShowError($"读取数据失败:{ex.Message}");
|
||
}
|
||
}
|
||
// 地址, 根据格式显示字符长度 32:2 16:1 ,绑定页面的name 值,F2 保留两位小数,单位
|
||
private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBox control, string format, string unit)
|
||
{
|
||
try
|
||
{ // 1. 页面销毁时直接退出,不执行
|
||
if (_cts?.IsCancellationRequested == true) return;
|
||
|
||
// 2. 关键:判断对象为空就直接返回,不执行
|
||
if (_modbusMaster == null) return;
|
||
|
||
ushort[] registers = await Task.Run(async () =>
|
||
await _modbusMaster!.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
|
||
);
|
||
|
||
if (registers != null && registers.Length >= 2)
|
||
{
|
||
float value = c.UshortToFloat(registers[1], registers[0]);
|
||
Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
|
||
}
|
||
else if (registers != null && registers.Length >= 1)
|
||
{
|
||
int value = registers[0];
|
||
Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
|
||
private async Task ReadAndUpdateFloatRangeAsync(int address, int length, string format, string unit)
|
||
{
|
||
try
|
||
{
|
||
ushort[] registers = await Task.Run(async () =>
|
||
await _modbusMaster!.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
|
||
);
|
||
|
||
if (registers != null && registers.Length >= 2)
|
||
{
|
||
float value = c.UshortToFloat(registers[1], registers[0]);
|
||
float value2 = c.UshortToFloat(registers[3], registers[2]);
|
||
float value3 = c.UshortToFloat(registers[5], registers[4]);
|
||
//float value4 = c.UshortToFloat(registers[7], registers[6]);
|
||
//float value5 = c.UshortToFloat(registers[9], registers[8]);
|
||
//float value6 = c.UshortToFloat(registers[11], registers[10]);
|
||
|
||
|
||
Dispatcher.Invoke(() =>
|
||
|
||
{
|
||
fbspeed.Text = value.ToString(format) + unit;
|
||
dqangle.Text = value2.ToString(format) + unit;
|
||
//zmsyarea.Text = value3.ToString(format) + unit;
|
||
//xfsyarea.Text = value4.ToString(format) + unit;
|
||
//smsyarea.Text = value5.ToString(format) + unit;
|
||
//ymsyarea.Text = value6.ToString(format) + unit;
|
||
//control.Text = value.ToString(format) + unit);
|
||
});
|
||
}
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
|
||
//写入
|
||
private void fbspeed_GotFocus(object sender, RoutedEventArgs e)
|
||
{
|
||
ma.WriteToPLCForNew(fbspeed.Text.Trim(), 200, Function.DataType.浮点型);
|
||
//程序等待50s 在进行
|
||
System.Threading.Tasks.Task.Delay(50);
|
||
fbspeed.Focus();
|
||
}
|
||
private void dqangle_GotFocus(object sender, RoutedEventArgs e)
|
||
{
|
||
ma.WriteToPLCForNew(dqangle.Text.Trim(), 202, Function.DataType.浮点型);
|
||
System.Threading.Tasks.Task.Delay(50);
|
||
dqangle.Focus();
|
||
}
|
||
private void zdangle_GotFocus(object sender, RoutedEventArgs e)
|
||
{
|
||
ma.WriteToPLCForNew(zdangle.Text.Trim(), 310, Function.DataType.浮点型);
|
||
System.Threading.Tasks.Task.Delay(50);
|
||
zdangle.Focus();
|
||
}
|
||
|
||
//错误信息提示
|
||
private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
private void GoHome(object s, RoutedEventArgs e) => NavigationService.Content = null;
|
||
private void GoTest(object s, RoutedEventArgs e)
|
||
{
|
||
_timer.Stop();
|
||
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();
|
||
|
||
private void Page_Loaded(object sender, RoutedEventArgs e)
|
||
{
|
||
|
||
|
||
System.Diagnostics.Debug.WriteLine("页面加载了!112222222");
|
||
_timer.Start();
|
||
ma = new Function(_modbusMaster);
|
||
c = new DataChange();
|
||
|
||
//zmsyarea.Text = "4.00"; // 左目
|
||
//smsyarea.Text = "5.00"; // 双目
|
||
//kbsyarea.Text = "6.00"; // 空白
|
||
//ymsyarea.Text = "7.00"; // 右目
|
||
//xfsyarea.Text = "8.00"; // 下方
|
||
//sybhl.Text = "9.00"; // 视野保存率
|
||
}
|
||
private void Page_Unloaded(object sender, RoutedEventArgs e)
|
||
{
|
||
testTimer?.Stop();
|
||
_timer?.Stop();
|
||
_cts?.Cancel();
|
||
_cts = null;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
}
|
||
|
||
|