diff --git a/App.config b/App.config new file mode 100644 index 0000000..91efc2e --- /dev/null +++ b/App.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/App.xaml b/App.xaml new file mode 100644 index 0000000..c9219e0 --- /dev/null +++ b/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/App.xaml.cs b/App.xaml.cs new file mode 100644 index 0000000..7827d99 --- /dev/null +++ b/App.xaml.cs @@ -0,0 +1,14 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace 医用刨削器特征新版8 +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } + +} diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs new file mode 100644 index 0000000..b0ec827 --- /dev/null +++ b/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/CurveWindow.xaml b/CurveWindow.xaml new file mode 100644 index 0000000..1466c4d --- /dev/null +++ b/CurveWindow.xaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CurveWindow.xaml.cs b/CurveWindow.xaml.cs new file mode 100644 index 0000000..84876fe --- /dev/null +++ b/CurveWindow.xaml.cs @@ -0,0 +1,122 @@ +using OxyPlot; +using OxyPlot.Series; +using System.Windows; +using System.Windows.Threading; + +namespace EmptyLoadTest +{ + public partial class CurveWindow : Window + { + private PlotModel _plotModel; + private LineSeries _torqueSpeedSeries; + private DispatcherTimer _updateTimer; + private static CurveWindow _instance; + + // 用于存储数据的队列(支持后台记录) + private readonly Queue _dataQueue = new Queue(); + private readonly object _lockObject = new object(); + + // 最大缓存数据点数 + private const int MAX_CACHE_POINTS = 1000; + + public static CurveWindow Instance + { + get + { + if (_instance == null || !_instance.IsLoaded) + { + _instance = new CurveWindow(); + } + return _instance; + } + } + + public CurveWindow() + { + InitializeComponent(); + InitializeChart(); + InitializeUpdateTimer(); + } + + // 外部调用此方法来更新数据(即使窗口未打开也会缓存) + public void UpdateData(float torque, float speed) + { + lock (_lockObject) + { + // 添加到队列 + _dataQueue.Enqueue(new DataPoint(torque, speed)); + + // 限制队列大小 + if (_dataQueue.Count > MAX_CACHE_POINTS) + { + _dataQueue.Dequeue(); + } + } + + // 如果窗口已打开,立即更新显示 + if (this.IsLoaded && IsVisible) + { + ProcessQueuedData(); + } + } + + private void ProcessQueuedData() + { + lock (_lockObject) + { + while (_dataQueue.Count > 0) + { + var point = _dataQueue.Dequeue(); + _torqueSpeedSeries.Points.Add(point); + + // 限制显示的数据点数 + if (_torqueSpeedSeries.Points.Count > 500) + { + _torqueSpeedSeries.Points.RemoveAt(0); + } + } + + _plotModel.InvalidatePlot(true); + UpdateStatusDisplay(); + } + } + + private void UpdateTimer_Tick(object sender, EventArgs e) + { + try + { + // 处理队列中的数据 + ProcessQueuedData(); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"曲线更新失败: {ex.Message}"); + } + } + + // 新增:获取当前数据点数 + public int GetDataCount() + { + lock (_lockObject) + { + return _dataQueue.Count + _torqueSpeedSeries.Points.Count; + } + } + + // 清空数据 + public void ClearData() + { + lock (_lockObject) + { + _dataQueue.Clear(); + _torqueSpeedSeries.Points.Clear(); + } + + if (this.IsLoaded) + { + _plotModel.InvalidatePlot(true); + UpdateStatusDisplay(); + } + } + } +} \ No newline at end of file diff --git a/Data/BoolSign.cs b/Data/BoolSign.cs new file mode 100644 index 0000000..7cf01e3 --- /dev/null +++ b/Data/BoolSign.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 软胶囊弹性硬度测试仪.Data +{ + + public class BoolSignal + { + private bool _previousValue; + + public event Action OnRisingEdge; + // bool value = true; + public bool Value { get; set; } + + public void CheckRisingEdge() + { + if (Value && !_previousValue) + { + OnRisingEdge?.Invoke(); + } + _previousValue = Value; + } + } + +} diff --git a/Data/DataChange.cs b/Data/DataChange.cs new file mode 100644 index 0000000..0b912a1 --- /dev/null +++ b/Data/DataChange.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 软胶囊弹性硬度测试仪 +{ + public class DataChange + { + /// + /// ushort转为float类型 + /// + /// + /// + /// float型数据 + public float UshortToFloat(ushort P1, ushort P2) + { + int intSign, intSignRest, intExponent, intExponentRest; + float faResult, faDigit; + intSign = P1 / 32768; + intSignRest = P1 % 32768; + intExponent = intSignRest / 128; + intExponentRest = intSignRest % 128; + faDigit = (float)(intExponentRest * 65536 + P2) / 8388608; + faResult = (float)Math.Pow(-1, intSign) * (float)Math.Pow(2, intExponent - 127) * (faDigit + 1); + return faResult; + } + /// + /// ushort转为int类型 + /// + /// + /// + /// 返回int型数据 + public int UshortToInt1(ushort u1, ushort u2) + { + ushort[] maidong = new ushort[2] { u1, u2 }; + byte[] bytes = new byte[maidong.Length * 2]; + Buffer.BlockCopy(maidong, 0, bytes, 0, bytes.Length); + int result = BitConverter.ToInt32(bytes, 0); + // 将字节数组转换为32位无符号整数 + return result; + + } + /// + /// Float转为Ushort数组发送 + /// + /// + /// 返回ushort数组 + public ushort[] SplitFloatToUShortArray(float value) + { + byte[] floatBytes = BitConverter.GetBytes(value); + ushort[] ushortArray = new ushort[floatBytes.Length / 2]; + + for (int i = 0, j = 0; i < floatBytes.Length; i += 2, j++) + { + ushortArray[j] = BitConverter.ToUInt16(floatBytes, i); + } + + return ushortArray; + } + /// + /// Int转为ushort数组发送 + /// + /// + /// 返回ushort数组 + public ushort[] intToushorts(int res) + { + ushort ust1 = (ushort)(res >> 16); + ushort ust2 = (ushort)res; + return new ushort[] { ust2, ust1 }; + } + } +} diff --git a/Data/ExperData.cs b/Data/ExperData.cs new file mode 100644 index 0000000..9b185e8 --- /dev/null +++ b/Data/ExperData.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 软胶囊弹性硬度测试仪 +{ + public class ExperData: INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + #region 实验属性 + static string experName = ""; + /// + /// 实验人员 + /// + public string ExperName { get { return experName; } set { experName = value; } } + + static string experDate = ""; + /// + /// 实验日期 + /// + public string ExperDate { get { return experDate; } set { experDate = value; } } + + static string experNum = ""; + /// + /// 实验编号 + /// + public string ExperNum { get { return experNum; } set { experNum = value; } } + + static string experType = " "; + /// + /// 实验种类 + /// + public string ExperType { get { return experType; } set { experType = value; } } + static float experMaskType = 2.0f; + /// + /// 口罩类型 + /// + public float ExperMaskType { get { return experMaskType; } set { experMaskType = value; } } + /// + /// 面罩类型 + /// + static string maskType; + public string MaskType { get { return maskType; } set { maskType = value; } } + static float _yangPinXiShu = 1.0f; + /// + /// 样品系数 + /// + public float YangPinXiShu { get { return _yangPinXiShu; } set { _yangPinXiShu = value; } } + static string _testStatus = ""; + + + /// + /// 实验状态 + /// + public string TestStatus { get { return _testStatus; } set { _testStatus = value; } } + static float benDiNongDu = 0.00f; + /// + /// 本底浓度 + /// + public float BenDiNongDu { get { return benDiNongDu; } set { benDiNongDu = value; } } + + static float huanJingWenDu = 0.00f; + /// + /// 环境温度 + /// + public float HuanJingWenDu { get { return huanJingWenDu; } set { huanJingWenDu = value; } } + + + static float huanJingShiDu = 0.00f; + /// + /// 环境湿度 + /// + public float HuanJingShiDu { get { return huanJingShiDu; } set { huanJingShiDu = value; } } + + static float o2NongDu = 0.00f; + /// + /// 环境氧浓度 + /// + public float O2NongDu { get { return o2NongDu; } set { o2NongDu = value; } } + + static float cO2NongDu = 0.00f; + /// + /// 环境C02浓度 + /// + public float CO2NongDu_Indoor { get { return cO2NongDu; } set { cO2NongDu = value; } } + + static float inDoor_TSINongDu = 0.00f; + /// + /// 环境气溶胶浓度 + /// + public float InDoor_TSINongDu { get { return inDoor_TSINongDu; } set { inDoor_TSINongDu = value; } } + + static float mask_CO2NongDu = 0.00f; + /// + /// 口罩内CO2浓度 + /// + public float Mask_CO2NongDu { get { return mask_CO2NongDu; } set { mask_CO2NongDu = value; } } + + static float mask_TSINongDu = 0.00f; + /// + /// 口罩内气溶胶浓度 + /// + public float Mask_TSINongDu { get { return mask_TSINongDu; } set { mask_TSINongDu = value; } } + + static float _liuLiang = 0.00f; + /// + /// 流量 + /// + public float LiuLiang { get { return _liuLiang; } set { _liuLiang = value; } } + static float _xieloulv = 0.00f; + /// + /// 泄露率 + /// + public float XieLouLv { get { return _xieloulv; } set { _xieloulv = value; } } + + + #endregion + + #region 泄露率计算 + //单独动作泄露率 + public float CumulativeLeakageRate(List inDoor_Tsi,List out_Door_Tsi,float benDiNongdu,float xiShu) + { + if (inDoor_Tsi.Count != 0 && out_Door_Tsi.Count != 0&& benDiNongdu!=0.0f) + { + //计算室内Tsi浓度平均值 + float inDoor_Tsi_Avg = inDoor_Tsi.Average(); + //计算室外Tsi浓度平均值 + float out_Door_Tsi_Avg = out_Door_Tsi.Average(); + //计算泄露率 + float leakageRate = ((out_Door_Tsi_Avg - inDoor_Tsi_Avg) * xiShu) / benDiNongdu; + return leakageRate; + } + else + { + return 0.00f; + } + + } + //全部动作泄露率 + public float CumulativeLeakageRate_All(List All_Cv_List) + + { + return All_Cv_List.Average(); + } + #endregion + + } +} diff --git a/Data/Function.cs b/Data/Function.cs new file mode 100644 index 0000000..72ac304 --- /dev/null +++ b/Data/Function.cs @@ -0,0 +1,222 @@ +using Modbus.Device; +using Modbus; +using Sunny.UI; +using System; +using System.Threading; +using System.Windows; +using System.Windows.Controls; + +namespace 软胶囊弹性硬度测试仪 +{ + public class Function + { + ModbusMaster master; + IModbusMaster modbusMaster; + DataChange dc = new DataChange(); + public enum ButtonType + { + 复归型, + 切换型, + 置位型, + 复位型 + } + public enum DataType + { + 整形, + 浮点型 + } + public Function(ModbusMaster master_in) + { + this.master = master_in; + } + + public Function(IModbusMaster modbusMaster) + { + this.modbusMaster = modbusMaster; + } + + public void BtnClickFunction(ButtonType buttonType, ushort address) + { + try + { + switch (buttonType) + { + case ButtonType.复归型: + master.WriteSingleCoil(1, address, true); + Thread.Sleep(100); + master.WriteSingleCoil(1, address, false); + Thread.Sleep(100); + break; + case ButtonType.切换型: + if (master.ReadCoils(1, address, 1)[0]) + { + master.WriteSingleCoil(1, address, false); Thread.Sleep(100); + } + else + { master.WriteSingleCoil(1, address, true); Thread.Sleep(100); } + break; + case ButtonType.置位型: + master.WriteSingleCoil(1, address, true); + Thread.Sleep(100); + break; + case ButtonType.复位型: + master.WriteSingleCoil(1, address, false); + Thread.Sleep(100); + break; + default: + break; + } + } + catch (Exception ex) + { + + } + + } + + public void BtnClickFunctionForNew(ButtonType buttonType, ushort address) + { + try + { + switch (buttonType) + { + case ButtonType.复归型: + modbusMaster.WriteSingleCoil(1, address, true); + Thread.Sleep(100); + modbusMaster.WriteSingleCoil(1, address, false); + Thread.Sleep(100); + break; + case ButtonType.切换型: + if (modbusMaster.ReadCoils(1, address, 1)[0]) + { + modbusMaster.WriteSingleCoil(1, address, false); Thread.Sleep(100); + } + else + { modbusMaster.WriteSingleCoil(1, address, true); Thread.Sleep(100); } + break; + case ButtonType.置位型: + modbusMaster.WriteSingleCoil(1, address, true); + Thread.Sleep(100); + break; + case ButtonType.复位型: + modbusMaster.WriteSingleCoil(1, address, false); + Thread.Sleep(100); + break; + default: + break; + } + } + catch (Exception ex) + { + + } + + } + public void WriteToPLC(string inPutValue, ushort address, DataType dataType) + { + + try + { + switch (dataType) + { + case DataType.浮点型: + double value = inPutValue.ToDouble(); + if (UIInputDialog.ShowInputDoubleDialog(ref value, UIStyle.Inherited, desc: "请输入值", showMask: false)) + { + + master.WriteMultipleRegisters(1, address, dc.SplitFloatToUShortArray((float)value)); + } + break; + case DataType.整形: + int value_int = inPutValue.ToInt(); + if (UIInputDialog.ShowInputIntegerDialog(ref value_int, UIStyle.Inherited, desc: "请输入数据:")) + { + + master.WriteMultipleRegisters(1, address, dc.intToushorts(value_int)); + } + break; + default: + break; + } + } + catch (Exception ex) + { + MessageBox.Show("操作失败!" + "\n" + "\n" + ex.Message, "错误"); + } + + } + + public void WriteToPLCForNew(string inPutValue, ushort address, DataType dataType) + { + try + { + //KeyboardHelper.ShowSoftKeyboard(); + switch (dataType) + { + case DataType.浮点型: + double value = inPutValue.ToDouble(); + + if (UIInputDialog.ShowInputDoubleDialog(ref value, UIStyle.Inherited,3, desc: "请输入值", showMask: false)) + { + + modbusMaster.WriteMultipleRegisters(1, address, dc.SplitFloatToUShortArray((float)value)); + } + break; + case DataType.整形: + int value_int = inPutValue.ToInt(); + if (UIInputDialog.ShowInputIntegerDialog(ref value_int, UIStyle.Inherited, desc: "请输入数据:")) + { + modbusMaster.WriteMultipleRegisters(1, address, dc.intToushorts(value_int)); + } + break; + default: + break; + } + + //KeyboardHelper.HideSoftKeyboard(); + } + catch (Exception ex) + { + MessageBox.Show("操作失败!" + "\n" + "\n" + ex.Message, "错误"); + } + + } + + + public void WriteToPLCForNewForThree(string inPutValue, ushort address, DataType dataType) + { + try + { + //KeyboardHelper.ShowSoftKeyboard(); + switch (dataType) + { + case DataType.浮点型: + double value = inPutValue.ToDouble(); + + if (UIInputDialog.ShowInputDoubleDialog(ref value, UIStyle.Inherited, 3, desc: "请输入值", showMask: false)) + { + + modbusMaster.WriteMultipleRegisters(1, address, dc.SplitFloatToUShortArray((float)value)); + } + break; + case DataType.整形: + int value_int = inPutValue.ToInt(); + if (UIInputDialog.ShowInputIntegerDialog(ref value_int, UIStyle.Inherited, desc: "请输入数据:")) + { + modbusMaster.WriteMultipleRegisters(1, address, dc.intToushorts(value_int)); + } + break; + default: + break; + } + + //KeyboardHelper.HideSoftKeyboard(); + } + catch (Exception ex) + { + MessageBox.Show("操作失败!" + "\n" + "\n" + ex.Message, "错误"); + } + + } + } +} diff --git a/Data/LoginData.cs b/Data/LoginData.cs new file mode 100644 index 0000000..71d6fba --- /dev/null +++ b/Data/LoginData.cs @@ -0,0 +1,21 @@ +namespace 软胶囊弹性硬度测试仪 +{ + public class LoginData + { + static string _userName = ""; + public string UserName + { + get { return _userName; } + set { _userName = value; } + } + + //登陆权限 + static int _userPower = 0;//0为普通用户,1为管理员 + public int UserPower + { + get { return _userPower; } + set { _userPower = value; } + } + + } +} diff --git a/Data/ModbusResourceManager.cs b/Data/ModbusResourceManager.cs new file mode 100644 index 0000000..5b2e345 --- /dev/null +++ b/Data/ModbusResourceManager.cs @@ -0,0 +1,69 @@ +using System; +using Modbus.Device; +using System.Net.Sockets; + +namespace 软胶囊弹性硬度测试仪.Data +{ + // 单例模式:全局唯一资源管理器 + public class ModbusResourceManager + { + // 私有构造函数:禁止外部new + private ModbusResourceManager() { } + + // 唯一实例 + private static readonly Lazy _instance = new Lazy(() => new ModbusResourceManager()); + public static ModbusResourceManager Instance => _instance.Value; + + // 共享资源 + public TcpClient TcpClient { get; private set; } + public IModbusMaster ModbusMaster { get; private set; } + + // 初始化资源(在程序启动时调用,如MainWindow加载时) + public bool Init(string ip, int port) + { + try + { + // 先释放旧资源 + ReleaseResource(); + + // 创建新连接 + TcpClient = new TcpClient(); + TcpClient.Connect(ip, port); + ModbusMaster = ModbusIpMaster.CreateIp(TcpClient); + return true; + } + catch (Exception ex) + { + Console.WriteLine($"资源初始化失败:{ex.Message}"); + ReleaseResource(); + return false; + } + } + + public void Dispose() + { + try + { + ModbusMaster?.Dispose(); + TcpClient?.Close(); + } + catch + { + // 忽略清理时的异常 + } + } + // 释放资源(统一释放,避免重复关闭) + public void ReleaseResource() + { + ModbusMaster?.Dispose(); + ModbusMaster = null; + + //if (TcpClient?.Connected ?? false) + //{ + // TcpClient.Close(); + //} + TcpClient?.Dispose(); + TcpClient = null; + } + } +} \ No newline at end of file diff --git a/Data/PLC_Data.cs b/Data/PLC_Data.cs new file mode 100644 index 0000000..7d8d671 --- /dev/null +++ b/Data/PLC_Data.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 软胶囊弹性硬度测试仪.Data +{ + internal class PLC_Data + { + + } +} diff --git a/Data/keyboard.cs b/Data/keyboard.cs new file mode 100644 index 0000000..35c8adb --- /dev/null +++ b/Data/keyboard.cs @@ -0,0 +1,71 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Security.Principal; +using System.Windows; + +public class KeyboardHelper +{ + public static void ShowSoftKeyboard() + { + if (!IsRunAsAdmin()) + { + RestartAsAdmin(); + return; + } + + // 替换原有的 Process.Start 代码 + string oskPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "osk.exe"); + if (File.Exists(oskPath)) + { + Process.Start(new ProcessStartInfo + { + FileName = oskPath, + UseShellExecute = true + }); + } + else + { + //MessageBox.Show("未找到屏幕键盘程序(osk.exe),可能系统文件缺失或非Windows系统。", "错误"); + } + } + + public static void HideSoftKeyboard() + { + try + { + Process.Start("cmd.exe", "/C taskkill /IM osk.exe /F"); + } + catch (Exception ex) + { + Console.WriteLine("Error: " + ex.Message); + } + } + + private static bool IsRunAsAdmin() + { + WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new WindowsPrincipal(identity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + + private static void RestartAsAdmin() + { + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.UseShellExecute = true; + startInfo.WorkingDirectory = Environment.CurrentDirectory; + startInfo.FileName = Process.GetCurrentProcess().MainModule.FileName; + startInfo.Verb = "runas"; + + try + { + Process.Start(startInfo); + } + catch (Exception ex) + { + Console.WriteLine("Error: " + ex.Message); + } + + Environment.Exit(0); + } +} diff --git a/EmergencyStopWindow.xaml b/EmergencyStopWindow.xaml new file mode 100644 index 0000000..78654d0 --- /dev/null +++ b/EmergencyStopWindow.xaml @@ -0,0 +1,527 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +