Compare commits
10 Commits
e007188418
...
8923dd1ed8
| Author | SHA1 | Date | |
|---|---|---|---|
| 8923dd1ed8 | |||
| 7f2fa77dd2 | |||
| ace97f14a6 | |||
| 9264596831 | |||
| 4640b47331 | |||
| 3027c288c3 | |||
| 0f32957416 | |||
| d2bf7ab4c0 | |||
| a25a4bc6ed | |||
| cd5683dae9 |
6
BOB.sln
6
BOB.sln
@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessManager", "ProcessMa
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{E2897246-96B3-48BE-AA08-4E774BE2BCFB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CAN驱动", "CAN驱动\CAN驱动.csproj", "{65DCA56F-A0EB-407F-80B9-C5C5F0E69681}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -63,6 +65,10 @@ Global
|
||||
{E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
102
BOB/App.xaml.cs
102
BOB/App.xaml.cs
@ -1,12 +1,18 @@
|
||||
using BOB.Converters;
|
||||
using BOB.Models;
|
||||
using BOB.Singleton;
|
||||
using BOB.ViewModels;
|
||||
using BOB.ViewModels.Dialogs;
|
||||
using BOB.Views;
|
||||
using BOB.Views.Dialogs;
|
||||
using Castle.DynamicProxy;
|
||||
using Model.SQLModel;
|
||||
using ORM;
|
||||
using Service.Implement;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
@ -22,10 +28,69 @@ namespace BOB
|
||||
{
|
||||
return Container.Resolve<ShellView>();
|
||||
}
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
if (e.Args.Length > 0)
|
||||
{
|
||||
string deviceName = e.Args[0];
|
||||
SystemConfig.Instance.Title = deviceName;
|
||||
InitDataBase(deviceName);
|
||||
//Debugger.Launch();
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemConfig.Instance.Title = "设备2";//模拟打开的设备
|
||||
InitDataBase("设备2");
|
||||
}
|
||||
base.OnStartup(e);
|
||||
}
|
||||
|
||||
private void InitDataBase(string deviceName)
|
||||
{
|
||||
int tenantId = 0;
|
||||
string dbFileName;
|
||||
switch (deviceName)
|
||||
{
|
||||
case "设备1":
|
||||
tenantId = 10001;
|
||||
dbFileName = "设备1.db";
|
||||
break;
|
||||
case "设备2":
|
||||
tenantId = 10002;
|
||||
dbFileName = "设备2.db";
|
||||
break;
|
||||
case "设备3":
|
||||
tenantId = 10003;
|
||||
dbFileName = "设备3.db";
|
||||
break;
|
||||
case "水冷机和环境箱":
|
||||
tenantId = 10004;
|
||||
dbFileName = "水冷机和环境箱.db";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("未知设备");
|
||||
}
|
||||
|
||||
// 设置租户 ID,初始化雪花 ID WorkId/DatacenterId
|
||||
DatabaseConfig.SetTenant(tenantId);
|
||||
|
||||
// 设置数据库路径
|
||||
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
string folder = Path.Combine(baseDir, "SQLDB");
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
string dbPath = Path.Combine(folder, dbFileName);
|
||||
DatabaseConfig.SetDbConnection($"Data Source={dbPath}");
|
||||
|
||||
// 创建数据库文件并检查连接
|
||||
DatabaseConfig.CreateDatabaseAndCheckConnection(createDatabase: true, checkConnection: true);
|
||||
SqlSugarContext.DbContext.CodeFirst.InitTables(typeof(BackFeedData), typeof(EAELD9080Data), typeof(IT6724CData),typeof(PSB1100Data));
|
||||
}
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
var regionManager = Container.Resolve<IRegionManager>();
|
||||
regionManager.RequestNavigate("ShellViewManager", "MainView");
|
||||
}
|
||||
@ -33,15 +98,44 @@ namespace BOB
|
||||
{
|
||||
//注册视图
|
||||
containerRegistry.RegisterForNavigation<MainView>("MainView");
|
||||
containerRegistry.RegisterForNavigation<MonitorView>("MonitorView");
|
||||
containerRegistry.RegisterForNavigation<Views.DataView>("DataView");
|
||||
containerRegistry.RegisterForNavigation<UpdateInfoView>("UpdateInfoView");
|
||||
//注册弹窗
|
||||
containerRegistry.RegisterDialog<MessageBoxView, MessageBoxViewModel>("MessageBox");
|
||||
containerRegistry.RegisterDialog<ParameterSetting, ParameterSettingViewModel>("ParameterSetting");
|
||||
containerRegistry.RegisterDialog<DeviceSetting, DeviceSettingViewModel>("DeviceSetting");
|
||||
//注册全局变量
|
||||
containerRegistry.RegisterDialog<BackfeedView, BackfeedViewModel>("Backfeed");
|
||||
containerRegistry.RegisterDialog<EAEL9080View, EAEL9080ViewModel>("EAEL9080");
|
||||
containerRegistry.RegisterDialog<IOBoardView, IOBoardViewModel>("IOBoard");
|
||||
containerRegistry.RegisterDialog<IT6724CView, IT6724CViewModel>("IT6724C");
|
||||
containerRegistry.RegisterDialog<LQ7500_DView, LQ7500_DViewModel>("LQ7500_D");
|
||||
containerRegistry.RegisterDialog<PSB11000View, PSB11000ViewModel>("PSB11000");
|
||||
containerRegistry.RegisterDialog<SQ0030G1DView, SQ0030G1DViewModel>("SQ0030G1D");
|
||||
containerRegistry.RegisterDialog<WS_68030_380TView, WS_68030_380TViewModel>("WS_68030_380T");
|
||||
containerRegistry.RegisterDialog<ZXKSView, ZXKSViewModel>("ZXKS");
|
||||
containerRegistry.RegisterDialog<CANView, CANViewModel>("CAN");
|
||||
//注册全局单例变量
|
||||
containerRegistry.RegisterSingleton<GlobalVariables>();
|
||||
containerRegistry.RegisterSingleton<Devices>();
|
||||
containerRegistry.RegisterSingleton<StepRunning>();
|
||||
// 注册仓储
|
||||
containerRegistry.RegisterScoped(typeof(SqlSugarRepository<>));
|
||||
// 注册服务
|
||||
containerRegistry.RegisterScoped(typeof(BackFeedService));
|
||||
containerRegistry.RegisterScoped(typeof(EAEL9080Service));
|
||||
containerRegistry.RegisterScoped(typeof(IT6724CService));
|
||||
containerRegistry.RegisterScoped(typeof(LQ7500DService));
|
||||
containerRegistry.RegisterScoped(typeof(PSB11000Service));
|
||||
containerRegistry.RegisterScoped(typeof(SQ0030Service));
|
||||
containerRegistry.RegisterScoped(typeof(WS680Service));
|
||||
containerRegistry.RegisterScoped(typeof(ZXKXService));
|
||||
}
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
var devices = Container.Resolve<Devices>();
|
||||
devices.Dispose();
|
||||
base.OnExit(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -39,10 +39,12 @@
|
||||
<PackageReference Include="MaterialDesignThemes" Version="5.3.0" />
|
||||
<PackageReference Include="MaterialDesignThemes.MahApps" Version="5.3.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="OxyPlot.Wpf" Version="2.2.0" />
|
||||
<PackageReference Include="Prism.Unity" Version="9.0.537" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CAN驱动\CAN驱动.csproj" />
|
||||
<ProjectReference Include="..\Command\Command.csproj" />
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
<ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" />
|
||||
|
||||
40
BOB/Converters/HexConverter.cs
Normal file
40
BOB/Converters/HexConverter.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BOB.Converters
|
||||
{
|
||||
public class HexConverter : IValueConverter
|
||||
{
|
||||
// 显示时:int → hex 字符串
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
return $"0x{i:X}"; // 例如 255 → 0xFF
|
||||
return "0x0";
|
||||
}
|
||||
|
||||
// 用户输入时:hex 字符串 → int
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var str = value?.ToString()?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return 0;
|
||||
|
||||
if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
str = str.Substring(2);
|
||||
|
||||
if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int result))
|
||||
return result;
|
||||
|
||||
return 0; // 或 return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
49
BOB/Models/DeviceInfoModel.cs
Normal file
49
BOB/Models/DeviceInfoModel.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using Model;
|
||||
|
||||
namespace BOB.Models
|
||||
{
|
||||
public class DeviceInfoModel : BindableBase
|
||||
{
|
||||
private string _deviceName;
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private string _deviceType;
|
||||
public string DeviceType
|
||||
{
|
||||
get => _deviceType;
|
||||
set => SetProperty(ref _deviceType, value);
|
||||
}
|
||||
|
||||
private string _remark;
|
||||
public string Remark
|
||||
{
|
||||
get => _remark;
|
||||
set => SetProperty(ref _remark, value);
|
||||
}
|
||||
|
||||
private bool _isEnabled;
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set => SetProperty(ref _isEnabled, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private ICommunicationConfig _communicationConfig;
|
||||
public ICommunicationConfig CommunicationConfig
|
||||
{
|
||||
get => _communicationConfig;
|
||||
set => SetProperty(ref _communicationConfig, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Models
|
||||
{
|
||||
public class DeviceModel
|
||||
{
|
||||
public DeviceModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DeviceModel(DeviceModel source)
|
||||
{
|
||||
ID = source.ID;
|
||||
ParameterID = source.ParameterID;
|
||||
Name = source.Name;
|
||||
Connected = source.Connected;
|
||||
ErrorMessage = source.ErrorMessage;
|
||||
Type = source.Type;
|
||||
ConnectString = source.ConnectString;
|
||||
CommunicationProtocol = source.CommunicationProtocol;
|
||||
Description = source.Description;
|
||||
}
|
||||
|
||||
public Guid ID { get; set; } = Guid.NewGuid();
|
||||
|
||||
public Guid ParameterID { get; set; }
|
||||
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
[JsonIgnore]
|
||||
public bool Connected { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string? ErrorMessage { get; set; }
|
||||
|
||||
public string Type { get; set; } = "Tcp";
|
||||
|
||||
public string ConnectString { get; set; } = "";
|
||||
|
||||
[JsonIgnore]
|
||||
public object? CommunicationProtocol { get; set; }
|
||||
|
||||
public string Description { get; set; } = "";
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,6 @@ namespace BOB.Models
|
||||
{
|
||||
ID = source.ID;
|
||||
StepCollection = new ObservableCollection<StepModel>(source.StepCollection.Select(p => new StepModel(p)));
|
||||
Devices = new ObservableCollection<DeviceModel>(source.Devices.Select(p => new DeviceModel(p)));
|
||||
Parameters = new ObservableCollection<ParameterModel>(source.Parameters.Select(p => new ParameterModel(p)));
|
||||
}
|
||||
|
||||
@ -40,11 +39,6 @@ namespace BOB.Models
|
||||
set => SetProperty(ref _parameters, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<DeviceModel> _devices = new ObservableCollection<DeviceModel>();
|
||||
public ObservableCollection<DeviceModel> Devices
|
||||
{
|
||||
get => _devices;
|
||||
set => SetProperty(ref _devices, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
65
BOB/Services/BackfeedPollingRead.cs
Normal file
65
BOB/Services/BackfeedPollingRead.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Model.SQLModel;
|
||||
using Service.Implement;
|
||||
using Service.Interface;
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class BackfeedPollingRead : PollingRead
|
||||
{
|
||||
private Backfeed _Backfeed { get;set; }
|
||||
private IEventAggregator _eventAggregator { get;set; }
|
||||
private IBaseService<BackFeedData> _backFeedService { get;set; }
|
||||
public BackfeedPollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
_backFeedService=containerProvider.Resolve<BackFeedService>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
DeviceName = "Backfeed";
|
||||
_Backfeed = _devices.DeviceDic["Backfeed"]as Backfeed;
|
||||
}
|
||||
public double 实时电流 { get; set; } = double.NaN;
|
||||
public double 实时电压 { get; set; } = double.NaN;
|
||||
public double 实时功率 { get; set; } = double.NaN;
|
||||
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
实时电流 = Random.Shared.NextDouble() * 10;
|
||||
实时电压 = Random.Shared.NextDouble() * 10;
|
||||
实时功率 = Random.Shared.NextDouble() * 10;
|
||||
//实时电流 =await _Backfeed!.查询实时电流(ct);
|
||||
//实时电压 = await _Backfeed!.查询实时电压(ct);
|
||||
//实时功率 = await _Backfeed!.查询实时功率(ct);
|
||||
var reuslt= await _backFeedService.InsertAsync(new BackFeedData
|
||||
{
|
||||
RealTimeCurrent = 实时电流,
|
||||
RealTimePower= 实时电压,
|
||||
RealTimeVoltage= 实时功率,
|
||||
CollectTime=DateTime.Now
|
||||
});
|
||||
if (reuslt.IsSuccess)
|
||||
{
|
||||
var dataDic = new Dictionary<string, double>
|
||||
{
|
||||
{ "实时电流", 实时电流 },
|
||||
{ "实时电压", 实时电压 },
|
||||
{ "实时功率", 实时功率 }
|
||||
};
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Publish(("Backfeed", dataDic));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify(reuslt.Msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
BOB/Services/EAEL9080PollingRead.cs
Normal file
64
BOB/Services/EAEL9080PollingRead.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Model.SQLModel;
|
||||
using Service.Implement;
|
||||
using Service.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class EAEL9080PollingRead:PollingRead
|
||||
{
|
||||
private EAEL9080 _EAEL9080 { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private IBaseService<EAELD9080Data> _eAEL9080Service { get; set; }
|
||||
public EAEL9080PollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
_eAEL9080Service = containerProvider.Resolve<EAEL9080Service>();
|
||||
DeviceName = "EAEL9080";
|
||||
_EAEL9080 = _devices.DeviceDic["EAEL9080"] as EAEL9080;
|
||||
}
|
||||
public double 实时电流 { get; set; } = double.NaN;
|
||||
public double 实时电压 { get; set; } = double.NaN;
|
||||
public double 实时功率 { get; set; } = double.NaN;
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
实时电流 = Random.Shared.NextDouble() * 10;
|
||||
实时电压 = Random.Shared.NextDouble() * 10;
|
||||
实时功率 = Random.Shared.NextDouble() * 10;
|
||||
//实时电流 = await _EAEL9080!.查询电流(ct);
|
||||
//实时电压 = await _EAEL9080!.查询电压(ct);
|
||||
//实时功率 = await _EAEL9080!.查询功率(ct);
|
||||
var reuslt = await _eAEL9080Service.InsertAsync(new EAELD9080Data
|
||||
{
|
||||
RealTimeCurrent = 实时电流,
|
||||
RealTimePower = 实时电压,
|
||||
RealTimeVoltage = 实时功率,
|
||||
CollectTime = DateTime.Now
|
||||
});
|
||||
if (reuslt.IsSuccess)
|
||||
{
|
||||
var dataDic = new Dictionary<string, double>
|
||||
{
|
||||
{ "实时电流", 实时电流 },
|
||||
{ "实时电压", 实时电压 },
|
||||
{ "实时功率", 实时功率 }
|
||||
};
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Publish(("EAEL9080", dataDic));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify(reuslt.Msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
63
BOB/Services/IT6724CPollingRead.cs
Normal file
63
BOB/Services/IT6724CPollingRead.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Model.SQLModel;
|
||||
using Service.Implement;
|
||||
using Service.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class IT6724CPollingRead : PollingRead
|
||||
{
|
||||
private IT6724C _IT6724C { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private IBaseService<IT6724CData> _iT6724CService { get; set; }
|
||||
public IT6724CPollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
_iT6724CService = containerProvider.Resolve<IT6724CService>();
|
||||
DeviceName = "Backfeed";
|
||||
_IT6724C = _devices.DeviceDic["IT6724C"] as IT6724C;
|
||||
}
|
||||
public double 实时电流 { get; set; } = double.NaN;
|
||||
public double 实时电压 { get; set; } = double.NaN;
|
||||
public double 实时功率 { get; set; } = double.NaN;
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
实时电流 = Random.Shared.NextDouble() * 10;
|
||||
实时电压 = Random.Shared.NextDouble() * 10;
|
||||
实时功率 = Random.Shared.NextDouble() * 10;
|
||||
//实时电流 = await _IT6724C!.查询实时电流(ct);
|
||||
//实时电压 = await _IT6724C!.查询实时电压(ct);
|
||||
//实时功率 = await _IT6724C!.查询实时功率(ct);
|
||||
var reuslt = await _iT6724CService.InsertAsync(new IT6724CData
|
||||
{
|
||||
RealTimeCurrent = 实时电流,
|
||||
RealTimePower = 实时电压,
|
||||
RealTimeVoltage = 实时功率,
|
||||
CollectTime = DateTime.Now
|
||||
});
|
||||
if (reuslt.IsSuccess)
|
||||
{
|
||||
var dataDic = new Dictionary<string, double>
|
||||
{
|
||||
{ "实时电流", 实时电流 },
|
||||
{ "实时电压", 实时电压 },
|
||||
{ "实时功率", 实时功率 }
|
||||
};
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Publish(("IT6724C", dataDic));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify(reuslt.Msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
BOB/Services/LQ7500-DPollingRead.cs
Normal file
41
BOB/Services/LQ7500-DPollingRead.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class LQ7500_DPollingRead : PollingRead
|
||||
{
|
||||
private LQ7500_D _LQ7500_D { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
public LQ7500_DPollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
DeviceName = "LQ7500_D";
|
||||
_LQ7500_D = _devices.DeviceDic["LQ7500_D"] as LQ7500_D;
|
||||
}
|
||||
public double 内部传感器温度 { get; set; } = double.NaN;
|
||||
public double 外部传感器温度 { get; set; } = double.NaN;
|
||||
public double 水流量 { get; set; } = double.NaN;
|
||||
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
内部传感器温度 = await _LQ7500_D.读取内部传感器温度();
|
||||
外部传感器温度 = await _LQ7500_D.读取外部传感器温度();
|
||||
水流量 = await _LQ7500_D.读取流量();
|
||||
var dataDic = new Dictionary<string, double>
|
||||
{
|
||||
{ "内部传感器温度", 内部传感器温度 },
|
||||
{ "外部传感器温度", 外部传感器温度 },
|
||||
{ "水流量", 水流量 }
|
||||
};
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Publish(("LQ7500_D", dataDic));
|
||||
}
|
||||
}
|
||||
}
|
||||
65
BOB/Services/PSB11000PollingRead.cs
Normal file
65
BOB/Services/PSB11000PollingRead.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Model.SQLModel;
|
||||
using Service.Implement;
|
||||
using Service.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class PSB11000PollingRead : PollingRead
|
||||
{
|
||||
private PSB11000 _PSB11000 { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private IBaseService<PSB1100Data> _pSB1100Service { get; set; }
|
||||
public PSB11000PollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
_pSB1100Service = containerProvider.Resolve<PSB11000Service>();
|
||||
DeviceName = "PSB11000";
|
||||
_PSB11000 = _devices.DeviceDic["PSB11000"] as PSB11000;
|
||||
}
|
||||
public double 实时电流 { get; set; } = double.NaN;
|
||||
public double 实时电压 { get; set; } = double.NaN;
|
||||
public double 实时功率 { get; set; } = double.NaN;
|
||||
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
|
||||
实时电流 = Random.Shared.NextDouble() * 10;
|
||||
实时电压 = Random.Shared.NextDouble() * 10;
|
||||
实时功率 = Random.Shared.NextDouble() * 10;
|
||||
//实时电流 = await _PSB11000!.查询电流(ct);
|
||||
//实时电压 = await _PSB11000!.查询电压(ct);
|
||||
//实时功率 = await _PSB11000!.查询功率(ct);
|
||||
var reuslt = await _pSB1100Service.InsertAsync(new PSB1100Data
|
||||
{
|
||||
RealTimeCurrent = 实时电流,
|
||||
RealTimePower = 实时电压,
|
||||
RealTimeVoltage = 实时功率,
|
||||
CollectTime = DateTime.Now
|
||||
});
|
||||
if (reuslt.IsSuccess)
|
||||
{
|
||||
var dataDic = new Dictionary<string, double>
|
||||
{
|
||||
{ "实时电流", 实时电流 },
|
||||
{ "实时电压", 实时电压 },
|
||||
{ "实时功率", 实时功率 }
|
||||
};
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Publish(("PSB11000", dataDic));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify(reuslt.Msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
BOB/Services/PollingRead.cs
Normal file
75
BOB/Services/PollingRead.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using BOB.Converters;
|
||||
using Common.PubEvent;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public abstract class PollingRead
|
||||
{
|
||||
private CancellationTokenSource _pollingCancellationTokenSource;
|
||||
private Task? _pollingTask;
|
||||
public int PollingInterval = 1000;
|
||||
public string DeviceName{get;set;}="";
|
||||
private bool IsConnect{ get; set; }=false;
|
||||
public PollingRead(IContainerProvider containerProvider)
|
||||
{
|
||||
var _eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
_eventAggregator.GetEvent<ConnectionChangeEvent>().Subscribe(PollingConnection);
|
||||
}
|
||||
|
||||
private void PollingConnection((string, bool) tuple)
|
||||
{
|
||||
var (device, isConnect) = tuple;
|
||||
//System.Diagnostics.Debug.WriteLine($"PollingRead收到连接状态变化事件:设备={device},状态={isConnect}");
|
||||
if (device== DeviceName)
|
||||
{
|
||||
IsConnect = isConnect;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartPolling()
|
||||
{
|
||||
if (_pollingTask != null)
|
||||
return;
|
||||
|
||||
if (_pollingCancellationTokenSource == null || _pollingCancellationTokenSource.IsCancellationRequested)
|
||||
_pollingCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_pollingTask = Task.Run(() => PollingLoop(_pollingCancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
public void StopPolling()
|
||||
{
|
||||
_pollingCancellationTokenSource?.Cancel();
|
||||
_pollingTask = null;
|
||||
}
|
||||
|
||||
private async Task PollingLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
if (IsConnect)
|
||||
{
|
||||
await Task.Delay(PollingInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await ReadDeviceDataAsync(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"轮询过程中发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract Task ReadDeviceDataAsync(CancellationToken ct = default);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
32
BOB/Services/SQ0030G1DPollingRead.cs
Normal file
32
BOB/Services/SQ0030G1DPollingRead.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class SQ0030G1DPollingRead : PollingRead
|
||||
{
|
||||
private SQ0030G1D _SQ0030G1D { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
public SQ0030G1DPollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
DeviceName = "SQ0030G1D";
|
||||
_SQ0030G1D = _devices.DeviceDic["SQ0030G1D"] as SQ0030G1D;
|
||||
}
|
||||
|
||||
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
30
BOB/Services/WS-68030-380TPollingRead.cs
Normal file
30
BOB/Services/WS-68030-380TPollingRead.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class WS_68030_380TPollingRead : PollingRead
|
||||
{
|
||||
private WS_68030_380T _WS_68030_380T { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
public WS_68030_380TPollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
DeviceName = "WS_68030_380T";
|
||||
_WS_68030_380T = _devices.DeviceDic["WS_68030_380T"] as WS_68030_380T;
|
||||
}
|
||||
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
32
BOB/Services/ZXKSPollingRead.cs
Normal file
32
BOB/Services/ZXKSPollingRead.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Services
|
||||
{
|
||||
public class ZXKSPollingRead : PollingRead
|
||||
{
|
||||
private ZXKS _ZXKS { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
public ZXKSPollingRead(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
var _devices = containerProvider.Resolve<Devices>();
|
||||
DeviceName = "ZXKS";
|
||||
_ZXKS = _devices.DeviceDic["ZXKS"] as ZXKS;
|
||||
}
|
||||
public double 实时电流 { get; set; } = double.NaN;
|
||||
public double 实时电压 { get; set; } = double.NaN;
|
||||
public double 实时功率 { get; set; } = double.NaN;
|
||||
|
||||
public override async Task ReadDeviceDataAsync(CancellationToken ct = default)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
345
BOB/Singleton/Devices.cs
Normal file
345
BOB/Singleton/Devices.cs
Normal file
@ -0,0 +1,345 @@
|
||||
using BOB.Services;
|
||||
using CAN驱动;
|
||||
using Castle.DynamicProxy;
|
||||
using DeviceCommand.Base;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Model;
|
||||
using Npgsql.TypeHandlers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.Singleton
|
||||
{
|
||||
public class Devices
|
||||
{
|
||||
public Devices(IContainerProvider containerProvider)
|
||||
{
|
||||
_containerProvider=containerProvider;
|
||||
}
|
||||
private IContainerProvider _containerProvider;
|
||||
private CancellationTokenSource _appCancellationTokenSource = new();
|
||||
public CancellationToken AppCancellationToken => _appCancellationTokenSource.Token;
|
||||
|
||||
public Dictionary<string, object> DeviceDic { get; private set; } = new Dictionary<string, object>();
|
||||
public Dictionary<string, PollingRead> PollingReadDic { get; private set; } = new Dictionary<string, PollingRead>();
|
||||
|
||||
private readonly ProxyGenerator _proxyGen = new ProxyGenerator();
|
||||
private readonly IInterceptor _loggingInterceptor = new LoggingInterceptor();
|
||||
|
||||
private ISerialPort IT6724CDevice { get; set; }
|
||||
private ITcp EAEL9080Device { get; set; }
|
||||
private IModbusDevice IOBoardevice { get; set; }
|
||||
private IModbusDevice LQ7500_DDevice { get; set; }
|
||||
private ITcp PSB11000Device { get; set; }
|
||||
private IModbusDevice WS_68030_380TDevice { get; set; }
|
||||
private ITcp SQ0030G1DTDevice { get; set; }
|
||||
private IModbusDevice ZXKSTDevice { get; set; }
|
||||
private Backfeed BackfeedDevice { get; set; }
|
||||
|
||||
public void Init(List<DeviceConfigModel> deviceList)
|
||||
{
|
||||
foreach (var device in deviceList)
|
||||
{
|
||||
if (!device.IsEnabled) continue;
|
||||
switch (device.DeviceType)
|
||||
{
|
||||
case "DeviceCommand.Device.E36233A":
|
||||
if (device.CommunicationConfig is TcpConfig tcp1)
|
||||
{
|
||||
BackfeedDevice = _proxyGen.CreateClassProxy<Backfeed>(
|
||||
new object[] { tcp1 },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["Backfeed"] = BackfeedDevice;
|
||||
}
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.IT6724CReverse":
|
||||
if (device.CommunicationConfig is SerialPortConfig sp3)
|
||||
{
|
||||
BackfeedDevice = _proxyGen.CreateClassProxy<Backfeed>(
|
||||
new object[] { sp3 },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["Backfeed"] = BackfeedDevice;
|
||||
}
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.IT6724C":
|
||||
if (device.CommunicationConfig is SerialPortConfig sp1)
|
||||
{
|
||||
var IT6724CDevice = _proxyGen.CreateClassProxy<IT6724C>(
|
||||
new object[] { sp1.COMPort, sp1.BaudRate, sp1.DataBit, sp1.StopBit, sp1.ParityBit, sp1.ReadTimeout, sp1.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["IT6724C"] = IT6724CDevice;
|
||||
}
|
||||
else throw new InvalidOperationException("IT6724C 必须使用 SerialPortConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.LQ7500_D":
|
||||
if (device.CommunicationConfig is SerialPortConfig sp2)
|
||||
{
|
||||
var LQ7500_DDevice = _proxyGen.CreateClassProxy<LQ7500_D>(
|
||||
new object[] { sp2.COMPort, sp2.BaudRate, sp2.DataBit, sp2.StopBit, sp2.ParityBit, sp2.ReadTimeout, sp2.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["LQ7500_D"] = LQ7500_DDevice;
|
||||
}
|
||||
else throw new InvalidOperationException("LQ7500D 必须使用 SerialPortConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.EAEL9080":
|
||||
if (device.CommunicationConfig is TcpConfig tcp2)
|
||||
{
|
||||
var EAEL9080Device = _proxyGen.CreateClassProxy<EAEL9080>(
|
||||
new object[] { tcp2.IPAddress, tcp2.Port, tcp2.ReadTimeout, tcp2.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["EAEL9080"] = EAEL9080Device;
|
||||
}
|
||||
else throw new InvalidOperationException("EAEL9080 必须使用 TcpConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.IOBoard":
|
||||
if (device.CommunicationConfig is TcpConfig tcp3)
|
||||
{
|
||||
var IOBoardevice = _proxyGen.CreateClassProxy<IOBoard>(
|
||||
new object[] { tcp3.IPAddress, tcp3.Port, tcp3.ReadTimeout, tcp3.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["IOBoard"] = IOBoardevice;
|
||||
}
|
||||
else throw new InvalidOperationException("IOBoard 必须使用 TcpConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.PSB11000":
|
||||
if (device.CommunicationConfig is TcpConfig tcp4)
|
||||
{
|
||||
var PSB11000Device = _proxyGen.CreateClassProxy<PSB11000>(
|
||||
new object[] { tcp4.IPAddress, tcp4.Port, tcp4.ReadTimeout, tcp4.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["PSB11000"] = PSB11000Device;
|
||||
}
|
||||
else throw new InvalidOperationException("PSB11000 必须使用 TcpConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.WS_68030_380T":
|
||||
if (device.CommunicationConfig is TcpConfig tcp5)
|
||||
{
|
||||
var WS_68030_380TDevice = _proxyGen.CreateClassProxy<WS_68030_380T>(
|
||||
new object[] { tcp5.IPAddress, tcp5.Port, tcp5.ReadTimeout, tcp5.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["WS_68030_380T"] = WS_68030_380TDevice;
|
||||
}
|
||||
else throw new InvalidOperationException("WS_68030_380T 必须使用 TcpConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.SQ0030G1D":
|
||||
if (device.CommunicationConfig is TcpConfig tcp7)
|
||||
{
|
||||
var SQ0030G1DTDevice = _proxyGen.CreateClassProxy<SQ0030G1D>(
|
||||
new object[] { tcp7.IPAddress, tcp7.Port, tcp7.ReadTimeout, tcp7.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["SQ0030G1D"] = SQ0030G1DTDevice;
|
||||
}
|
||||
else throw new InvalidOperationException("SQ0030G1D 必须使用 TcpConfig");
|
||||
break;
|
||||
|
||||
case "DeviceCommand.Device.ZXKS":
|
||||
if (device.CommunicationConfig is TcpConfig tcp6)
|
||||
{
|
||||
var ZXKSTDevice = _proxyGen.CreateClassProxy<ZXKS>(
|
||||
new object[] { tcp6.IPAddress, tcp6.Port, tcp6.ReadTimeout, tcp6.WriteTimeout },
|
||||
_loggingInterceptor
|
||||
);
|
||||
DeviceDic["ZXKS"] = ZXKSTDevice;
|
||||
}
|
||||
else throw new InvalidOperationException("ZXKS 必须使用 TcpConfig");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"未知设备类型:{device.DeviceType}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void InitCan()
|
||||
{
|
||||
同星驱动类.DisConnect();
|
||||
var re1 = 同星驱动类.Init("ATS测试系统");
|
||||
var re2 = 同星驱动类.Connect();
|
||||
if (re1 == 0 && re2 == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public async Task ConnectAllDevicesAsync()
|
||||
{
|
||||
if (DeviceDic.Count == 0)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
foreach (var kvp in DeviceDic)
|
||||
{
|
||||
var name = kvp.Key;
|
||||
var device = kvp.Value;
|
||||
|
||||
if (device == null)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify($"{name} 实例为空,跳过连接");
|
||||
continue;
|
||||
}
|
||||
await Task.Delay(10);
|
||||
try
|
||||
{
|
||||
// 检查并处理 ITcp 接口
|
||||
if (device is ITcp itcpDevice)
|
||||
{
|
||||
bool result = await itcpDevice.ConnectAsync(CancellationToken.None);
|
||||
LoggerHelper.SuccessWithNotify($"{name} 连接成功 (ITcp)");
|
||||
}
|
||||
// 检查并处理 IModbusDevice 接口
|
||||
else if (device is IModbusDevice imodbusDevice)
|
||||
{
|
||||
bool result = await imodbusDevice.ConnectAsync(CancellationToken.None);
|
||||
LoggerHelper.SuccessWithNotify($"{name} 连接成功 (IModbusDevice)");
|
||||
}
|
||||
// 检查并处理 ISerialPort 接口
|
||||
else if (device is ISerialPort iserialPortDevice)
|
||||
{
|
||||
bool result = await iserialPortDevice.ConnectAsync(CancellationToken.None);
|
||||
LoggerHelper.SuccessWithNotify($"{name} 连接成功 (ISerialPort)");
|
||||
}
|
||||
// 检查并处理 Backfeed 类型
|
||||
else if (device is Backfeed backfeedDevice)
|
||||
{
|
||||
if(backfeedDevice.CurrentInstance is ITcp itcpDevice1)
|
||||
{
|
||||
bool result = await itcpDevice1.ConnectAsync(CancellationToken.None);
|
||||
}
|
||||
else if (backfeedDevice.CurrentInstance is ISerialPort iserialPortDevice1)
|
||||
{
|
||||
bool result = await iserialPortDevice1.ConnectAsync(CancellationToken.None);
|
||||
}
|
||||
LoggerHelper.SuccessWithNotify($"{name} 连接成功 (Backfeed)");
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.WarnWithNotify($"{name} 不是有效的设备类型");
|
||||
}
|
||||
}
|
||||
catch(InvalidCastException ex)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"{name} 连接失败: {ex.Message}", ex.StackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public void StartPollingCollectionAsync()
|
||||
{
|
||||
foreach (var dc in DeviceDic)
|
||||
{
|
||||
var name = dc.Key;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "Backfeed":
|
||||
{
|
||||
var polling = new BackfeedPollingRead(_containerProvider);
|
||||
PollingReadDic.Add("Backfeed", polling);
|
||||
polling.StartPolling();
|
||||
break;
|
||||
}
|
||||
|
||||
case "IT6724C":
|
||||
{
|
||||
var polling = new IT6724CPollingRead(_containerProvider);
|
||||
PollingReadDic.Add("IT6724C", polling);
|
||||
polling.StartPolling();
|
||||
break;
|
||||
}
|
||||
|
||||
case "LQ7500_D":
|
||||
{
|
||||
var polling = new LQ7500_DPollingRead(_containerProvider);
|
||||
PollingReadDic.Add("LQ7500_D", polling);
|
||||
polling.StartPolling();
|
||||
break;
|
||||
}
|
||||
|
||||
case "EAEL9080":
|
||||
{
|
||||
var polling = new EAEL9080PollingRead(_containerProvider);
|
||||
PollingReadDic.Add("EAEL9080", polling);
|
||||
polling.StartPolling();
|
||||
break;
|
||||
}
|
||||
|
||||
case "IOBoard":
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "PSB11000":
|
||||
{
|
||||
var polling = new PSB11000PollingRead(_containerProvider);
|
||||
PollingReadDic.Add("PSB11000", polling);
|
||||
polling.StartPolling();
|
||||
break;
|
||||
}
|
||||
|
||||
case "WS_68030_380T":
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "SQ0030G1D":
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "ZXKS":
|
||||
{
|
||||
var polling = new ZXKSPollingRead(_containerProvider);
|
||||
PollingReadDic.Add("ZXKS", polling);
|
||||
polling.StartPolling();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LoggerHelper.Warn($"未定义 {name} 的轮询处理器");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_appCancellationTokenSource.Cancel();
|
||||
_appCancellationTokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,5 @@ namespace BOB
|
||||
public PackIconKind RunIcon { get; set; } = PackIconKind.Play;
|
||||
public StepModel SelectedStep { get; set; }
|
||||
public ParameterModel SelectedParameter { get; set; }
|
||||
public DeviceModel SelectedDevice { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using BOB.Models;
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using Common.Tools;
|
||||
using Logger;
|
||||
@ -19,6 +20,8 @@ namespace BOB
|
||||
public class StepRunning
|
||||
{
|
||||
private GlobalVariables _globalVariables;
|
||||
private Devices _devices;
|
||||
private IContainerProvider containerProvider;
|
||||
private IEventAggregator _eventAggregator;
|
||||
|
||||
private readonly Dictionary<Guid, ParameterModel> tmpParameters = [];
|
||||
@ -33,10 +36,11 @@ namespace BOB
|
||||
private bool SubSingleStep = false;
|
||||
|
||||
private Guid TestRoundID;
|
||||
public StepRunning(GlobalVariables globalVariables,IEventAggregator eventAggregator)
|
||||
public StepRunning(GlobalVariables globalVariables,IEventAggregator eventAggregator,IContainerProvider containerProvider)
|
||||
{
|
||||
_globalVariables = globalVariables;
|
||||
_eventAggregator= eventAggregator;
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = eventAggregator;
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
}
|
||||
public async Task<bool> ExecuteSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@ -359,7 +363,7 @@ namespace BOB
|
||||
{
|
||||
try
|
||||
{
|
||||
instance = Activator.CreateInstance(targetType);
|
||||
instance = _devices.DeviceDic[targetType.Name];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
using BOB.Models;
|
||||
using Logger;
|
||||
using Newtonsoft.Json;
|
||||
using Model;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
@ -31,6 +32,9 @@ namespace BOB
|
||||
|
||||
[JsonIgnore]
|
||||
public string SystemPath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BOB");
|
||||
public string Title { get; set; } = "";
|
||||
public int SaveDay { get; set; }
|
||||
public string DBSavePath { get; set; } = "";
|
||||
|
||||
public int PerformanceLevel { get; set; } = 50;
|
||||
|
||||
@ -39,6 +43,7 @@ namespace BOB
|
||||
public string SubProgramFilePath { get; set; } = @"D:\BOB\子程序\";
|
||||
|
||||
public string DefaultSubProgramFilePath { get; set; } = "";
|
||||
public ObservableCollection<string> CurSingleList { get; set; }
|
||||
public List<DeviceConfigModel> DeviceList { get; set; } = new();
|
||||
|
||||
#region 配置加载方法
|
||||
@ -51,7 +56,7 @@ namespace BOB
|
||||
if (!Directory.Exists(SystemPath))
|
||||
Directory.CreateDirectory(SystemPath);
|
||||
|
||||
string configPath = Path.Combine(SystemPath, "system.json");
|
||||
string configPath = Path.Combine(SystemPath, $"{Title}.json");
|
||||
|
||||
// 支持接口多态序列化
|
||||
string json = JsonConvert.SerializeObject(this, Formatting.Indented,
|
||||
@ -73,11 +78,13 @@ namespace BOB
|
||||
|
||||
public void LoadFromFile()
|
||||
{
|
||||
string configPath = Path.Combine(SystemPath, "system.json");
|
||||
|
||||
string configPath = Path.Combine(SystemPath, $"{Title}.json");
|
||||
if(Title == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
// 文件不存在则保存当前配置
|
||||
SaveToFile();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using BOB.Models;
|
||||
using BOB.Singleton;
|
||||
using Common.Attributes;
|
||||
using Logger;
|
||||
using Microsoft.IdentityModel.Logging;
|
||||
@ -89,9 +90,11 @@ namespace BOB.ViewModels
|
||||
public ICommand SearchEnterCommand { get; set; }
|
||||
public ICommand TreeDoubleClickCommand { get; set; }
|
||||
public ICommand ReloadCommand { get; set; }
|
||||
public CommandTreeViewModel(GlobalVariables _GlobalVariables)
|
||||
private Devices _devices { get; set; }
|
||||
public CommandTreeViewModel(GlobalVariables _GlobalVariables, Devices devices)
|
||||
{
|
||||
_globalVariables= _GlobalVariables;
|
||||
_devices = devices;
|
||||
LoadedCommand = new DelegateCommand(Loaded);
|
||||
SearchEnterCommand = new DelegateCommand(Search);
|
||||
TreeDoubleClickCommand = new DelegateCommand<object>(TreeDoubleClick);
|
||||
@ -143,8 +146,8 @@ namespace BOB.ViewModels
|
||||
|
||||
private void Loaded()
|
||||
{
|
||||
Directory.CreateDirectory(SystemConfig.Instance.DLLFilePath);
|
||||
Directory.CreateDirectory(SystemConfig.Instance.SubProgramFilePath);
|
||||
//Directory.CreateDirectory(SystemConfig.Instance.DLLFilePath);
|
||||
//Directory.CreateDirectory(SystemConfig.Instance.SubProgramFilePath);
|
||||
LoadAllAssemblies();
|
||||
LoadSubPrograms();
|
||||
LoadInstructionsToTreeView();
|
||||
@ -267,12 +270,12 @@ namespace BOB.ViewModels
|
||||
foreach (var assembly in Assemblies)
|
||||
{
|
||||
List<Type> validTypes = new List<Type>();
|
||||
|
||||
try
|
||||
{
|
||||
var types = assembly.GetTypes().Where(t =>
|
||||
t.IsPublic &&
|
||||
!t.IsNested &&
|
||||
|
||||
(t.IsClass || t.IsValueType) &&
|
||||
(!t.IsAbstract || t.IsSealed) &&
|
||||
t.GetCustomAttribute<BOBCommandAttribute>() != null);
|
||||
@ -306,6 +309,7 @@ namespace BOB.ViewModels
|
||||
|
||||
foreach (var type in validTypes)
|
||||
{
|
||||
if (!_devices.DeviceDic.ContainsKey(type.Name)&& assembly.GetName().Name!= "Command") continue;
|
||||
var typeNode = new InstructionNode
|
||||
{
|
||||
Name = type.Name,
|
||||
@ -355,7 +359,7 @@ namespace BOB.ViewModels
|
||||
private void GetPublicMethods(Type type, HashSet<MethodInfo> methods)
|
||||
{
|
||||
// 获取当前类型的所有公共方法(包括继承的)
|
||||
var allMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
|
||||
var allMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)
|
||||
.Where(m => !m.IsSpecialName &&
|
||||
m.DeclaringType != typeof(object))
|
||||
.ToList();
|
||||
@ -487,13 +491,6 @@ namespace BOB.ViewModels
|
||||
var tmp = JsonConvert.DeserializeObject<ProgramModel>(jsonstr);
|
||||
if (tmp != null)
|
||||
{
|
||||
if (tmp.Devices != null && tmp.Devices.Count > 0)
|
||||
{
|
||||
foreach (var device in tmp.Devices)
|
||||
{
|
||||
// _ = DeviceConnect.InitAndConnectDevice(tmp, device);
|
||||
}
|
||||
}
|
||||
newStep.SubProgram = tmp;
|
||||
}
|
||||
if (insertIndex >= 0 && insertIndex <= Program.StepCollection.Count)
|
||||
|
||||
360
BOB/ViewModels/DataViewModel.cs
Normal file
360
BOB/ViewModels/DataViewModel.cs
Normal file
@ -0,0 +1,360 @@
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using Logger;
|
||||
using Model.SQLModel;
|
||||
using Prism.Commands;
|
||||
using Prism.Mvvm;
|
||||
using Service.Implement;
|
||||
using Service.Interface;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels
|
||||
{
|
||||
public class DataViewModel : BindableBase, INavigationAware
|
||||
{
|
||||
#region 属性
|
||||
|
||||
private int _currentPage = 1;
|
||||
public int CurrentPage
|
||||
{
|
||||
get => _currentPage;
|
||||
set => SetProperty(ref _currentPage, value);
|
||||
}
|
||||
|
||||
private RefAsync<int> _totalPages=new RefAsync<int>(0);
|
||||
public RefAsync<int> TotalPages
|
||||
{
|
||||
get => _totalPages;
|
||||
set => SetProperty(ref _totalPages, value);
|
||||
}
|
||||
private int _UITotalPages;
|
||||
public int UITotalPages
|
||||
{
|
||||
get => _UITotalPages;
|
||||
set => SetProperty(ref _UITotalPages, value);
|
||||
}
|
||||
|
||||
private List<string> _dataTableList;
|
||||
public List<string> DataTableList
|
||||
{
|
||||
get => _dataTableList;
|
||||
set => SetProperty(ref _dataTableList, value);
|
||||
}
|
||||
private string _SelectTable;
|
||||
public string SelectTable
|
||||
{
|
||||
get => _SelectTable;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _SelectTable, value))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
private List<BackFeedData> _BackFeedDataList;
|
||||
public List<BackFeedData> BackFeedDataList
|
||||
{
|
||||
get => _BackFeedDataList;
|
||||
set => SetProperty(ref _BackFeedDataList, value);
|
||||
}
|
||||
private List<EAELD9080Data> _EAELD9080DataList;
|
||||
public List<EAELD9080Data> EAELD9080DataList
|
||||
{
|
||||
get => _EAELD9080DataList;
|
||||
set => SetProperty(ref _EAELD9080DataList, value);
|
||||
}
|
||||
private List<PSB1100Data> _PSB1100DataList;
|
||||
public List<PSB1100Data> PSB1100DataList
|
||||
{
|
||||
get => _PSB1100DataList;
|
||||
set => SetProperty(ref _PSB1100DataList, value);
|
||||
}
|
||||
private List<IT6724CData> _IT6724CDataList;
|
||||
public List<IT6724CData> IT6724CDataList
|
||||
{
|
||||
get => _IT6724CDataList;
|
||||
set => SetProperty(ref _IT6724CDataList, value);
|
||||
}
|
||||
private DateTime? _startDate;
|
||||
public DateTime? StartDate
|
||||
{
|
||||
get => _startDate;
|
||||
set => SetProperty(ref _startDate, value);
|
||||
}
|
||||
|
||||
private DateTime? _endDate;
|
||||
public DateTime? EndDate
|
||||
{
|
||||
get => _endDate;
|
||||
set => SetProperty(ref _endDate, value);
|
||||
}
|
||||
private ObservableCollection<object> _currentDataSource;
|
||||
public ObservableCollection<object> CurrentDataSource
|
||||
{
|
||||
get => _currentDataSource;
|
||||
set => SetProperty(ref _currentDataSource, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand FirstPageCommand { get; private set; }
|
||||
public ICommand PreviousPageCommand { get; private set; }
|
||||
public ICommand NextPageCommand { get; private set; }
|
||||
public ICommand LastPageCommand { get; private set; }
|
||||
public ICommand LoadCommand { get; private set; }
|
||||
public ICommand QueryCommand { get; private set; }
|
||||
public ICommand RefreshCommand { get; private set; }
|
||||
public ICommand SelectTableCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
private IEventAggregator _eventAggregator;
|
||||
private IDialogService _dialogService;
|
||||
private Devices _devices { get; set; }
|
||||
private IBaseService<BackFeedData> _backFeedService { get; set; }
|
||||
private IBaseService<EAELD9080Data> _eAELD9080Service { get; set; }
|
||||
private IBaseService<PSB1100Data> _pSB1100Service { get; set; }
|
||||
private IBaseService<IT6724CData> _iT6724CService { get; set; }
|
||||
|
||||
public DataViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
_dialogService = containerProvider.Resolve<IDialogService>();
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_backFeedService= containerProvider.Resolve<BackFeedService>();
|
||||
_eAELD9080Service = containerProvider.Resolve<EAEL9080Service>();
|
||||
_pSB1100Service = containerProvider.Resolve<PSB11000Service>();
|
||||
_iT6724CService = containerProvider.Resolve<IT6724CService>();
|
||||
FirstPageCommand = new AsyncDelegateCommand(GoToFirstPage);
|
||||
PreviousPageCommand = new AsyncDelegateCommand(GoToPreviousPage);
|
||||
NextPageCommand = new AsyncDelegateCommand(GoToNextPage);
|
||||
LastPageCommand = new AsyncDelegateCommand(GoToLastPage);
|
||||
LoadCommand = new AsyncDelegateCommand(Load);
|
||||
QueryCommand = new AsyncDelegateCommand(Query);
|
||||
RefreshCommand = new AsyncDelegateCommand(Refresh);
|
||||
SelectTableCommand = new AsyncDelegateCommand(OnSelectTable);
|
||||
DataTableList = new List<string> { "BackFeedData", "EAELD9080Data", "IT6724CData", "PSB1100Data"};
|
||||
}
|
||||
|
||||
private async Task OnSelectTable()
|
||||
{
|
||||
switch (SelectTable)
|
||||
{
|
||||
case "BackFeedData":
|
||||
CurrentDataSource = new ObservableCollection<object>(BackFeedDataList);
|
||||
break;
|
||||
case "EAELD9080Data":
|
||||
CurrentDataSource = new ObservableCollection<object>(EAELD9080DataList);
|
||||
break;
|
||||
case "PSB1100Data":
|
||||
CurrentDataSource = new ObservableCollection<object>(PSB1100DataList);
|
||||
break;
|
||||
case "IT6724CData":
|
||||
CurrentDataSource = new ObservableCollection<object>(IT6724CDataList);
|
||||
break;
|
||||
default:
|
||||
CurrentDataSource = new ObservableCollection<object>();
|
||||
break;
|
||||
}
|
||||
GoToFirstPage();
|
||||
}
|
||||
private DateTime? QueryStartTime;
|
||||
private DateTime? QueryEndTime;
|
||||
private bool DataQuery=false;
|
||||
private async Task Refresh()
|
||||
{
|
||||
DataQuery = false;
|
||||
QueryStartTime = null;
|
||||
QueryEndTime = null;
|
||||
await GoToFirstPage();
|
||||
}
|
||||
|
||||
private async Task Query()
|
||||
{
|
||||
if (!StartDate.HasValue || !EndDate.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DateTime endDateWithTime = EndDate.Value.AddDays(1);
|
||||
if (StartDate.Value < endDateWithTime)
|
||||
{
|
||||
QueryStartTime = StartDate;
|
||||
QueryEndTime = endDateWithTime;
|
||||
DataQuery = true;
|
||||
await GoToFirstPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task Load()
|
||||
{
|
||||
var backFeedResult = await _backFeedService.GetAllAsync();
|
||||
if (backFeedResult.IsSuccess)
|
||||
{
|
||||
BackFeedDataList = backFeedResult.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("加载 BackFeed 数据失败");
|
||||
}
|
||||
|
||||
var eaELD9080Result = await _eAELD9080Service.GetAllAsync();
|
||||
if (eaELD9080Result.IsSuccess)
|
||||
{
|
||||
EAELD9080DataList = eaELD9080Result.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("加载 EAELD9080 数据失败");
|
||||
}
|
||||
|
||||
var pSB1100Result = await _pSB1100Service.GetAllAsync();
|
||||
if (pSB1100Result.IsSuccess)
|
||||
{
|
||||
PSB1100DataList = pSB1100Result.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("加载 PSB1100 数据失败");
|
||||
}
|
||||
|
||||
var it6724CResult = await _iT6724CService.GetAllAsync();
|
||||
if (it6724CResult.IsSuccess)
|
||||
{
|
||||
IT6724CDataList = it6724CResult.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("加载 IT6724C 数据失败");
|
||||
}
|
||||
}
|
||||
private async Task GoToFirstPage()
|
||||
{
|
||||
CurrentPage = 1;
|
||||
await LoadPageData(CurrentPage);
|
||||
}
|
||||
|
||||
private async Task GoToPreviousPage()
|
||||
{
|
||||
if (CurrentPage > 1)
|
||||
{
|
||||
CurrentPage--;
|
||||
await LoadPageData(CurrentPage);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GoToNextPage()
|
||||
{
|
||||
if (CurrentPage < TotalPages)
|
||||
{
|
||||
CurrentPage++;
|
||||
await LoadPageData(CurrentPage);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GoToLastPage()
|
||||
{
|
||||
CurrentPage = TotalPages;
|
||||
await LoadPageData(CurrentPage);
|
||||
}
|
||||
|
||||
private int PageSize=20;
|
||||
private async Task LoadPageData(int currentPage)
|
||||
{
|
||||
switch (SelectTable)
|
||||
{
|
||||
case "BackFeedData":
|
||||
if (DataQuery) // 如果启用日期查询
|
||||
{
|
||||
var result = await _backFeedService.GetPagedAsync(currentPage, PageSize, TotalPages, QueryStartTime, QueryEndTime);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await _backFeedService.GetPagedAsync(currentPage, PageSize, TotalPages);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
break;
|
||||
|
||||
case "EAELD9080Data":
|
||||
if (DataQuery)
|
||||
{
|
||||
var result = await _eAELD9080Service.GetPagedAsync(currentPage, PageSize, TotalPages, QueryStartTime, QueryEndTime);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await _eAELD9080Service.GetPagedAsync(currentPage, PageSize, TotalPages);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
break;
|
||||
|
||||
case "PSB1100Data":
|
||||
if (DataQuery)
|
||||
{
|
||||
var result = await _pSB1100Service.GetPagedAsync(currentPage, PageSize, TotalPages, QueryStartTime, QueryEndTime);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await _pSB1100Service.GetPagedAsync(currentPage, PageSize, TotalPages);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
break;
|
||||
|
||||
case "IT6724CData":
|
||||
if (DataQuery)
|
||||
{
|
||||
var result = await _iT6724CService.GetPagedAsync(currentPage, PageSize, TotalPages, QueryStartTime, QueryEndTime);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await _iT6724CService.GetPagedAsync(currentPage, PageSize, TotalPages);
|
||||
if (result.IsSuccess)
|
||||
CurrentDataSource = new ObservableCollection<object>(result.Data);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
CurrentDataSource = new ObservableCollection<object>();
|
||||
break;
|
||||
}
|
||||
|
||||
UITotalPages = TotalPages.Value;
|
||||
}
|
||||
|
||||
#region 导航
|
||||
|
||||
public void OnNavigatedTo(NavigationContext navigationContext) { }
|
||||
|
||||
public bool IsNavigationTarget(NavigationContext navigationContext)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom(NavigationContext navigationContext) { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
454
BOB/ViewModels/Dialogs/BackfeedViewModel.cs
Normal file
454
BOB/ViewModels/Dialogs/BackfeedViewModel.cs
Normal file
@ -0,0 +1,454 @@
|
||||
using BOB.Singleton;
|
||||
using BOB.ViewModels.UserControls;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
using Prism.Commands;
|
||||
using Prism.Events;
|
||||
using Prism.Mvvm;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class BackfeedViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
#region 属性
|
||||
|
||||
private string _Title = "反灌电压";
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
|
||||
private string _设备标识字符串;
|
||||
public string 设备标识字符串
|
||||
{
|
||||
get { return _设备标识字符串; }
|
||||
set { SetProperty(ref _设备标识字符串, value); }
|
||||
}
|
||||
|
||||
private string _输出电压;
|
||||
public string 输出电压
|
||||
{
|
||||
get { return _输出电压; }
|
||||
set { SetProperty(ref _输出电压, value); }
|
||||
}
|
||||
|
||||
private string _输出电流;
|
||||
public string 输出电流
|
||||
{
|
||||
get { return _输出电流; }
|
||||
set { SetProperty(ref _输出电流, value); }
|
||||
}
|
||||
|
||||
private string _OCP电流;
|
||||
public string OCP电流
|
||||
{
|
||||
get { return _OCP电流; }
|
||||
set { SetProperty(ref _OCP电流, value); }
|
||||
}
|
||||
|
||||
private string _OVP电压;
|
||||
public string OVP电压
|
||||
{
|
||||
get { return _OVP电压; }
|
||||
set { SetProperty(ref _OVP电压, value); }
|
||||
}
|
||||
|
||||
private string _OPP功率;
|
||||
public string OPP功率
|
||||
{
|
||||
get { return _OPP功率; }
|
||||
set { SetProperty(ref _OPP功率, value); }
|
||||
}
|
||||
private LineSeries _电压_lineSeries = new LineSeries { Title = "电压(V)", StrokeThickness = 2 };
|
||||
public LineSeries 电压_lineSeries
|
||||
{
|
||||
get => _电压_lineSeries;
|
||||
set => SetProperty(ref _电压_lineSeries, value);
|
||||
}
|
||||
|
||||
private LineSeries _电流_lineSeries = new LineSeries { Title = "电流(A)", StrokeThickness = 2 };
|
||||
public LineSeries 电流_lineSeries
|
||||
{
|
||||
get => _电流_lineSeries;
|
||||
set => SetProperty(ref _电流_lineSeries, value);
|
||||
}
|
||||
|
||||
private LineSeries _功率_lineSeries = new LineSeries { Title = "功率(W)", StrokeThickness = 2 };
|
||||
public LineSeries 功率_lineSeries
|
||||
{
|
||||
get => _功率_lineSeries;
|
||||
set => SetProperty(ref _功率_lineSeries, value);
|
||||
}
|
||||
private NumericalDisplayViewModel _电压MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 电压MV
|
||||
{
|
||||
get => _电压MV;
|
||||
set => SetProperty(ref _电压MV, value);
|
||||
}
|
||||
|
||||
private NumericalDisplayViewModel _电流MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 电流MV
|
||||
{
|
||||
get => _电流MV;
|
||||
set => SetProperty(ref _电流MV, value);
|
||||
}
|
||||
|
||||
private NumericalDisplayViewModel _功率MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 功率MV
|
||||
{
|
||||
get => _功率MV;
|
||||
set => SetProperty(ref _功率MV, value);
|
||||
}
|
||||
private PlotModel _曲线Model = new PlotModel();
|
||||
public PlotModel 曲线Model
|
||||
{
|
||||
get => _曲线Model;
|
||||
set => SetProperty(ref _曲线Model, value);
|
||||
}
|
||||
public DateTimeAxis TimeAxis { get; private set; }
|
||||
public LinearAxis ValueAxis { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand ConnectCommand { get; private set; }
|
||||
public ICommand DisconnectCommand { get; private set; }
|
||||
public ICommand QueryDeviceCommand { get; private set; }
|
||||
public ICommand SetVoltageCommand { get; private set; }
|
||||
public ICommand SetCurrentCommand { get; private set; }
|
||||
public ICommand EnableOCPCommand { get; private set; }
|
||||
public ICommand DisableOCPCommand { get; private set; }
|
||||
public ICommand SetOCPCommand { get; private set; }
|
||||
public ICommand EnableOVPCommand { get; private set; }
|
||||
public ICommand DisableOVPCommand { get; private set; }
|
||||
public ICommand SetOVPCommand { get; private set; }
|
||||
public ICommand EnableOPPCommand { get; private set; }
|
||||
public ICommand DisableOPPCommand { get; private set; }
|
||||
public ICommand SetOPPCommand { get; private set; }
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
public ICommand ResetViewCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private IEventAggregator _eventAggregator { get;set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private object device { get; set; }
|
||||
|
||||
public BackfeedViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
|
||||
// Initialize commands
|
||||
ConnectCommand = new AsyncDelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
QueryDeviceCommand = new AsyncDelegateCommand(OnQueryDevice);
|
||||
SetVoltageCommand = new AsyncDelegateCommand(OnSetVoltage);
|
||||
SetCurrentCommand = new AsyncDelegateCommand(OnSetCurrent);
|
||||
EnableOCPCommand = new AsyncDelegateCommand(OnEnableOCP);
|
||||
DisableOCPCommand = new AsyncDelegateCommand(OnDisableOCP);
|
||||
SetOCPCommand = new AsyncDelegateCommand(OnSetOCP);
|
||||
EnableOVPCommand = new AsyncDelegateCommand(OnEnableOVP);
|
||||
DisableOVPCommand = new AsyncDelegateCommand(OnDisableOVP);
|
||||
SetOVPCommand = new AsyncDelegateCommand(OnSetOVP);
|
||||
EnableOPPCommand = new AsyncDelegateCommand(OnEnableOPP);
|
||||
DisableOPPCommand = new AsyncDelegateCommand(OnDisableOPP);
|
||||
SetOPPCommand = new AsyncDelegateCommand(OnSetOPP);
|
||||
CloseCommand = new DelegateCommand(OnClose);
|
||||
ResetViewCommand = new DelegateCommand(ResetView);
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Subscribe(UpdateCurve);
|
||||
InitCurve();
|
||||
}
|
||||
private void ResetView()
|
||||
{
|
||||
曲线Model.ResetAllAxes();
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
private void InitCurve()
|
||||
{
|
||||
TimeAxis = new DateTimeAxis
|
||||
{
|
||||
Position = AxisPosition.Bottom,
|
||||
StringFormat = "HH:mm:ss",
|
||||
IntervalType = DateTimeIntervalType.Seconds,
|
||||
};
|
||||
ValueAxis = new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
};
|
||||
曲线Model.Axes.Add(TimeAxis);
|
||||
曲线Model.Axes.Add(ValueAxis);
|
||||
曲线Model.Series.Add(电压_lineSeries);
|
||||
曲线Model.Series.Add(电流_lineSeries);
|
||||
曲线Model.Series.Add(功率_lineSeries);
|
||||
曲线Model.Legends.Add(new Legend()
|
||||
{
|
||||
LegendPosition = LegendPosition.TopRight,
|
||||
LegendOrientation = LegendOrientation.Vertical,
|
||||
LegendPlacement = LegendPlacement.Inside
|
||||
});
|
||||
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
private void UpdateCurve((string device, Dictionary<string, double> data )tuple)
|
||||
{
|
||||
var (device, data) = tuple;
|
||||
if (device != "IT6724C") return;
|
||||
电流MV.MonitorValue = data["实时电流"];
|
||||
电压MV.MonitorValue = data["实时电压"];
|
||||
功率MV.MonitorValue = data["实时功率"];
|
||||
|
||||
var now = DateTimeAxis.ToDouble(DateTime.Now);
|
||||
电流_lineSeries.Points.Add(new DataPoint(now, data["实时电流"]));
|
||||
电压_lineSeries.Points.Add(new DataPoint(now, data["实时电压"]));
|
||||
功率_lineSeries.Points.Add(new DataPoint(now, data["实时功率"]));
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
|
||||
#region Command Handlers
|
||||
|
||||
private async Task OnConnect()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.ConnectAsync();
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.ConnectAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
e36233A.Close();
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
it6724CReverse.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnQueryDevice()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
设备标识字符串 = await e36233A.查询设备信息();
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
设备标识字符串 = await it6724CReverse.查询设备信息();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSetVoltage()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置电压(Convert.ToDouble(输出电压));
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置电压(Convert.ToDouble(输出电压));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSetCurrent()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置电流(Convert.ToDouble(输出电流));
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置电流(Convert.ToDouble(输出电流));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnEnableOCP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置OCP开关(true);
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置OCP开关(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnDisableOCP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置OCP开关(false);
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置OCP开关(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSetOCP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置电流保护OCP电流(Convert.ToDouble(OCP电流));
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置电流保护OCP电流(Convert.ToDouble(OCP电流));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnEnableOVP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置OVP开关(true);
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置OVP开关(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnDisableOVP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置OVP开关(false);
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置OVP开关(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSetOVP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置电压保护OVP电压(Convert.ToDouble(OVP电压));
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置电压保护OVP电压(Convert.ToDouble(OVP电压));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnEnableOPP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置OVP开关(true);
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置OVP开关(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnDisableOPP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置OVP开关(false);
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置OVP开关(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSetOPP()
|
||||
{
|
||||
if (device is E36233A e36233A)
|
||||
{
|
||||
await e36233A.设置功率保护功率(Convert.ToDouble(OPP功率));
|
||||
}
|
||||
else if (device is IT6724CReverse it6724CReverse)
|
||||
{
|
||||
await it6724CReverse.设置功率保护功率(Convert.ToDouble(OPP功率));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClose()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dialog规范
|
||||
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
// Implement cleanup logic here if needed
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_devices.DeviceDic.ContainsKey("E36233A"))
|
||||
{
|
||||
var a = _devices.DeviceDic["E36233A"] as E36233A;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
else if (_devices.DeviceDic.ContainsKey("IT6724CReverse"))
|
||||
{
|
||||
var a = _devices.DeviceDic["IT6724CReverse"] as IT6724CReverse;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
107
BOB/ViewModels/Dialogs/CANViewModel.cs
Normal file
107
BOB/ViewModels/Dialogs/CANViewModel.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using BOB.Singleton;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class CANViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
|
||||
#region 属性
|
||||
private string _Title = "同星CAN";
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
private string _BLFPath;
|
||||
|
||||
public string BLFPath
|
||||
{
|
||||
get { return _BLFPath; }
|
||||
set { SetProperty(ref _BLFPath, value); }
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#region 命令
|
||||
public ICommand SelectBLFPathCommand { get; set; }
|
||||
public ICommand SaveBLFPathCommand { get; set; }
|
||||
public ICommand StartTranscirbeCommand { get; set; }
|
||||
public ICommand EndTranscirbeCommand { get; set; }
|
||||
|
||||
#endregion
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
public CANViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
SelectBLFPathCommand = new DelegateCommand(SelectBLFPath);
|
||||
SaveBLFPathCommand = new DelegateCommand(SaveBLFPath);
|
||||
StartTranscirbeCommand = new DelegateCommand(StartTranscirbe);
|
||||
EndTranscirbeCommand = new DelegateCommand(EndTranscirbe);
|
||||
}
|
||||
|
||||
#region 命令
|
||||
private void EndTranscirbe()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void StartTranscirbe()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void SaveBLFPath()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void SelectBLFPath()
|
||||
{
|
||||
var dialog = new SaveFileDialog
|
||||
{
|
||||
Title = "保存 CAN报文回放 BLF 文件",
|
||||
Filter = "BLF 文件 (*.blf)|*.blf|所有文件 (*.*)|*.*",
|
||||
DefaultExt = ".blf",
|
||||
FileName = "log.blf",
|
||||
OverwritePrompt = true
|
||||
};
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
BLFPath = Path.GetFullPath(dialog.FileName);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,212 +0,0 @@
|
||||
using BOB.Models;
|
||||
using Common.PubEvent;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using static BOB.Models.ParameterModel;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class DeviceSettingViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
#region 属性
|
||||
private string _title = "设备设置界面";
|
||||
public string Title
|
||||
{
|
||||
get => _title;
|
||||
set => SetProperty(ref _title, value);
|
||||
}
|
||||
private ObservableCollection<string> _types = ["串口", "Tcp", "ModbusRtu", "ModbusTcp", "CAN", "Udp"];
|
||||
public ObservableCollection<string> Types
|
||||
{
|
||||
get => _types;
|
||||
set => SetProperty(ref _types, value);
|
||||
}
|
||||
|
||||
private string _Mode;
|
||||
public string Mode
|
||||
{
|
||||
get => _Mode;
|
||||
set => SetProperty(ref _Mode, value);
|
||||
}
|
||||
private bool _IsAdd;
|
||||
public bool IsAdd
|
||||
{
|
||||
get => _IsAdd;
|
||||
set => SetProperty(ref _IsAdd, value);
|
||||
}
|
||||
|
||||
private ProgramModel _program;
|
||||
public ProgramModel Program
|
||||
{
|
||||
get => _program;
|
||||
set => SetProperty(ref _program, value);
|
||||
}
|
||||
private DeviceModel _Device;
|
||||
public DeviceModel Device
|
||||
{
|
||||
get => _Device;
|
||||
set => SetProperty(ref _Device, value);
|
||||
}
|
||||
private ObservableCollection<DeviceConnectSettingModel> _DeviceConnectSettings=new();
|
||||
public ObservableCollection<DeviceConnectSettingModel> DeviceConnectSettings
|
||||
{
|
||||
get => _DeviceConnectSettings;
|
||||
set => SetProperty(ref _DeviceConnectSettings, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
private GlobalVariables _globalVariables;
|
||||
private IEventAggregator _eventAggregator;
|
||||
public ICommand CancelCommand { get; set; }
|
||||
public ICommand SaveCommand { get; set; }
|
||||
public ICommand SelectionChangedCommand { get; set; }
|
||||
public DeviceSettingViewModel(GlobalVariables globalVariables, IEventAggregator eventAggregator)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
_globalVariables = globalVariables;
|
||||
CancelCommand = new DelegateCommand(Cancel);
|
||||
SaveCommand = new DelegateCommand(Save);
|
||||
SelectionChangedCommand = new DelegateCommand(SelectionChanged);
|
||||
}
|
||||
|
||||
private void SelectionChanged()
|
||||
{
|
||||
if (Device == null) return;
|
||||
DeviceConnectSettings.Clear();
|
||||
switch (Device!.Type)
|
||||
{
|
||||
case "Tcp":
|
||||
case "ModbusTcp":
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "IP地址",
|
||||
Value = "127.0.0.1"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "端口号",
|
||||
Value = "502"
|
||||
});
|
||||
break;
|
||||
case "串口":
|
||||
case "ModbusRtu":
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "COM口",
|
||||
Value = "COM1"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "波特率",
|
||||
Value = "9600"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "数据位",
|
||||
Value = "8"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "停止位",
|
||||
Value = "1"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "奇偶",
|
||||
Value = "无"
|
||||
});
|
||||
break;
|
||||
case "Udp":
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "远程IP地址",
|
||||
Value = "127.0.0.1"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "远程端口号",
|
||||
Value = "8080"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "本地端口号",
|
||||
Value = "0"
|
||||
});
|
||||
break;
|
||||
}
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "读超时",
|
||||
Value = "3000"
|
||||
});
|
||||
DeviceConnectSettings.Add(new()
|
||||
{
|
||||
Name = "写超时",
|
||||
Value = "3000"
|
||||
});
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
if (Mode == "ADD")
|
||||
{
|
||||
Program.Devices.Add(Device);
|
||||
_globalVariables.SelectedDevice = Device;
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = Program.Devices
|
||||
.Select((x, i) => new { x, i })
|
||||
.FirstOrDefault(p => p.x.ID == _globalVariables.SelectedDevice.ID)?.i;
|
||||
|
||||
if (index.HasValue)
|
||||
{
|
||||
Program.Devices[index.Value] = Device;
|
||||
}
|
||||
}
|
||||
RequestClose.Invoke(ButtonResult.OK);
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
RequestClose.Invoke(ButtonResult.No);
|
||||
}
|
||||
#region Prism Dialog 规范
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
_eventAggregator.GetEvent<OverlayEvent>().Publish(false);
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
_eventAggregator.GetEvent<OverlayEvent>().Publish(true);
|
||||
Program = _globalVariables.Program;
|
||||
Mode = parameters.GetValue<string>("Mode");
|
||||
if(Mode == "ADD")
|
||||
{
|
||||
Device = new();
|
||||
IsAdd = true;
|
||||
Device.Type = "Tcp";
|
||||
SelectionChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
Device = new DeviceModel(_globalVariables.SelectedDevice);
|
||||
IsAdd = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
263
BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs
Normal file
263
BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs
Normal file
@ -0,0 +1,263 @@
|
||||
using BOB.Singleton;
|
||||
using BOB.ViewModels.UserControls;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Annotations;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
using Prism.Commands;
|
||||
using Prism.Events;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class EAEL9080ViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
|
||||
#region 属性
|
||||
private string _Title = "低压直流负载";
|
||||
private string _设备标识字符串;
|
||||
private string _负载模式;
|
||||
private LineSeries _电压_lineSeries = new LineSeries
|
||||
{
|
||||
Title = "电压(V)",
|
||||
StrokeThickness = 2,
|
||||
};
|
||||
private LineSeries _电流_lineSeries = new LineSeries
|
||||
{
|
||||
Title = "电流(A)",
|
||||
StrokeThickness = 2,
|
||||
};
|
||||
private LineSeries _功率_lineSeries = new LineSeries
|
||||
{
|
||||
Title = "功率(W)",
|
||||
StrokeThickness = 2,
|
||||
};
|
||||
private NumericalDisplayViewModel _电压MV=new();
|
||||
private NumericalDisplayViewModel _电流MV = new();
|
||||
private NumericalDisplayViewModel _功率MV=new();
|
||||
private PlotModel _曲线Model = new();
|
||||
|
||||
public PlotModel 曲线Model
|
||||
{
|
||||
get { return _曲线Model; }
|
||||
set { SetProperty(ref _曲线Model, value); }
|
||||
}
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
|
||||
public string 设备标识字符串
|
||||
{
|
||||
get { return _设备标识字符串; }
|
||||
set { SetProperty(ref _设备标识字符串, value); }
|
||||
}
|
||||
|
||||
public string 负载模式
|
||||
{
|
||||
get { return _负载模式; }
|
||||
set { SetProperty(ref _负载模式, value); }
|
||||
}
|
||||
|
||||
public LineSeries 电流_lineSeries
|
||||
{
|
||||
get { return _电流_lineSeries; }
|
||||
set { SetProperty(ref _电流_lineSeries, value); }
|
||||
}
|
||||
|
||||
public LineSeries 电压_lineSeries
|
||||
{
|
||||
get { return _电压_lineSeries; }
|
||||
set { SetProperty(ref _电压_lineSeries, value); }
|
||||
}
|
||||
public LineSeries 功率_lineSeries
|
||||
{
|
||||
get { return _功率_lineSeries; }
|
||||
set { SetProperty(ref _功率_lineSeries, value); }
|
||||
}
|
||||
public NumericalDisplayViewModel 电压MV
|
||||
{
|
||||
get { return _电压MV; }
|
||||
set { SetProperty(ref _电压MV, value); }
|
||||
}
|
||||
public NumericalDisplayViewModel 电流MV
|
||||
{
|
||||
get { return _电流MV; }
|
||||
set { SetProperty(ref _电流MV, value); }
|
||||
}
|
||||
public NumericalDisplayViewModel 功率MV
|
||||
{
|
||||
get { return _功率MV; }
|
||||
set { SetProperty(ref _功率MV, value); }
|
||||
}
|
||||
public DateTimeAxis TimeAxis { get; private set; }
|
||||
public LinearAxis ValueAxis { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
public ICommand 连接命令 { get; private set; }
|
||||
public ICommand 断开命令 { get; private set; }
|
||||
public ICommand 设置为远程模式命令 { get; private set; }
|
||||
public ICommand 设置负载工作模式命令 { get; private set; }
|
||||
public ICommand 电源输出开命令 { get; private set; }
|
||||
public ICommand 电源输出关命令 { get; private set; }
|
||||
public ICommand 关闭命令 { get; private set; }
|
||||
public ICommand 查询设备信息命令 { get; private set; }
|
||||
public ICommand ResetViewCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private EAEL9080 device { get; set; }
|
||||
|
||||
public EAEL9080ViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
连接命令 = new AsyncDelegateCommand(OnConnect);
|
||||
断开命令 = new DelegateCommand(OnDisconnect);
|
||||
设置为远程模式命令 = new AsyncDelegateCommand(OnSetRemoteMode);
|
||||
设置负载工作模式命令 = new AsyncDelegateCommand(OnSetLoadMode);
|
||||
电源输出开命令 = new AsyncDelegateCommand(OnPowerOn);
|
||||
电源输出关命令 = new AsyncDelegateCommand(OnPowerOff);
|
||||
关闭命令 = new DelegateCommand(OnOff);
|
||||
查询设备信息命令 = new AsyncDelegateCommand(OnQueryDeviceInfo);
|
||||
ResetViewCommand = new DelegateCommand(ResetView);
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Subscribe(UpdateCurve);
|
||||
InitCurve();
|
||||
}
|
||||
private void ResetView()
|
||||
{
|
||||
曲线Model.ResetAllAxes();
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
private void InitCurve()
|
||||
{
|
||||
TimeAxis = new DateTimeAxis
|
||||
{
|
||||
Position = AxisPosition.Bottom,
|
||||
StringFormat = "HH:mm:ss",
|
||||
IntervalType = DateTimeIntervalType.Seconds,
|
||||
};
|
||||
ValueAxis = new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
};
|
||||
曲线Model.Axes.Add(TimeAxis);
|
||||
曲线Model.Axes.Add(ValueAxis);
|
||||
曲线Model.Series.Add(电压_lineSeries);
|
||||
曲线Model.Series.Add(电流_lineSeries);
|
||||
曲线Model.Series.Add(功率_lineSeries);
|
||||
曲线Model.Legends.Add(new Legend()
|
||||
{
|
||||
LegendPosition = LegendPosition.TopRight,
|
||||
LegendOrientation = LegendOrientation.Vertical,
|
||||
LegendPlacement = LegendPlacement.Inside
|
||||
});
|
||||
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
private void UpdateCurve((string device, Dictionary<string,double> data) tuple)
|
||||
{
|
||||
var (device, data) = tuple;
|
||||
if (device != "EAEL9080") return;
|
||||
电流MV.MonitorValue = data["实时电流"];
|
||||
电压MV.MonitorValue = data["实时电压"];
|
||||
功率MV.MonitorValue = data["实时功率"];
|
||||
|
||||
var now = DateTimeAxis.ToDouble(DateTime.Now);
|
||||
电流_lineSeries.Points.Add(new DataPoint(now, data["实时电流"]));
|
||||
电压_lineSeries.Points.Add(new DataPoint(now, data["实时电压"]));
|
||||
功率_lineSeries.Points.Add(new DataPoint(now, data["实时功率"]));
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
private async Task OnQueryDeviceInfo()
|
||||
{
|
||||
设备标识字符串 = await device.查询设备信息();
|
||||
}
|
||||
|
||||
private void OnOff()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
|
||||
private async Task OnConnect()
|
||||
{
|
||||
await device.ConnectAsync();
|
||||
}
|
||||
|
||||
private async void OnDisconnect()
|
||||
{
|
||||
device.Close();
|
||||
}
|
||||
|
||||
|
||||
private async Task OnSetRemoteMode()
|
||||
{
|
||||
await device.设置远程控制(true);
|
||||
}
|
||||
|
||||
private async Task OnSetLoadMode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnPowerOn()
|
||||
{
|
||||
await device.打开输出();
|
||||
}
|
||||
|
||||
private async Task OnPowerOff()
|
||||
{
|
||||
await device.关闭输出();
|
||||
}
|
||||
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = _devices.DeviceDic["EAEL9080"] as EAEL9080;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
197
BOB/ViewModels/Dialogs/IOBoardViewModel.cs
Normal file
197
BOB/ViewModels/Dialogs/IOBoardViewModel.cs
Normal file
@ -0,0 +1,197 @@
|
||||
using BOB.Singleton;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class IOBoardViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
public enum Address : ushort
|
||||
{
|
||||
ushort0 = 0,
|
||||
ushort1 = 1,
|
||||
ushort2 = 2,
|
||||
ushort3 = 3,
|
||||
ushort4 = 4,
|
||||
ushort5 = 5,
|
||||
ushort6 = 6,
|
||||
ushort7 = 7,
|
||||
ushort8 = 8,
|
||||
ushort9 = 9,
|
||||
ushort10 = 10,
|
||||
ushort11 = 11,
|
||||
ushort12 = 12,
|
||||
ushort13 = 13,
|
||||
ushort14 = 14,
|
||||
ushort15 = 15
|
||||
}
|
||||
#region 属性
|
||||
private string _title = "IO板卡";
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return _title; }
|
||||
set { SetProperty(ref _title, value); }
|
||||
}
|
||||
|
||||
private string _offset="0";
|
||||
public string Offset
|
||||
{
|
||||
get { return _offset; }
|
||||
set { SetProperty(ref _offset, value); }
|
||||
}
|
||||
|
||||
private string _batchWriteStatus;
|
||||
public string BatchWriteStatus
|
||||
{
|
||||
get { return _batchWriteStatus; }
|
||||
set { SetProperty(ref _batchWriteStatus, value); }
|
||||
}
|
||||
private Address _SelectedAddress;
|
||||
public Address SelectedAddress
|
||||
{
|
||||
get { return _SelectedAddress; }
|
||||
set { SetProperty(ref _SelectedAddress, value); }
|
||||
}
|
||||
private List<Address> _AddressList=Enum.GetValues(typeof(Address)).Cast<Address>().ToList();
|
||||
public List<Address> AddressList
|
||||
{
|
||||
get { return _AddressList; }
|
||||
set { SetProperty(ref _AddressList, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand ConnectCommand { get; private set; }
|
||||
public ICommand DisconnectCommand { get; private set; }
|
||||
public ICommand PowerOnCommand { get; private set; }
|
||||
public ICommand PowerOffCommand { get; private set; }
|
||||
public ICommand SetCommand { get; private set; }
|
||||
public ICommand ReadCommand { get; private set; }
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private IOBoard device { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
public IOBoardViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
ConnectCommand = new AsyncDelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
PowerOnCommand = new AsyncDelegateCommand(OnPowerOn);
|
||||
PowerOffCommand = new AsyncDelegateCommand(OnPowerOff);
|
||||
SetCommand = new AsyncDelegateCommand(OnSet);
|
||||
ReadCommand = new AsyncDelegateCommand(OnRead);
|
||||
CloseCommand = new DelegateCommand(OnClose);
|
||||
}
|
||||
|
||||
|
||||
private async Task OnConnect()
|
||||
{
|
||||
await device.ConnectAsync();
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
device.Close();
|
||||
}
|
||||
|
||||
private async Task OnPowerOn()
|
||||
{
|
||||
await device.写输出开关(1, (ushort)SelectedAddress, true);
|
||||
}
|
||||
|
||||
private async Task OnPowerOff()
|
||||
{
|
||||
await device.写输出开关(1, (ushort)SelectedAddress, false);
|
||||
}
|
||||
|
||||
private async Task OnSet()
|
||||
{
|
||||
bool[] statusArray = JsonConvert.DeserializeObject<bool[]>(BatchWriteStatus);
|
||||
|
||||
if (ushort.TryParse(Offset, out ushort offset))
|
||||
{
|
||||
if (statusArray==null||statusArray.Length+offset>16||statusArray.Length<=0||offset<0)
|
||||
{
|
||||
LoggerHelper.Error("BatchWriteStatus 数组内容不符合预期");
|
||||
return;
|
||||
}
|
||||
await device.批量写输出开关(1, offset, System.Text.Json.JsonSerializer.Deserialize<bool[]>(BatchWriteStatus));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.Error("BatchWriteStatus 数组内容不符合预期");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnRead()
|
||||
{
|
||||
if (ushort.TryParse(Offset, out ushort offset))
|
||||
{
|
||||
BatchWriteStatus = System.Text.Json.JsonSerializer.Serialize( await device.批量读输出开关(1, offset, 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.Error("Offset 解析失败,确保其是有效的数字!");
|
||||
}
|
||||
}
|
||||
private void OnClose()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = _devices.DeviceDic["IOBoard"] as IOBoard;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
331
BOB/ViewModels/Dialogs/IT6724CViewModel.cs
Normal file
331
BOB/ViewModels/Dialogs/IT6724CViewModel.cs
Normal file
@ -0,0 +1,331 @@
|
||||
using BOB.Singleton;
|
||||
using BOB.ViewModels.UserControls;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Annotations;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class IT6724CViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
#region 属性
|
||||
private string _title = "低压直流电源";
|
||||
public string Title
|
||||
{
|
||||
get => _title;
|
||||
set => SetProperty(ref _title, value);
|
||||
}
|
||||
private string _设备标识字符串;
|
||||
public string 设备标识字符串
|
||||
{
|
||||
get => _设备标识字符串;
|
||||
set => SetProperty(ref _设备标识字符串, value);
|
||||
}
|
||||
private string _输出电压;
|
||||
public string 输出电压
|
||||
{
|
||||
get => _输出电压;
|
||||
set => SetProperty(ref _输出电压, value);
|
||||
}
|
||||
|
||||
private string _输出电流;
|
||||
public string 输出电流
|
||||
{
|
||||
get => _输出电流;
|
||||
set => SetProperty(ref _输出电流, value);
|
||||
}
|
||||
|
||||
private string _OCP电流;
|
||||
public string OCP电流
|
||||
{
|
||||
get => _OCP电流;
|
||||
set => SetProperty(ref _OCP电流, value);
|
||||
}
|
||||
|
||||
private string _OVP电压;
|
||||
public string OVP电压
|
||||
{
|
||||
get => _OVP电压;
|
||||
set => SetProperty(ref _OVP电压, value);
|
||||
}
|
||||
|
||||
private LineSeries _电压_lineSeries = new LineSeries { Title = "电压(V)", StrokeThickness = 2 };
|
||||
public LineSeries 电压_lineSeries
|
||||
{
|
||||
get => _电压_lineSeries;
|
||||
set => SetProperty(ref _电压_lineSeries, value);
|
||||
}
|
||||
|
||||
private LineSeries _电流_lineSeries = new LineSeries { Title = "电流(A)", StrokeThickness = 2 };
|
||||
public LineSeries 电流_lineSeries
|
||||
{
|
||||
get => _电流_lineSeries;
|
||||
set => SetProperty(ref _电流_lineSeries, value);
|
||||
}
|
||||
|
||||
private LineSeries _功率_lineSeries = new LineSeries { Title = "功率(W)", StrokeThickness = 2 };
|
||||
public LineSeries 功率_lineSeries
|
||||
{
|
||||
get => _功率_lineSeries;
|
||||
set => SetProperty(ref _功率_lineSeries, value);
|
||||
}
|
||||
private NumericalDisplayViewModel _电压MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 电压MV
|
||||
{
|
||||
get => _电压MV;
|
||||
set => SetProperty(ref _电压MV, value);
|
||||
}
|
||||
|
||||
private NumericalDisplayViewModel _电流MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 电流MV
|
||||
{
|
||||
get => _电流MV;
|
||||
set => SetProperty(ref _电流MV, value);
|
||||
}
|
||||
|
||||
private NumericalDisplayViewModel _功率MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 功率MV
|
||||
{
|
||||
get => _功率MV;
|
||||
set => SetProperty(ref _功率MV, value);
|
||||
}
|
||||
private PlotModel _曲线Model = new PlotModel();
|
||||
public PlotModel 曲线Model
|
||||
{
|
||||
get => _曲线Model;
|
||||
set => SetProperty(ref _曲线Model, value);
|
||||
}
|
||||
public DateTimeAxis TimeAxis { get; private set; }
|
||||
public LinearAxis ValueAxis { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
public ICommand ConnectCommand { get; private set; }
|
||||
public ICommand DisconnectCommand { get; private set; }
|
||||
public ICommand PowerOnCommand { get; private set; }
|
||||
public ICommand PowerOffCommand { get; private set; }
|
||||
public ICommand SetOutputVoltageCommand { get; private set; }
|
||||
public ICommand SetOutputCurrentCommand { get; private set; }
|
||||
public ICommand SetRemoteModeCommand { get; private set; }
|
||||
public ICommand QueryDeviceInfoCommand { get; private set; }
|
||||
public ICommand EnableOCPCommand { get; private set; }
|
||||
public ICommand DisableOCPCommand { get; private set; }
|
||||
public ICommand ClearOCPAlarmCommand { get; private set; }
|
||||
public ICommand SetOCPCommand { get; private set; }
|
||||
public ICommand EnableOVPCommand { get; private set; }
|
||||
public ICommand DisableOVPCommand { get; private set; }
|
||||
public ICommand ClearOVPAlarmCommand { get; private set; }
|
||||
public ICommand SetOVPCommand { get; private set; }
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
public ICommand ResetViewCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private IT6724C device { get; set; }
|
||||
public IT6724CViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
ConnectCommand = new AsyncDelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
PowerOnCommand = new AsyncDelegateCommand(OnPowerOn);
|
||||
PowerOffCommand = new AsyncDelegateCommand(OnPowerOff);
|
||||
SetOutputVoltageCommand = new AsyncDelegateCommand(OnSetOutputVoltage);
|
||||
SetOutputCurrentCommand = new AsyncDelegateCommand(OnSetOutputCurrent);
|
||||
SetRemoteModeCommand = new AsyncDelegateCommand(OnSetRemoteMode);
|
||||
QueryDeviceInfoCommand = new AsyncDelegateCommand(OnQueryDeviceInfo);
|
||||
EnableOCPCommand = new AsyncDelegateCommand(OnEnableOCP);
|
||||
DisableOCPCommand = new AsyncDelegateCommand(OnDisableOCP);
|
||||
ClearOCPAlarmCommand = new AsyncDelegateCommand(OnClearOCPAlarm);
|
||||
SetOCPCommand = new AsyncDelegateCommand(OnSetOCP);
|
||||
EnableOVPCommand = new AsyncDelegateCommand(OnEnableOVP);
|
||||
DisableOVPCommand = new AsyncDelegateCommand(OnDisableOVP);
|
||||
ClearOVPAlarmCommand = new AsyncDelegateCommand(OnClearOVPAlarm);
|
||||
SetOVPCommand = new AsyncDelegateCommand(OnSetOVP);
|
||||
CloseCommand = new DelegateCommand(OnClose);
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
ResetViewCommand = new DelegateCommand(ResetView);
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Subscribe(UpdateCurve);
|
||||
InitCurve();
|
||||
}
|
||||
private void ResetView()
|
||||
{
|
||||
曲线Model.ResetAllAxes();
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
private void InitCurve()
|
||||
{
|
||||
TimeAxis = new DateTimeAxis
|
||||
{
|
||||
Position = AxisPosition.Bottom,
|
||||
StringFormat = "HH:mm:ss",
|
||||
IntervalType = DateTimeIntervalType.Seconds,
|
||||
};
|
||||
ValueAxis = new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
};
|
||||
曲线Model.Axes.Add(TimeAxis);
|
||||
曲线Model.Axes.Add(ValueAxis);
|
||||
曲线Model.Series.Add(电压_lineSeries);
|
||||
曲线Model.Series.Add(电流_lineSeries);
|
||||
曲线Model.Series.Add(功率_lineSeries);
|
||||
曲线Model.Legends.Add(new Legend()
|
||||
{
|
||||
LegendPosition = LegendPosition.TopRight,
|
||||
LegendOrientation = LegendOrientation.Vertical,
|
||||
LegendPlacement = LegendPlacement.Inside
|
||||
});
|
||||
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
private void UpdateCurve((string device, Dictionary<string, double> data) tuple)
|
||||
{
|
||||
var (device, data) = tuple;
|
||||
if (device != "IT6724C") return;
|
||||
电流MV.MonitorValue = data["实时电流"];
|
||||
电压MV.MonitorValue = data["实时电压"];
|
||||
功率MV.MonitorValue = data["实时功率"];
|
||||
|
||||
var now = DateTimeAxis.ToDouble(DateTime.Now);
|
||||
电流_lineSeries.Points.Add(new DataPoint(now, data["实时电流"]));
|
||||
电压_lineSeries.Points.Add(new DataPoint(now, data["实时电压"]));
|
||||
功率_lineSeries.Points.Add(new DataPoint(now, data["实时功率"]));
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
#region 命令处理方法
|
||||
private void OnClose()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
private async Task OnConnect()
|
||||
{
|
||||
await device.ConnectAsync();
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
device.Close();
|
||||
}
|
||||
|
||||
private async Task OnPowerOn()
|
||||
{
|
||||
await device.设置电源输出(true);
|
||||
}
|
||||
|
||||
private async Task OnPowerOff()
|
||||
{
|
||||
await device.设置电源输出(false);
|
||||
}
|
||||
|
||||
private async Task OnSetOutputVoltage()
|
||||
{
|
||||
await device.设置电压(double.Parse(输出电压));
|
||||
}
|
||||
|
||||
private async Task OnSetOutputCurrent()
|
||||
{
|
||||
await device.设置电流(double.Parse(输出电流));
|
||||
}
|
||||
|
||||
private async Task OnSetRemoteMode()
|
||||
{
|
||||
await device.设置为远程模式();
|
||||
}
|
||||
|
||||
private async Task OnQueryDeviceInfo()
|
||||
{
|
||||
设备标识字符串=await device.查询设备信息();
|
||||
}
|
||||
|
||||
private async Task OnEnableOCP()
|
||||
{
|
||||
await device.设置OCP开关(true);
|
||||
}
|
||||
|
||||
private async Task OnDisableOCP()
|
||||
{
|
||||
await device.设置OCP开关(false);
|
||||
}
|
||||
|
||||
private async Task OnClearOCPAlarm()
|
||||
{
|
||||
await device.清除电流保护();
|
||||
}
|
||||
|
||||
private async Task OnSetOCP()
|
||||
{
|
||||
await device.设置电流保护OCP电流(double.Parse(OCP电流));
|
||||
}
|
||||
|
||||
private async Task OnEnableOVP()
|
||||
{
|
||||
await device.设置OVP开关(true);
|
||||
}
|
||||
|
||||
private async Task OnDisableOVP()
|
||||
{
|
||||
await device.设置OVP开关(false);
|
||||
}
|
||||
|
||||
private async Task OnClearOVPAlarm()
|
||||
{
|
||||
await device.清除电压保护();
|
||||
}
|
||||
|
||||
private async Task OnSetOVP()
|
||||
{
|
||||
await device.设置电压保护OVP电压(double.Parse(OVP电压));
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = _devices.DeviceDic["IT6724C"] as IT6724C;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
57
BOB/ViewModels/Dialogs/LQ7500-DViewModel.cs
Normal file
57
BOB/ViewModels/Dialogs/LQ7500-DViewModel.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using BOB.Singleton;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class LQ7500_DViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
|
||||
#region 属性
|
||||
private string _Title = "水冷机";
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#region 命令
|
||||
|
||||
|
||||
#endregion
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
public LQ7500_DViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
}
|
||||
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
298
BOB/ViewModels/Dialogs/PSB11000ViewModel.cs
Normal file
298
BOB/ViewModels/Dialogs/PSB11000ViewModel.cs
Normal file
@ -0,0 +1,298 @@
|
||||
using BOB.Singleton;
|
||||
using BOB.ViewModels.UserControls;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class PSB11000ViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
|
||||
#region 属性
|
||||
private string _Title = "反灌高压直流双向电源";
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
|
||||
private string _设备标识字符串;
|
||||
public string 设备标识字符串
|
||||
{
|
||||
get { return _设备标识字符串; }
|
||||
set { SetProperty(ref _设备标识字符串, value); }
|
||||
}
|
||||
|
||||
private string _输出电压;
|
||||
public string 输出电压
|
||||
{
|
||||
get { return _输出电压; }
|
||||
set { SetProperty(ref _输出电压, value); }
|
||||
}
|
||||
|
||||
private string _输出电流;
|
||||
public string 输出电流
|
||||
{
|
||||
get { return _输出电流; }
|
||||
set { SetProperty(ref _输出电流, value); }
|
||||
}
|
||||
|
||||
private string _OCP电流;
|
||||
public string OCP电流
|
||||
{
|
||||
get { return _OCP电流; }
|
||||
set { SetProperty(ref _OCP电流, value); }
|
||||
}
|
||||
private LineSeries _电压_lineSeries = new LineSeries { Title = "电压(V)", StrokeThickness = 2 };
|
||||
public LineSeries 电压_lineSeries
|
||||
{
|
||||
get => _电压_lineSeries;
|
||||
set => SetProperty(ref _电压_lineSeries, value);
|
||||
}
|
||||
|
||||
private LineSeries _电流_lineSeries = new LineSeries { Title = "电流(A)", StrokeThickness = 2 };
|
||||
public LineSeries 电流_lineSeries
|
||||
{
|
||||
get => _电流_lineSeries;
|
||||
set => SetProperty(ref _电流_lineSeries, value);
|
||||
}
|
||||
|
||||
private LineSeries _功率_lineSeries = new LineSeries { Title = "功率(W)", StrokeThickness = 2 };
|
||||
public LineSeries 功率_lineSeries
|
||||
{
|
||||
get => _功率_lineSeries;
|
||||
set => SetProperty(ref _功率_lineSeries, value);
|
||||
}
|
||||
private NumericalDisplayViewModel _电压MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 电压MV
|
||||
{
|
||||
get => _电压MV;
|
||||
set => SetProperty(ref _电压MV, value);
|
||||
}
|
||||
|
||||
private NumericalDisplayViewModel _电流MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 电流MV
|
||||
{
|
||||
get => _电流MV;
|
||||
set => SetProperty(ref _电流MV, value);
|
||||
}
|
||||
|
||||
private NumericalDisplayViewModel _功率MV = new NumericalDisplayViewModel();
|
||||
public NumericalDisplayViewModel 功率MV
|
||||
{
|
||||
get => _功率MV;
|
||||
set => SetProperty(ref _功率MV, value);
|
||||
}
|
||||
private PlotModel _曲线Model = new PlotModel();
|
||||
public PlotModel 曲线Model
|
||||
{
|
||||
get => _曲线Model;
|
||||
set => SetProperty(ref _曲线Model, value);
|
||||
}
|
||||
public DateTimeAxis TimeAxis { get; private set; }
|
||||
public LinearAxis ValueAxis { get; private set; }
|
||||
|
||||
#endregion
|
||||
#region 命令
|
||||
|
||||
public ICommand ConnectCommand { get; private set; }
|
||||
public ICommand DisconnectCommand { get; private set; }
|
||||
public ICommand PowerOnCommand { get; private set; }
|
||||
public ICommand PowerOffCommand { get; private set; }
|
||||
public ICommand SetRemoteModeCommand { get; private set; }
|
||||
public ICommand QueryDeviceInfoCommand { get; private set; }
|
||||
public ICommand SwitchWorkingModeCommand { get; private set; }
|
||||
public ICommand SwitchDCSourceModeCommand { get; private set; }
|
||||
public ICommand SwitchLoadModeCommand { get; private set; }
|
||||
public ICommand SetCCVoltageCommand { get; private set; }
|
||||
public ICommand SetCCCurrentCommand { get; private set; }
|
||||
public ICommand SetOCPCurrentCommand { get; private set; }
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
public ICommand ResetViewCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private PSB11000 device;
|
||||
public PSB11000ViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
ConnectCommand = new AsyncDelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
PowerOnCommand = new AsyncDelegateCommand(OnPowerOn);
|
||||
PowerOffCommand = new AsyncDelegateCommand(OnPowerOff);
|
||||
SetRemoteModeCommand = new AsyncDelegateCommand(OnSetRemoteMode);
|
||||
QueryDeviceInfoCommand = new AsyncDelegateCommand(OnQueryDeviceInfo);
|
||||
SwitchWorkingModeCommand = new AsyncDelegateCommand(OnSwitchWorkingMode);
|
||||
SwitchDCSourceModeCommand = new AsyncDelegateCommand(OnSwitchDCSourceMode);
|
||||
SwitchLoadModeCommand = new AsyncDelegateCommand(OnSwitchLoadMode);
|
||||
SetCCVoltageCommand = new AsyncDelegateCommand(OnSetCCVoltage);
|
||||
SetCCCurrentCommand = new AsyncDelegateCommand(OnSetCCCurrent);
|
||||
SetOCPCurrentCommand = new AsyncDelegateCommand(OnSetOCPCurrent);
|
||||
CloseCommand = new DelegateCommand(OnClose);
|
||||
ResetViewCommand = new DelegateCommand(ResetView);
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Subscribe(UpdateCurve);
|
||||
InitCurve();
|
||||
}
|
||||
private void ResetView()
|
||||
{
|
||||
曲线Model.ResetAllAxes();
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
private void InitCurve()
|
||||
{
|
||||
TimeAxis = new DateTimeAxis
|
||||
{
|
||||
Position = AxisPosition.Bottom,
|
||||
StringFormat = "HH:mm:ss",
|
||||
IntervalType = DateTimeIntervalType.Seconds,
|
||||
};
|
||||
ValueAxis = new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
};
|
||||
曲线Model.Axes.Add(TimeAxis);
|
||||
曲线Model.Axes.Add(ValueAxis);
|
||||
曲线Model.Series.Add(电压_lineSeries);
|
||||
曲线Model.Series.Add(电流_lineSeries);
|
||||
曲线Model.Series.Add(功率_lineSeries);
|
||||
曲线Model.Legends.Add(new Legend()
|
||||
{
|
||||
LegendPosition = LegendPosition.TopRight,
|
||||
LegendOrientation = LegendOrientation.Vertical,
|
||||
LegendPlacement = LegendPlacement.Inside
|
||||
});
|
||||
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
private void UpdateCurve((string device, Dictionary<string, double> data) tuple)
|
||||
{
|
||||
var (device, data) = tuple;
|
||||
if (device != "IT6724C") return;
|
||||
电流MV.MonitorValue = data["实时电流"];
|
||||
电压MV.MonitorValue = data["实时电压"];
|
||||
功率MV.MonitorValue = data["实时功率"];
|
||||
|
||||
var now = DateTimeAxis.ToDouble(DateTime.Now);
|
||||
电流_lineSeries.Points.Add(new DataPoint(now, data["实时电流"]));
|
||||
电压_lineSeries.Points.Add(new DataPoint(now, data["实时电压"]));
|
||||
功率_lineSeries.Points.Add(new DataPoint(now, data["实时功率"]));
|
||||
曲线Model.InvalidatePlot(true);
|
||||
}
|
||||
#region Command Handlers
|
||||
private void OnClose()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
private async Task OnConnect()
|
||||
{
|
||||
await device.ConnectAsync();
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
device.Close();
|
||||
}
|
||||
|
||||
private async Task OnPowerOn()
|
||||
{
|
||||
await device.打开输出();
|
||||
}
|
||||
|
||||
private async Task OnPowerOff()
|
||||
{
|
||||
await device.关闭输出();
|
||||
}
|
||||
|
||||
private async Task OnSetRemoteMode()
|
||||
{
|
||||
await device.设置远程控制(true);
|
||||
}
|
||||
|
||||
private async Task OnQueryDeviceInfo()
|
||||
{
|
||||
设备标识字符串=await device.查询设备信息();
|
||||
}
|
||||
|
||||
private async Task OnSwitchWorkingMode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSwitchDCSourceMode()
|
||||
{
|
||||
// Logic for switching DC source mode
|
||||
}
|
||||
|
||||
private async Task OnSwitchLoadMode()
|
||||
{
|
||||
// Logic for switching load mode
|
||||
}
|
||||
|
||||
private async Task OnSetCCVoltage()
|
||||
{
|
||||
// Logic for setting CC voltage
|
||||
}
|
||||
|
||||
private async Task OnSetCCCurrent()
|
||||
{
|
||||
// Logic for setting CC current
|
||||
}
|
||||
|
||||
private async Task OnSetOCPCurrent()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = _devices.DeviceDic["PSB11000"] as PSB11000;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
227
BOB/ViewModels/Dialogs/SQ0030G1DViewModel.cs
Normal file
227
BOB/ViewModels/Dialogs/SQ0030G1DViewModel.cs
Normal file
@ -0,0 +1,227 @@
|
||||
using BOB.Singleton;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class SQ0030G1DViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
|
||||
#region 属性
|
||||
|
||||
private string _Title = "交流电源";
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
|
||||
private string _UPhaseVoltage;
|
||||
public string UPhaseVoltage
|
||||
{
|
||||
get { return _UPhaseVoltage; }
|
||||
set { SetProperty(ref _UPhaseVoltage, value); }
|
||||
}
|
||||
|
||||
private string _VPhaseVoltage;
|
||||
public string VPhaseVoltage
|
||||
{
|
||||
get { return _VPhaseVoltage; }
|
||||
set { SetProperty(ref _VPhaseVoltage, value); }
|
||||
}
|
||||
|
||||
private string _WPhaseVoltage;
|
||||
public string WPhaseVoltage
|
||||
{
|
||||
get { return _WPhaseVoltage; }
|
||||
set { SetProperty(ref _WPhaseVoltage, value); }
|
||||
}
|
||||
|
||||
private string _CommonOutputVoltage;
|
||||
public string CommonOutputVoltage
|
||||
{
|
||||
get { return _CommonOutputVoltage; }
|
||||
set { SetProperty(ref _CommonOutputVoltage, value); }
|
||||
}
|
||||
|
||||
private string _CommonOutputFrequency;
|
||||
public string CommonOutputFrequency
|
||||
{
|
||||
get { return _CommonOutputFrequency; }
|
||||
set { SetProperty(ref _CommonOutputFrequency, value); }
|
||||
}
|
||||
|
||||
private string _StepOutputVoltage;
|
||||
public string StepOutputVoltage
|
||||
{
|
||||
get { return _StepOutputVoltage; }
|
||||
set { SetProperty(ref _StepOutputVoltage, value); }
|
||||
}
|
||||
|
||||
private string _StepOutputFrequency;
|
||||
public string StepOutputFrequency
|
||||
{
|
||||
get { return _StepOutputFrequency; }
|
||||
set { SetProperty(ref _StepOutputFrequency, value); }
|
||||
}
|
||||
|
||||
private string _StepOutputVoltageGroup;
|
||||
public string StepOutputVoltageGroup
|
||||
{
|
||||
get { return _StepOutputVoltageGroup; }
|
||||
set { SetProperty(ref _StepOutputVoltageGroup, value); }
|
||||
}
|
||||
|
||||
private string _StepOutputFrequencyGroup;
|
||||
public string StepOutputFrequencyGroup
|
||||
{
|
||||
get { return _StepOutputFrequencyGroup; }
|
||||
set { SetProperty(ref _StepOutputFrequencyGroup, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand ConnectCommand { get; private set; }
|
||||
public ICommand DisconnectCommand { get; private set; }
|
||||
public ICommand SetVoltageLevelLowCommand { get; private set; }
|
||||
public ICommand SetVoltageLevelHighCommand { get; private set; }
|
||||
public ICommand SetThreePhaseVoltageCommand { get; private set; }
|
||||
public ICommand SetCommonOutputVoltageCommand { get; private set; }
|
||||
public ICommand SetCommonOutputFrequencyCommand { get; private set; }
|
||||
public ICommand SetStepOutputVoltageCommand { get; private set; }
|
||||
public ICommand SetStepOutputFrequencyCommand { get; private set; }
|
||||
public ICommand OpenPowerSupplyCommand { get; private set; }
|
||||
public ICommand ClosePowerSupplyCommand { get; private set; }
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private SQ0030G1D device { get; set; }
|
||||
public SQ0030G1DViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
ConnectCommand = new AsyncDelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
CloseCommand = new DelegateCommand(OnClose);
|
||||
SetVoltageLevelLowCommand = new AsyncDelegateCommand(OnSetVoltageLevelLow);
|
||||
SetVoltageLevelHighCommand = new AsyncDelegateCommand(OnSetVoltageLevelHigh);
|
||||
SetThreePhaseVoltageCommand = new AsyncDelegateCommand(OnSetThreePhaseVoltage);
|
||||
SetCommonOutputVoltageCommand = new AsyncDelegateCommand(OnSetCommonOutputVoltage);
|
||||
SetCommonOutputFrequencyCommand = new AsyncDelegateCommand(OnSetCommonOutputFrequency);
|
||||
SetStepOutputVoltageCommand = new AsyncDelegateCommand(OnSetStepOutputVoltage);
|
||||
SetStepOutputFrequencyCommand = new AsyncDelegateCommand(OnSetStepOutputFrequency);
|
||||
ClosePowerSupplyCommand = new AsyncDelegateCommand(ClosePowerSupply);
|
||||
OpenPowerSupplyCommand = new AsyncDelegateCommand(OpenPowerSupply);
|
||||
}
|
||||
|
||||
#region Command Handlers
|
||||
private void OnClose()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
private async Task OnConnect()
|
||||
{
|
||||
await device.ConnectAsync();
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
device.Close();
|
||||
}
|
||||
private async Task OpenPowerSupply()
|
||||
{
|
||||
await device.启动电源();
|
||||
}
|
||||
|
||||
private async Task ClosePowerSupply()
|
||||
{
|
||||
await device.关闭电源();
|
||||
}
|
||||
private async Task OnSetVoltageLevelLow()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSetVoltageLevelHigh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSetThreePhaseVoltage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSetCommonOutputVoltage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSetCommonOutputFrequency()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSetStepOutputVoltage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnSetStepOutputFrequency()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = _devices.DeviceDic["SQ0030G1D"] as SQ0030G1D;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
149
BOB/ViewModels/Dialogs/WS-68030-380TViewModel.cs
Normal file
149
BOB/ViewModels/Dialogs/WS-68030-380TViewModel.cs
Normal file
@ -0,0 +1,149 @@
|
||||
using BOB.Singleton;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using NetTaste;
|
||||
using Prism.Commands;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class WS_68030_380TViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
#region 属性
|
||||
|
||||
private string _title = "交流负载";
|
||||
public string Title
|
||||
{
|
||||
get { return _title; }
|
||||
set { SetProperty(ref _title, value); }
|
||||
}
|
||||
|
||||
private string _currentPowerDisplay;
|
||||
public string CurrentPowerDisplay
|
||||
{
|
||||
get { return _currentPowerDisplay; }
|
||||
set { SetProperty(ref _currentPowerDisplay, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand ConnectCommand { get; private set; }
|
||||
public ICommand DisconnectCommand { get; private set; }
|
||||
public ICommand LoadCommand { get; private set; }
|
||||
public ICommand UnloadCommand { get; private set; }
|
||||
public ICommand ReadPowerCommand { get; private set; }
|
||||
public ICommand SetPowerCommand { get; private set; }
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件聚合器和设备操作
|
||||
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private WS_68030_380T device { get; set; }
|
||||
|
||||
public WS_68030_380TViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
|
||||
// 初始化命令
|
||||
ConnectCommand = new AsyncDelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
LoadCommand = new AsyncDelegateCommand(OnLoad);
|
||||
UnloadCommand = new AsyncDelegateCommand(OnUnload);
|
||||
ReadPowerCommand = new AsyncDelegateCommand(OnReadPower);
|
||||
SetPowerCommand = new AsyncDelegateCommand(OnSetPower);
|
||||
CloseCommand = new DelegateCommand(OnClose);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令处理方法
|
||||
|
||||
private async Task OnConnect()
|
||||
{
|
||||
await device.ConnectAsync();
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
device.Close();
|
||||
}
|
||||
|
||||
private async Task OnLoad()
|
||||
{
|
||||
await device.加载();
|
||||
}
|
||||
|
||||
private async Task OnUnload()
|
||||
{
|
||||
await device.卸载();
|
||||
}
|
||||
|
||||
private async Task OnReadPower()
|
||||
{
|
||||
var result = await device.读取功率_KW();
|
||||
}
|
||||
|
||||
private async Task OnSetPower()
|
||||
{
|
||||
if (float.TryParse(CurrentPowerDisplay, out float a))
|
||||
{
|
||||
await device.设置功率_KW(a);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dialog 规范
|
||||
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
var a = _devices.DeviceDic["WS_68030_380T"] as WS_68030_380T;
|
||||
if (a != null)
|
||||
{
|
||||
device = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面");
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面");
|
||||
}
|
||||
|
||||
}
|
||||
private void OnClose()
|
||||
{
|
||||
RequestClose.Invoke();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
57
BOB/ViewModels/Dialogs/ZXKSViewModel.cs
Normal file
57
BOB/ViewModels/Dialogs/ZXKSViewModel.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using BOB.Singleton;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BOB.ViewModels.Dialogs
|
||||
{
|
||||
public class ZXKSViewModel : BindableBase, IDialogAware
|
||||
{
|
||||
|
||||
#region 属性
|
||||
private string _Title = "环境箱";
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return _Title; }
|
||||
set { SetProperty(ref _Title, value); }
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#region 命令
|
||||
|
||||
|
||||
#endregion
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
public ZXKSViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>();
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||
}
|
||||
|
||||
#region dialog规范
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
using Logger;
|
||||
using BOB.Singleton;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using Prism.Mvvm;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
@ -18,8 +21,10 @@ namespace BOB.ViewModels
|
||||
set => SetProperty(ref _logs, value);
|
||||
}
|
||||
public ICommand ClearLogCommand { get; set; }
|
||||
public LogAreaViewModel()
|
||||
public Devices devices { get; set; }
|
||||
public LogAreaViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
devices=containerProvider.Resolve<Devices>();
|
||||
ClearLogCommand = new DelegateCommand(ClearLog);
|
||||
LoggerHelper.Progress = new System.Progress<(string message, string color,int depth)>(
|
||||
log =>
|
||||
@ -29,6 +34,8 @@ namespace BOB.ViewModels
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ClearLog()
|
||||
{
|
||||
Logs.Clear();
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
using Common.PubEvent;
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using Common.PubEvents;
|
||||
using Logger;
|
||||
using NLog;
|
||||
using Prism.Dialogs;
|
||||
using Prism.Events;
|
||||
@ -13,46 +15,61 @@ using System.Windows.Input;
|
||||
|
||||
namespace BOB.ViewModels
|
||||
{
|
||||
public class MainViewModel : BindableBase,INavigationAware,IDialogAware
|
||||
public class MainViewModel : BindableBase,INavigationAware
|
||||
{
|
||||
#region 属性
|
||||
|
||||
|
||||
#endregion
|
||||
#region 命令
|
||||
public ICommand testcommand { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
private IEventAggregator _eventAggregator;
|
||||
private IDialogService _dialogService;
|
||||
public MainViewModel(IEventAggregator eventAggregator, IDialogService dialogService)
|
||||
private Devices _devices{ get; set; }
|
||||
public MainViewModel(IEventAggregator eventAggregator, IDialogService dialogService,IContainerProvider containerProvider)
|
||||
{
|
||||
_dialogService = dialogService;
|
||||
_eventAggregator = eventAggregator;
|
||||
testcommand = new DelegateCommand(test);
|
||||
_devices=containerProvider.Resolve<Devices>();
|
||||
|
||||
}
|
||||
private void test()
|
||||
{
|
||||
//_eventAggregator.GetEvent<OverlayEvent>().Publish(true);
|
||||
//var parameters = new DialogParameters
|
||||
//{
|
||||
// { "Title", "提示" },
|
||||
// { "Message", "操作成功!" },
|
||||
// { "Icon", "info" },
|
||||
// { "ShowOk", true }
|
||||
//};
|
||||
//_dialogService.ShowDialog("MessageBox",parameters);
|
||||
}
|
||||
|
||||
|
||||
private async Task InitializeDevicesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_devices.Init(SystemConfig.Instance.DeviceList);
|
||||
await _devices.ConnectAllDevicesAsync();
|
||||
_devices.InitCan();
|
||||
_devices.StartPollingCollectionAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"设备连接异常: {ex.Message}", ex.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_eventAggregator.GetEvent<OverlayEvent>().Publish(false);
|
||||
}
|
||||
}
|
||||
#region 导航
|
||||
private bool _isInitialized = false;
|
||||
|
||||
public void OnNavigatedTo(NavigationContext navigationContext)
|
||||
{
|
||||
|
||||
if (!_isInitialized)
|
||||
{
|
||||
_eventAggregator.GetEvent<OverlayEvent>().Publish(true);
|
||||
_ = InitializeDevicesAsync();
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsNavigationTarget(NavigationContext navigationContext)
|
||||
{
|
||||
return true;
|
||||
@ -64,21 +81,6 @@ namespace BOB.ViewModels
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 弹窗
|
||||
public bool CanCloseDialog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDialogClosed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
366
BOB/ViewModels/MonitorViewModel.cs
Normal file
366
BOB/ViewModels/MonitorViewModel.cs
Normal file
@ -0,0 +1,366 @@
|
||||
using BOB.Services;
|
||||
using BOB.Singleton;
|
||||
using Common.PubEvent;
|
||||
using Common.PubEvents;
|
||||
using Logger;
|
||||
using Microsoft.Win32;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
using Prism.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace BOB.ViewModels
|
||||
{
|
||||
public class MonitorViewModel : BindableBase, INavigationAware
|
||||
{
|
||||
#region 属性
|
||||
private PlotModel _CurveModel=new();
|
||||
|
||||
public PlotModel CurveModel
|
||||
{
|
||||
get => _CurveModel;
|
||||
set => SetProperty(ref _CurveModel, value);
|
||||
}
|
||||
private Dictionary<string, LineSeries> _SeriesDic = new ();
|
||||
|
||||
public Dictionary<string,LineSeries> SeriesDic
|
||||
{
|
||||
get => _SeriesDic;
|
||||
set => SetProperty(ref _SeriesDic, value);
|
||||
}
|
||||
private string _FilePath;
|
||||
|
||||
public string FilePath
|
||||
{
|
||||
get => _FilePath;
|
||||
set => SetProperty(ref _FilePath, value);
|
||||
}
|
||||
private string _SelectCurve;
|
||||
|
||||
public string SelectCurve
|
||||
{
|
||||
get => _SelectCurve;
|
||||
set => SetProperty(ref _SelectCurve, value);
|
||||
}
|
||||
private string _SelectDeleteCurve;
|
||||
|
||||
public string SelectDeleteCurve
|
||||
{
|
||||
get => _SelectDeleteCurve;
|
||||
set => SetProperty(ref _SelectDeleteCurve, value);
|
||||
}
|
||||
private string _SelectedSaveDays;
|
||||
|
||||
public string SelectedSaveDays
|
||||
{
|
||||
get => _SelectedSaveDays;
|
||||
set => SetProperty(ref _SelectedSaveDays, value);
|
||||
}
|
||||
//private ObservableCollection<string> _CurSingleList=new();
|
||||
|
||||
public ObservableCollection<string> CurSingleList
|
||||
{
|
||||
get => SystemConfig.Instance.CurSingleList;
|
||||
set
|
||||
{
|
||||
if (SystemConfig.Instance.CurSingleList != value)
|
||||
{
|
||||
SystemConfig.Instance.CurSingleList = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
private ObservableCollection<string> _DeviceSingleList = new();
|
||||
|
||||
public ObservableCollection<string> DeviceSingleList
|
||||
{
|
||||
get => _DeviceSingleList;
|
||||
set => SetProperty(ref _DeviceSingleList, value);
|
||||
}
|
||||
#endregion
|
||||
#region 命令
|
||||
public ICommand ResetViewCommand { get; set; }
|
||||
public ICommand AddSignalCommand { get; set; }
|
||||
public ICommand RemoveSignalCommand { get; set; }
|
||||
public ICommand ChanegPathCommand { get; set; }
|
||||
public ICommand SaveCommand { get; set; }
|
||||
|
||||
#endregion
|
||||
private IEventAggregator _eventAggregator;
|
||||
private IDialogService _dialogService;
|
||||
private static Random _random = new Random();
|
||||
private DispatcherTimer _refreshTimer;
|
||||
private Devices _devices { get; set; }
|
||||
private readonly IProgress<(string name, double value)> _progress;
|
||||
public MonitorViewModel(IEventAggregator eventAggregator, IDialogService dialogService, IContainerProvider containerProvider )
|
||||
{
|
||||
_dialogService = dialogService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_devices = containerProvider.Resolve<Devices>();
|
||||
ResetViewCommand = new DelegateCommand(ResetView);
|
||||
AddSignalCommand = new DelegateCommand<string>(AddSignal);
|
||||
RemoveSignalCommand = new DelegateCommand(RemoveSignal);
|
||||
ChanegPathCommand = new DelegateCommand(ChanegPath);
|
||||
SaveCommand = new DelegateCommand(Save);
|
||||
_eventAggregator.GetEvent<CurveDataEvent>().Subscribe(OnCurveDataReceived);
|
||||
_progress = new Progress<(string name, double value)>(UpdateCurveOnUI);
|
||||
InitData();
|
||||
}
|
||||
private void UpdateCurveOnUI((string name, double value) update)
|
||||
{
|
||||
var (signalName, value) = update;
|
||||
|
||||
if (!SeriesDic.TryGetValue(signalName, out var line))
|
||||
return;
|
||||
|
||||
line.Points.Add(DateTimeAxis.CreateDataPoint(DateTime.Now, value));
|
||||
}
|
||||
|
||||
private async void OnCurveDataReceived((string device, Dictionary<string, double> data) tuple)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var (device, data) = tuple;
|
||||
foreach (var item in data)
|
||||
{
|
||||
string propname = item.Key;
|
||||
double value = item.Value;
|
||||
string signalName = device + "." + propname;
|
||||
|
||||
if (CurSingleList.Contains(signalName))
|
||||
{
|
||||
// 通过 Progress 安全更新 UI
|
||||
_progress.Report((signalName, value));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void InitData()
|
||||
{
|
||||
SelectedSaveDays=SystemConfig.Instance.SaveDay.ToString();
|
||||
FilePath= SystemConfig.Instance.DBSavePath;
|
||||
foreach (var _PollingRead in _devices.PollingReadDic)
|
||||
{
|
||||
string deviceName = _PollingRead.Key;
|
||||
PollingRead pollingRead = _PollingRead.Value;
|
||||
|
||||
var props = pollingRead.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.PropertyType == typeof(double));
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
DeviceSingleList.Add(deviceName + "." + prop.Name);
|
||||
}
|
||||
}
|
||||
foreach(var curve in CurSingleList)
|
||||
{
|
||||
AddSignal(curve);
|
||||
}
|
||||
InitCurveModel();
|
||||
InitTimer();
|
||||
}
|
||||
private void InitCurveModel()
|
||||
{
|
||||
CurveModel.Axes.Clear();
|
||||
|
||||
var timeAxis = new DateTimeAxis
|
||||
{
|
||||
Position = AxisPosition.Bottom,
|
||||
StringFormat = "HH:mm:ss",
|
||||
Title = "时间",
|
||||
IntervalType = DateTimeIntervalType.Seconds
|
||||
};
|
||||
CurveModel.Axes.Add(timeAxis);
|
||||
|
||||
var valueAxis = new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
Title = "数值"
|
||||
};
|
||||
CurveModel.Axes.Add(valueAxis);
|
||||
}
|
||||
|
||||
private void InitTimer()
|
||||
{
|
||||
_refreshTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
};
|
||||
_refreshTimer.Tick += (s, e) =>
|
||||
{
|
||||
CurveModel.InvalidatePlot(true);
|
||||
};
|
||||
_refreshTimer.Start();
|
||||
}
|
||||
|
||||
|
||||
private OxyColor GetRandomColor()
|
||||
{
|
||||
// 生成随机的红色、绿色、蓝色分量,范围是 0 到 255
|
||||
byte r = (byte)_random.Next(0, 256);
|
||||
byte g = (byte)_random.Next(0, 256);
|
||||
byte b = (byte)_random.Next(0, 256);
|
||||
|
||||
// 返回一个随机的颜色
|
||||
return OxyColor.FromRgb(r, g, b);
|
||||
}
|
||||
|
||||
private void AddSignal(string Curve="")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Curve == null)
|
||||
{
|
||||
if (_SeriesDic.ContainsKey(SelectCurve))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sineSignal = new LineSeries
|
||||
{
|
||||
Title = SelectCurve,
|
||||
MarkerType = MarkerType.Circle,
|
||||
StrokeThickness = 2,
|
||||
Color = GetRandomColor()
|
||||
};
|
||||
CurveModel.Series.Add(sineSignal);
|
||||
CurveModel.Legends.Add(new Legend
|
||||
{
|
||||
LegendPosition = LegendPosition.TopCenter, // 图表顶部中间
|
||||
LegendOrientation = LegendOrientation.Horizontal, // 横向排列
|
||||
LegendPlacement = LegendPlacement.Inside, // 放在图上面
|
||||
LegendBorderThickness = 0, // 去掉边框,可选
|
||||
LegendBackground = OxyColors.WhiteSmoke // 背景色,可选
|
||||
});
|
||||
|
||||
SeriesDic.Add(SelectCurve, sineSignal);
|
||||
CurSingleList.Add(SelectCurve);
|
||||
SystemConfig.Instance.SaveToFile();
|
||||
CurveModel.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var sineSignal = new LineSeries
|
||||
{
|
||||
Title = Curve,
|
||||
MarkerType = MarkerType.Circle,
|
||||
StrokeThickness = 2,
|
||||
Color = GetRandomColor()
|
||||
};
|
||||
CurveModel.Series.Add(sineSignal);
|
||||
CurveModel.Legends.Add(new Legend
|
||||
{
|
||||
LegendPosition = LegendPosition.TopCenter, // 图表顶部中间
|
||||
LegendOrientation = LegendOrientation.Horizontal, // 横向排列
|
||||
LegendPlacement = LegendPlacement.Inside, // 放在图上面
|
||||
LegendBorderThickness = 0, // 去掉边框,可选
|
||||
LegendBackground = OxyColors.WhiteSmoke // 背景色,可选
|
||||
});
|
||||
|
||||
SeriesDic.Add(Curve, sineSignal);
|
||||
CurveModel.InvalidatePlot(true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("添加曲线失败", ex.StackTrace);
|
||||
}
|
||||
}
|
||||
private void RemoveSignal()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_SeriesDic.ContainsKey(SelectDeleteCurve))
|
||||
{
|
||||
var signalToRemove = _SeriesDic[SelectDeleteCurve];
|
||||
_SeriesDic.Remove(SelectDeleteCurve);
|
||||
CurveModel.Series.Remove(signalToRemove);
|
||||
CurSingleList.Remove(SelectDeleteCurve);
|
||||
SystemConfig.Instance.SaveToFile();
|
||||
CurveModel.InvalidatePlot(true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("删除曲线失败",ex.StackTrace);
|
||||
}
|
||||
}
|
||||
private void Save()
|
||||
{
|
||||
SelectedSaveDays = SelectedSaveDays ?? "30";
|
||||
if (int.TryParse(SelectedSaveDays, out int saveDays))
|
||||
{
|
||||
if (saveDays > 0 && saveDays <= 30)
|
||||
{
|
||||
Console.WriteLine($"保存天数: {saveDays}");
|
||||
}
|
||||
else
|
||||
{
|
||||
//_dialogService.ShowDialog("请输入1到30之间的有效天数。", "无效输入");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//_dialogService.ShowDialog("请输入有效的数字。", "无效输入");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ChanegPath()
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog
|
||||
{
|
||||
CheckFileExists = false,
|
||||
CheckPathExists = true,
|
||||
FileName = "Folder",
|
||||
ValidateNames = false,
|
||||
Filter = "All files (*.*)|*.*"
|
||||
};
|
||||
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
{
|
||||
FilePath = System.IO.Path.GetDirectoryName(openFileDialog.FileName);
|
||||
SystemConfig.Instance.DBSavePath = FilePath;
|
||||
SystemConfig.Instance.SaveToFile();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ResetView()
|
||||
{
|
||||
CurveModel.ResetAllAxes();
|
||||
CurveModel.InvalidatePlot(true);
|
||||
}
|
||||
#region 导航
|
||||
public void OnNavigatedTo(NavigationContext navigationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool IsNavigationTarget(NavigationContext navigationContext)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom(NavigationContext navigationContext)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,14 @@
|
||||
using BOB.Models;
|
||||
using BOB.Singleton;
|
||||
using BOB.Views.Dialogs;
|
||||
using Common.PubEvent;
|
||||
using DeviceCommand.Base;
|
||||
using DeviceCommand.Device;
|
||||
using Logger;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Model;
|
||||
using OxyPlot;
|
||||
using Prism.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@ -8,6 +16,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Xml;
|
||||
|
||||
@ -16,6 +25,21 @@ namespace BOB.ViewModels
|
||||
public class ParametersManagerViewModel:BindableBase
|
||||
{
|
||||
#region 属性
|
||||
private ObservableCollection<DeviceConfigModel> _DeviceList;
|
||||
|
||||
public ObservableCollection<DeviceConfigModel> DeviceList
|
||||
{
|
||||
get { return _DeviceList; }
|
||||
set { SetProperty(ref _DeviceList,value); }
|
||||
}
|
||||
private ObservableCollection<DeviceInfoModel> _DeviceInfoModel;
|
||||
|
||||
public ObservableCollection<DeviceInfoModel> DeviceInfoModel
|
||||
{
|
||||
get { return _DeviceInfoModel; }
|
||||
set { SetProperty(ref _DeviceInfoModel, value); }
|
||||
}
|
||||
|
||||
public ProgramModel Program
|
||||
{
|
||||
get => _globalVariables.Program;
|
||||
@ -40,90 +64,149 @@ namespace BOB.ViewModels
|
||||
}
|
||||
}
|
||||
}
|
||||
private DeviceModel _SelectedDevice;
|
||||
public DeviceModel SelectedDevice
|
||||
private DeviceInfoModel _SelectedDevice;
|
||||
public DeviceInfoModel SelectedDevice
|
||||
{
|
||||
get => _SelectedDevice;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _SelectedDevice, value))
|
||||
{
|
||||
_globalVariables.SelectedDevice = value;
|
||||
}
|
||||
}
|
||||
get { return _SelectedDevice; }
|
||||
set { SetProperty(ref _SelectedDevice, value); }
|
||||
}
|
||||
#endregion
|
||||
private GlobalVariables _globalVariables { get; set; }
|
||||
private IDialogService _dialogService { get; set; }
|
||||
private IContainerProvider _containerProvider { get; set; }
|
||||
private Devices _devices { get; set; }
|
||||
private IEventAggregator _eventAggregator { get; set; }
|
||||
public ICommand ParameterAddCommand { get; set; }
|
||||
public ICommand ParameterEditCommand { get; set; }
|
||||
public ICommand ParameterDeleteCommand { get; set; }
|
||||
public ICommand DeviceAddCommand { get; set; }
|
||||
public ICommand DeviceEditCommand { get; set; }
|
||||
public ICommand DeviceDeleteCommand { get; set; }
|
||||
public ICommand ReconnnectCommand { get; set; }
|
||||
public ICommand CloseCommand { get; set; }
|
||||
|
||||
|
||||
|
||||
public ParametersManagerViewModel(GlobalVariables GlobalVariables,IDialogService dialogService,IEventAggregator eventAggregator)
|
||||
public ParametersManagerViewModel(GlobalVariables GlobalVariables,IDialogService dialogService,IEventAggregator eventAggregator,IContainerProvider containerProvider)
|
||||
{
|
||||
_containerProvider= containerProvider;
|
||||
_globalVariables = GlobalVariables;
|
||||
_eventAggregator= eventAggregator;
|
||||
_devices=containerProvider.Resolve<Devices>();
|
||||
_dialogService = dialogService;
|
||||
Program = _globalVariables.Program;
|
||||
ParameterAddCommand = new DelegateCommand(ParameterAdd);
|
||||
ParameterEditCommand = new DelegateCommand(ParameterEdit);
|
||||
ParameterDeleteCommand = new DelegateCommand(ParameterDelete);
|
||||
DeviceAddCommand = new DelegateCommand(DeviceAdd);
|
||||
DeviceEditCommand = new DelegateCommand(DeviceEdit);
|
||||
DeviceDeleteCommand = new DelegateCommand(DeviceDelete);
|
||||
|
||||
|
||||
ReconnnectCommand = new DelegateCommand(Reconnnect);
|
||||
CloseCommand = new DelegateCommand(Close);
|
||||
DeviceList = new ObservableCollection<DeviceConfigModel>(SystemConfig.Instance.DeviceList);
|
||||
InitData();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void InitData()
|
||||
{
|
||||
DeviceInfoModel = new ObservableCollection<DeviceInfoModel>();
|
||||
for (int i = 0; i < DeviceList.Count; i++)
|
||||
{
|
||||
DeviceInfoModel.Add(new DeviceInfoModel
|
||||
{
|
||||
DeviceName = DeviceList[i].DeviceName,
|
||||
Remark = DeviceList[i].Remark,
|
||||
IsConnected = false,
|
||||
IsEnabled= DeviceList[i].IsEnabled,
|
||||
DeviceType= DeviceList[i].DeviceType,
|
||||
CommunicationConfig= DeviceList[i].CommunicationConfig
|
||||
});
|
||||
}
|
||||
|
||||
var progress = new Progress<(int index, bool isConnected)>();
|
||||
progress.ProgressChanged += (s, e) =>
|
||||
{
|
||||
DeviceInfoModel[e.index].IsConnected = e.isConnected;
|
||||
};
|
||||
|
||||
var token = _devices.AppCancellationToken;
|
||||
Task.Run(() => PollingConnection(progress, token));
|
||||
}
|
||||
|
||||
private async Task PollingConnection(IProgress<(int index, bool isConnected)> progress, CancellationToken token)
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
for (int i = 0; i < DeviceList.Count; i++)
|
||||
{
|
||||
bool isConnected = false;
|
||||
|
||||
if (_devices.DeviceDic.TryGetValue(DeviceList[i].Remark, out var device) && device != null)
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case ITcp tcpDevice:
|
||||
isConnected = tcpDevice.TcpClient?.Connected ?? false;
|
||||
break;
|
||||
|
||||
case ISerialPort serialDevice:
|
||||
isConnected = serialDevice.SerialPort?.IsOpen ?? false;
|
||||
break;
|
||||
|
||||
case IModbusDevice modbusDevice:
|
||||
isConnected = (modbusDevice.TcpClient?.Connected ?? false) || (modbusDevice.SerialPort?.IsOpen ?? false);
|
||||
break;
|
||||
default:
|
||||
if (device is Backfeed backfeed)
|
||||
{
|
||||
if (backfeed.CurrentDevice == "E36233A")
|
||||
{
|
||||
var e36233A = backfeed.CurrentInstance as E36233A;
|
||||
if (e36233A != null)
|
||||
{
|
||||
isConnected = e36233A.TcpClient?.Connected ?? false;
|
||||
}
|
||||
}
|
||||
else if (backfeed.CurrentDevice == "IT6724CReverse")
|
||||
{
|
||||
var it6724CReverse = backfeed.CurrentInstance as IT6724CReverse;
|
||||
if (it6724CReverse != null)
|
||||
{
|
||||
isConnected = it6724CReverse.SerialPort?.IsOpen ?? false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
_eventAggregator.GetEvent<ConnectionChangeEvent>().Publish((DeviceList[i].Remark, isConnected));
|
||||
}
|
||||
|
||||
progress.Report((i, isConnected));
|
||||
}
|
||||
|
||||
await Task.Delay(200, token); // 支持取消
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region 委托命令
|
||||
|
||||
private void DeviceDelete()
|
||||
{
|
||||
Program.Devices.Remove(SelectedDevice);
|
||||
}
|
||||
|
||||
|
||||
private void DeviceEdit()
|
||||
{
|
||||
var param = new DialogParameters
|
||||
if(SelectedDevice==null)
|
||||
{
|
||||
{ "Mode", SelectedDevice==null?"ADD":"Edit" }
|
||||
};
|
||||
_dialogService.ShowDialog("DeviceSetting", param, (r) =>
|
||||
return;
|
||||
}
|
||||
var type = SelectedDevice.DeviceType.Split('.').Last();
|
||||
if(type=="E36233A"|| type == "IT6724CReverse")
|
||||
{
|
||||
if (r.Result == ButtonResult.OK)
|
||||
{
|
||||
_eventAggregator.GetEvent<ParamsChangedEvent>().Publish();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void DeviceAdd()
|
||||
{
|
||||
var param = new DialogParameters
|
||||
_dialogService.Show("Backfeed");
|
||||
}
|
||||
else
|
||||
{
|
||||
{ "Mode", "ADD" }
|
||||
};
|
||||
_dialogService.ShowDialog("DeviceSetting", param, (r) =>
|
||||
{
|
||||
if (r.Result == ButtonResult.OK)
|
||||
{
|
||||
_eventAggregator.GetEvent<ParamsChangedEvent>().Publish();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
_dialogService.Show(type);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParameterDelete()
|
||||
@ -170,7 +253,113 @@ namespace BOB.ViewModels
|
||||
|
||||
});
|
||||
}
|
||||
private void Close()
|
||||
{
|
||||
if (SelectedDevice != null)
|
||||
{
|
||||
if (_devices.DeviceDic.TryGetValue(SelectedDevice.Remark, out var device) && device != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case ITcp tcpDevice:
|
||||
tcpDevice.Close();
|
||||
break;
|
||||
|
||||
case ISerialPort serialDevice:
|
||||
serialDevice.Close();
|
||||
break;
|
||||
|
||||
case IModbusDevice modbusDevice:
|
||||
modbusDevice.Close();
|
||||
break;
|
||||
default:
|
||||
if (device is Backfeed backfeed)
|
||||
{
|
||||
if (backfeed.CurrentDevice == "E36233A")
|
||||
{
|
||||
var e36233A = backfeed.CurrentInstance as E36233A;
|
||||
if (e36233A != null)
|
||||
{
|
||||
e36233A.Close();
|
||||
}
|
||||
}
|
||||
else if (backfeed.CurrentDevice == "IT6724CReverse")
|
||||
{
|
||||
var it6724CReverse = backfeed.CurrentInstance as IT6724CReverse;
|
||||
if (it6724CReverse != null)
|
||||
{
|
||||
it6724CReverse.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Reconnnect()
|
||||
{
|
||||
if (SelectedDevice != null)
|
||||
{
|
||||
if (_devices.DeviceDic.TryGetValue(SelectedDevice.Remark, out var device) && device != null)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case ITcp tcpDevice:
|
||||
await tcpDevice.ConnectAsync();
|
||||
|
||||
break;
|
||||
|
||||
case ISerialPort serialDevice:
|
||||
await serialDevice.ConnectAsync();
|
||||
break;
|
||||
|
||||
case IModbusDevice modbusDevice:
|
||||
await modbusDevice.ConnectAsync();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (device is Backfeed backfeed)
|
||||
{
|
||||
if (backfeed.CurrentDevice == "E36233A")
|
||||
{
|
||||
var e36233A = backfeed.CurrentInstance as E36233A;
|
||||
if (e36233A != null)
|
||||
{
|
||||
await e36233A.ConnectAsync();
|
||||
}
|
||||
}
|
||||
else if (backfeed.CurrentDevice == "IT6724CReverse")
|
||||
{
|
||||
var it6724CReverse = backfeed.CurrentInstance as IT6724CReverse;
|
||||
if (it6724CReverse != null)
|
||||
{
|
||||
await it6724CReverse.ConnectAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"设备重连时发生错误: {SelectedDevice.Remark} - {ex.Message}", ex.StackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
using BOB.Models;
|
||||
using BOB.Singleton;
|
||||
using BOB.Views;
|
||||
using CAN驱动;
|
||||
using Common.PubEvent;
|
||||
using Logger;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Microsoft.Win32;
|
||||
using Model;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
@ -15,6 +18,13 @@ namespace BOB.ViewModels
|
||||
public class ShellViewModel : BindableBase
|
||||
{
|
||||
#region 属性
|
||||
private string _Title="";
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => _Title;
|
||||
set => SetProperty(ref _Title, value);
|
||||
}
|
||||
private bool _IsLeftDrawerOpen;
|
||||
|
||||
public bool IsLeftDrawerOpen
|
||||
@ -85,18 +95,26 @@ namespace BOB.ViewModels
|
||||
public ICommand NewCommand { get; set; }
|
||||
public ICommand SetDefaultCommand { get; set; }
|
||||
public ICommand LoadCommand { get; set; }
|
||||
public ICommand NavigateOneCommand { get; set; }
|
||||
public ICommand NavigateCommand { get; set; }
|
||||
public ICommand SettingChannelCommand { get; set; }
|
||||
public ICommand NavigateToCanPageCommand { get; set; }
|
||||
#endregion
|
||||
|
||||
private IEventAggregator _eventAggregator;
|
||||
private GlobalVariables _globalVariables;
|
||||
private IContainerProvider _containerProvider;
|
||||
private IRegionManager _regionManager;
|
||||
private StepRunning _stepRunning;
|
||||
private IDialogService _dialogService;
|
||||
private Task? currentExecutionTask;
|
||||
public ShellViewModel(IEventAggregator eventAggregator, IContainerProvider containerProvider,GlobalVariables globalVariables, StepRunning stepRunning)
|
||||
public ShellViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
_globalVariables = globalVariables;
|
||||
_stepRunning =stepRunning;
|
||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>(); ;
|
||||
_containerProvider = containerProvider;
|
||||
_globalVariables = containerProvider.Resolve<GlobalVariables>(); ;
|
||||
_regionManager = containerProvider.Resolve<IRegionManager>(); ;
|
||||
_dialogService= containerProvider.Resolve<IDialogService>();
|
||||
_stepRunning = containerProvider.Resolve<StepRunning>(); ;
|
||||
LeftDrawerOpenCommand = new DelegateCommand(LeftDrawerOpen);
|
||||
MinimizeCommand = new DelegateCommand<Window>(MinimizeWindow);
|
||||
MaximizeCommand = new DelegateCommand<Window>(MaximizeWindow);
|
||||
@ -111,30 +129,54 @@ namespace BOB.ViewModels
|
||||
SaveCommand = new DelegateCommand(Save);
|
||||
SetDefaultCommand = new DelegateCommand(SetDefault);
|
||||
LoadCommand = new DelegateCommand(Load);
|
||||
NavigateCommand = new DelegateCommand<string>(Navigate);
|
||||
SettingChannelCommand = new DelegateCommand(SettingChannel);
|
||||
NavigateToCanPageCommand = new DelegateCommand(NavigateToCanPage);
|
||||
_eventAggregator.GetEvent<UpdateIconEvent>().Subscribe(UpdateRunIcon);
|
||||
}
|
||||
|
||||
|
||||
private void UpdateRunIcon(string obj)
|
||||
{
|
||||
RunIcon= obj switch
|
||||
{
|
||||
"Play" => PackIconKind.Play,
|
||||
"Pause" => PackIconKind.Pause,
|
||||
_ => RunIcon
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#region ToolBar命令
|
||||
private void Load()
|
||||
private bool isConnect = false;
|
||||
|
||||
private void SettingChannel()
|
||||
{
|
||||
if (SystemConfig.Instance.DefaultSubProgramFilePath != null)
|
||||
var re = 同星驱动类.ShowChannelMappingWindow(true);
|
||||
if (re != 0)
|
||||
{
|
||||
if (File.Exists(SystemConfig.Instance.DefaultSubProgramFilePath))
|
||||
{
|
||||
Open(SystemConfig.Instance.DefaultSubProgramFilePath);
|
||||
}
|
||||
var msg = 同星驱动类.GetErrorDescription(re);
|
||||
LoggerHelper.ErrorWithNotify($"同星通道映射界面打开失败:{msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
private void NavigateToCanPage()
|
||||
{
|
||||
_dialogService.Show("CAN");
|
||||
}
|
||||
private void Navigate(string content)
|
||||
{
|
||||
switch (content)
|
||||
{
|
||||
case "程序界面":
|
||||
_regionManager.RequestNavigate("ShellViewManager", "MainView");
|
||||
break;
|
||||
|
||||
case "监控界面":
|
||||
_regionManager.RequestNavigate("ShellViewManager", "MonitorView");
|
||||
break;
|
||||
|
||||
case "数据管理":
|
||||
_regionManager.RequestNavigate("ShellViewManager", "DataView");
|
||||
break;
|
||||
|
||||
case "更新信息":
|
||||
_regionManager.RequestNavigate("ShellViewManager", "UpdateInfoView");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void SetDefault()
|
||||
{
|
||||
if(_globalVariables.CurrentFilePath!=null)
|
||||
@ -147,7 +189,6 @@ namespace BOB.ViewModels
|
||||
{
|
||||
_globalVariables.CurrentFilePath = null;
|
||||
_globalVariables.Program.Parameters.Clear();
|
||||
_globalVariables.Program.Devices.Clear();
|
||||
_globalVariables.Program.StepCollection.Clear();
|
||||
}
|
||||
|
||||
@ -191,7 +232,6 @@ namespace BOB.ViewModels
|
||||
}
|
||||
|
||||
_globalVariables.Program.Parameters = program.Parameters;
|
||||
_globalVariables.Program.Devices = program.Devices;
|
||||
_globalVariables.Program.StepCollection = program.StepCollection;
|
||||
_globalVariables.CurrentFilePath = filePath;
|
||||
LoggerHelper.SuccessWithNotify($"成功打开文件: {filePath}");
|
||||
@ -242,10 +282,6 @@ namespace BOB.ViewModels
|
||||
private ProgramModel ClearDeviceParameterValue(ProgramModel program)
|
||||
{
|
||||
var tmp = new ProgramModel(program);
|
||||
foreach (var device in tmp.Devices)
|
||||
{
|
||||
tmp.Parameters.Remove(tmp.Parameters.First(x => x.ID == device.ParameterID));
|
||||
}
|
||||
foreach (var step in tmp.StepCollection)
|
||||
{
|
||||
if (step.SubProgram != null)
|
||||
@ -370,5 +406,27 @@ namespace BOB.ViewModels
|
||||
window?.Close();
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void UpdateRunIcon(string obj)
|
||||
{
|
||||
RunIcon = obj switch
|
||||
{
|
||||
"Play" => PackIconKind.Play,
|
||||
"Pause" => PackIconKind.Pause,
|
||||
_ => RunIcon
|
||||
};
|
||||
}
|
||||
private void Load()
|
||||
{
|
||||
SystemConfig.Instance.LoadFromFile();
|
||||
if (SystemConfig.Instance.DefaultSubProgramFilePath != null)
|
||||
{
|
||||
if (File.Exists(SystemConfig.Instance.DefaultSubProgramFilePath))
|
||||
{
|
||||
Open(SystemConfig.Instance.DefaultSubProgramFilePath);
|
||||
}
|
||||
}
|
||||
Title = SystemConfig.Instance.Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
BOB/ViewModels/UpdateInfoViewModel.cs
Normal file
46
BOB/ViewModels/UpdateInfoViewModel.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using Model;
|
||||
using Newtonsoft.Json;
|
||||
using Prism.Mvvm;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace BOB.ViewModels
|
||||
{
|
||||
public class UpdateInfoViewModel : BindableBase
|
||||
{
|
||||
private List<UpdateInfoModel> _updateList;
|
||||
public List<UpdateInfoModel> UpdateList
|
||||
{
|
||||
get => _updateList;
|
||||
set => SetProperty(ref _updateList, value);
|
||||
}
|
||||
|
||||
public UpdateInfoViewModel(IContainerProvider containerProvider)
|
||||
{
|
||||
string path = Path.Combine(SystemConfig.Instance.SystemPath, "UpdateInfo.json");
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(path, Encoding.UTF8);
|
||||
UpdateList = JsonConvert.DeserializeObject<List<UpdateInfoModel>>(json)
|
||||
?? new List<UpdateInfoModel>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateList = new List<UpdateInfoModel>();
|
||||
Console.WriteLine("读取 UpdateInfo.json 出错: " + ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
UpdateList = new List<UpdateInfoModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
BOB/ViewModels/UserControls/NumericalDisplayViewModel.cs
Normal file
69
BOB/ViewModels/UserControls/NumericalDisplayViewModel.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using Prism.Mvvm;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace BOB.ViewModels.UserControls
|
||||
{
|
||||
public class NumericalDisplayViewModel : BindableBase
|
||||
{
|
||||
public NumericalDisplayViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
private string _channelNumber = string.Empty;
|
||||
private double _MonitorValue = double.NaN;
|
||||
private double _upperLimit = double.NaN;
|
||||
private double _lowerLimit = double.NaN;
|
||||
private SolidColorBrush _textColor = Brushes.Green;
|
||||
private SolidColorBrush _backgroundColor = Brushes.White;
|
||||
private Visibility _limitsVisibility = Visibility.Visible;
|
||||
|
||||
// 通道号
|
||||
public string ChannelNumber
|
||||
{
|
||||
get => _channelNumber;
|
||||
set => SetProperty(ref _channelNumber, value);
|
||||
}
|
||||
|
||||
public double MonitorValue
|
||||
{
|
||||
get => _MonitorValue;
|
||||
set => SetProperty(ref _MonitorValue, value);
|
||||
}
|
||||
|
||||
// 上限
|
||||
public double UpperLimit
|
||||
{
|
||||
get => _upperLimit;
|
||||
set => SetProperty(ref _upperLimit, value);
|
||||
}
|
||||
|
||||
// 下限
|
||||
public double LowerLimit
|
||||
{
|
||||
get => _lowerLimit;
|
||||
set => SetProperty(ref _lowerLimit, value);
|
||||
}
|
||||
|
||||
// 文字颜色
|
||||
public SolidColorBrush TextColor
|
||||
{
|
||||
get => _textColor;
|
||||
set => SetProperty(ref _textColor, value);
|
||||
}
|
||||
|
||||
// 背景颜色
|
||||
public SolidColorBrush BackgroundColor
|
||||
{
|
||||
get => _backgroundColor;
|
||||
set => SetProperty(ref _backgroundColor, value);
|
||||
}
|
||||
|
||||
// 上下限可见度
|
||||
public Visibility LimitsVisibility
|
||||
{
|
||||
get => _limitsVisibility;
|
||||
set => SetProperty(ref _limitsVisibility, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
129
BOB/Views/DataView.xaml
Normal file
129
BOB/Views/DataView.xaml
Normal file
@ -0,0 +1,129 @@
|
||||
<UserControl x:Class="BOB.Views.DataView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:vs="clr-namespace:BOB.Views"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
d:DesignHeight="1080"
|
||||
d:DesignWidth="1920">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Loaded">
|
||||
<i:InvokeCommandAction Command="{Binding LoadCommand}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<DataGrid ItemsSource="{Binding CurrentDataSource}"
|
||||
AutoGenerateColumns="True"
|
||||
Margin="20,20,0,0" />
|
||||
<GroupBox Header="数据处理"
|
||||
Grid.Row="1"
|
||||
Margin="5"
|
||||
Padding="0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="5">
|
||||
<ComboBox ItemsSource="{Binding DataTableList}"
|
||||
SelectedItem="{Binding SelectTable, Mode=TwoWay}"
|
||||
MinWidth="150"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="15,0,15,0" />
|
||||
<Button Content="选择数据表"
|
||||
Command="{Binding SelectTableCommand}"
|
||||
Margin="15,0,15,0" />
|
||||
<!-- 查询输入框 -->
|
||||
<!--<TextBox x:Name="QueryTextBox"
|
||||
Width="200"
|
||||
Margin="0,0,10,0" />
|
||||
--><!-- 查询按钮 --><!--
|
||||
<Button Content="查询"
|
||||
Command="{Binding QueryCommand}"
|
||||
CommandParameter="{Binding Text, ElementName=QueryTextBox}"
|
||||
Margin="10,0,20,0" />-->
|
||||
</StackPanel>
|
||||
|
||||
<!-- 右侧内容: 日期选择器 -->
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Column="2"
|
||||
Margin="5">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Margin="15,0,15,0"
|
||||
Text="起始日期:" />
|
||||
<DatePicker materialDesign:HintAssist.Hint="起始日期"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||
Style="{StaticResource MaterialDesignFloatingHintDatePicker}"
|
||||
Width="120"
|
||||
|
||||
Margin="0,0,10,0"
|
||||
SelectedDate="{Binding StartDate, Mode=TwoWay}" />
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="15,0,15,0"
|
||||
Text="结束日期:" />
|
||||
<DatePicker materialDesign:HintAssist.Hint="结束日期"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||
Style="{StaticResource MaterialDesignFloatingHintDatePicker}"
|
||||
Width="120"
|
||||
Margin="0,0,10,0"
|
||||
SelectedDate="{Binding EndDate, Mode=TwoWay}" />
|
||||
<!-- 查询按钮 -->
|
||||
<Button Content="查询"
|
||||
Command="{Binding QueryCommand}"
|
||||
Margin="10,0,0,0" />
|
||||
<Button Content="刷新数据"
|
||||
Command="{Binding RefreshCommand}"
|
||||
Margin="15,0,15,0" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<StackPanel Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="5">
|
||||
<Button Content="第一页"
|
||||
Command="{Binding FirstPageCommand}"
|
||||
Margin="10,0,10,0" />
|
||||
<Button Content="上一页"
|
||||
Command="{Binding PreviousPageCommand}"
|
||||
Margin="10,0,10,0" />
|
||||
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Margin="10 10 0 10"
|
||||
Text="{Binding CurrentPage}"
|
||||
materialDesign:HintAssist.Hint="" />
|
||||
<TextBlock Text="/"
|
||||
Margin="0 10"
|
||||
materialDesign:HintAssist.Hint="" />
|
||||
<TextBlock Text="{Binding UITotalPages}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="0 10" />
|
||||
|
||||
<Button Content="下一页"
|
||||
Command="{Binding NextPageCommand}"
|
||||
Margin="10,0,10,0" />
|
||||
<Button Content="最后一页"
|
||||
Command="{Binding LastPageCommand}"
|
||||
Margin="10,0,15,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -10,16 +10,17 @@ 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;
|
||||
|
||||
namespace BOB.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// ProgressView.xaml 的交互逻辑
|
||||
/// DataView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ProgressView : UserControl
|
||||
public partial class DataView : UserControl
|
||||
{
|
||||
public ProgressView()
|
||||
public DataView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
228
BOB/Views/Dialogs/BackfeedView.xaml
Normal file
228
BOB/Views/Dialogs/BackfeedView.xaml
Normal file
@ -0,0 +1,228 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.BackfeedView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:ucs="clr-namespace:BOB.Views.UserControls"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<Grid MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="220" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="350" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 实时监控 -->
|
||||
<GroupBox x:Name="实时监控区"
|
||||
Header="实时监控"
|
||||
Padding="0,0,0,0">
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电压MV,Mode=TwoWay}"
|
||||
Grid.Column="0" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电流MV,Mode=TwoWay}"
|
||||
Grid.Column="1" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 功率MV,Mode=TwoWay}"
|
||||
Grid.Column="2" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 实时曲线 -->
|
||||
<GroupBox Header="实时曲线"
|
||||
Grid.Row="1"
|
||||
Padding="0,0,0,0">
|
||||
<oxy:PlotView Model="{Binding 曲线Model}">
|
||||
<oxy:PlotView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="视图复位"
|
||||
Command="{Binding ResetViewCommand}" />
|
||||
</ContextMenu>
|
||||
</oxy:PlotView.ContextMenu>
|
||||
</oxy:PlotView>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 调试选项 -->
|
||||
<GroupBox Header="调试选项"
|
||||
Grid.Row="2">
|
||||
<TreeView Margin="10">
|
||||
<!-- 连接状态设置 -->
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding ConnectCommand}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding DisconnectCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 查询 -->
|
||||
<TreeViewItem Header="查询">
|
||||
<TreeViewItem Header="查询设备标识">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="查询设备标识"
|
||||
Margin="5"
|
||||
Command="{Binding QueryDeviceCommand}" />
|
||||
<Label Content="结果"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding 设备标识字符串}"
|
||||
MinWidth="100"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 设置 -->
|
||||
<TreeViewItem Header="设置">
|
||||
<!-- 远程模式 -->
|
||||
<TreeViewItem Header="远程">
|
||||
<Button Content="设置为远程模式"
|
||||
Command="{Binding SetRemoteModeCommand}"
|
||||
Margin="5" />
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 输出设置 -->
|
||||
<TreeViewItem Header="输出">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding OutputOnCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding OutputOffCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电压(V)"
|
||||
Command="{Binding SetVoltageCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding 输出电压}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电流(A)"
|
||||
Command="{Binding SetCurrentCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding 输出电流}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 电流保护 -->
|
||||
<TreeViewItem Header="电流保护(OCP)">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding EnableOCPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding DisableOCPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="清除报警"
|
||||
Command="{Binding ClearOCPAlarmCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电流保护(A)"
|
||||
Command="{Binding SetOCPCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding OCP电流}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 电压保护 -->
|
||||
<TreeViewItem Header="电压保护(OVP)">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding EnableOVPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding DisableOVPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="清除报警"
|
||||
Command="{Binding ClearOVPAlarmCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电压保护(V)"
|
||||
Command="{Binding SetOVPCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding OVP电压}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 功率保护 -->
|
||||
<TreeViewItem Header="功率保护(OPP)">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding EnableOPPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding DisableOPPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="清除报警"
|
||||
Command="{Binding ClearOPPAlarmCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置功率(W)"
|
||||
Command="{Binding SetOPPCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding OPP功率}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
</GroupBox>
|
||||
<StackPanel Grid.Row="2"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/BackfeedView.xaml.cs
Normal file
36
BOB/Views/Dialogs/BackfeedView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// BackfeedView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class BackfeedView : UserControl
|
||||
{
|
||||
public BackfeedView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
225
BOB/Views/Dialogs/CANView.xaml
Normal file
225
BOB/Views/Dialogs/CANView.xaml
Normal file
@ -0,0 +1,225 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.CANView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:cons="clr-namespace:BOB.Converters"
|
||||
xmlns:ucs="clr-namespace:BOB.Views.UserControls"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<UserControl.Resources>
|
||||
<cons:HexConverter x:Key="HexConverter" />
|
||||
</UserControl.Resources>
|
||||
<GroupBox Header="CAN手动设置"
|
||||
Padding="0,0,0,0"
|
||||
MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- TreeView 用于显示不同选项 -->
|
||||
<TreeView Grid.Row="1">
|
||||
<!-- 调试选项 -->
|
||||
<TreeViewItem Header="调试选项"
|
||||
Visibility="{Binding 高级模式可见度}">
|
||||
<Button Content="初始化TSMaster"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="初始化TSMaster" />
|
||||
<Button Content="释放TSMaster"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="释放TSMaster" />
|
||||
<Button Content="注册监听事件"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="注册监听事件" />
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 监视选项 -->
|
||||
<TreeViewItem Header="监视">
|
||||
<Frame x:Name="监视Frame"
|
||||
Height="400"
|
||||
Width="700" />
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- DBC 配置 -->
|
||||
<TreeViewItem Header="DBC">
|
||||
<Label Content="请注意,要在断开CAN卡的情况下才能操作DBC!"
|
||||
Foreground="Red" />
|
||||
<Button Content="卸载所有DBC"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="卸载DBC" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Margin="0 0 10 0"
|
||||
Content="更换DBC"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="更换DBC" />
|
||||
<Button Content="加载DBC"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="加载DBC" />
|
||||
<Label Content="通道(从0开始)"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding DBC加载通道}"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<Button Content="查看DBC"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="查看DBC" />
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- CAN卡连接选项 -->
|
||||
<TreeViewItem Header="CAN卡连接">
|
||||
<Button Content="连接"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="连接" />
|
||||
<Button Content="断开"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="断开" />
|
||||
<Button Content="清空循环发送报文"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="清空循环发送报文" />
|
||||
<Button Content="硬件配置"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="硬件配置" />
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- DBC报文发送 -->
|
||||
<TreeViewItem Header="DBC报文发送">
|
||||
<DockPanel>
|
||||
<Label Content="报文" />
|
||||
<ComboBox MinWidth="100"
|
||||
SelectedIndex="{Binding 选中报文}"
|
||||
ItemsSource="{Binding 报文}"
|
||||
/>
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="信号" />
|
||||
<ComboBox SelectedIndex="{Binding 选中信号}"
|
||||
ItemsSource="{Binding 信号}"
|
||||
MinWidth="100" />
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="信号值" />
|
||||
<TextBox Text="{Binding can报文}"
|
||||
MinWidth="100" />
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="循环发送时间间隔(ms)(0为单次发送)" />
|
||||
<TextBox Text="{Binding dbc循环发送时间间隔}"
|
||||
MinWidth="100" />
|
||||
</DockPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="通道(从0开始)"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding 报文发送通道}"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,10,10,10" />
|
||||
<Button Content="加载报文"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="加载报文"
|
||||
Margin="10" />
|
||||
<Button Content="设置信号并发送"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="设置" />
|
||||
<CheckBox Content="直接发送"
|
||||
IsChecked="{Binding 直接发送}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 自定义报文发送 -->
|
||||
<TreeViewItem Header="自定义报文发送">
|
||||
<DockPanel>
|
||||
<Label Content="通道" />
|
||||
<ComboBox MinWidth="100"
|
||||
SelectedItem="{Binding AIdxChn}"
|
||||
ItemsSource="{Binding APP_CHANNEL名称}"
|
||||
/>
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="ID" />
|
||||
<TextBox MinWidth="100"
|
||||
Text="{Binding AID, Converter={StaticResource HexConverter}, Mode=TwoWay}" />
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="DLC" />
|
||||
<TextBox MinWidth="200"
|
||||
Text="{Binding ADLC}" />
|
||||
<CheckBox Content="自动设定"
|
||||
IsChecked="{Binding 自动设定}" />
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="报文" />
|
||||
<TextBox MinWidth="200"
|
||||
Text="{Binding 自定义报文}" />
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="循环发送时间间隔(ms)(0为单次发送)" />
|
||||
<TextBox Text="{Binding 自定义循环发送时间间隔}"
|
||||
MinWidth="100" />
|
||||
</DockPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Content="发送帧"
|
||||
IsChecked="{Binding AIsTx}" />
|
||||
<CheckBox Content="扩展帧"
|
||||
IsChecked="{Binding AIsExt}" />
|
||||
<CheckBox Content="远程帧"
|
||||
IsChecked="{Binding AIsRemote}" />
|
||||
<CheckBox Content="FD"
|
||||
IsChecked="{Binding AIsFD}" />
|
||||
<CheckBox Content="BRS"
|
||||
IsChecked="{Binding AIsBRS}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="发送"
|
||||
Command="{Binding ButtonClickCommand}"
|
||||
CommandParameter="自定义报文发送" />
|
||||
<CheckBox Margin="10"
|
||||
Content="更新到数据库"
|
||||
IsChecked="{Binding 更新到数据库}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<!-- 报文录制 -->
|
||||
<TreeViewItem Header="报文录制">
|
||||
<DockPanel>
|
||||
<Label Content="路径(开始录制时使用)"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox MinWidth="100"
|
||||
Text="{Binding BLFPath}"
|
||||
VerticalContentAlignment="Center" />
|
||||
<Button Content="选择路径" Margin="10 0"
|
||||
Command="{Binding SelectBLFPathCommand}"
|
||||
CommandParameter="选择路径" />
|
||||
<Button Content="保存路径"
|
||||
Command="{Binding SaveBLFPathCommand}"
|
||||
CommandParameter="保存路径" />
|
||||
</DockPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开始录制"
|
||||
Command="{Binding StartTranscirbeCommand}"
|
||||
CommandParameter="开始录制" />
|
||||
<Button Content="结束录制"
|
||||
Margin="10 0"
|
||||
Command="{Binding EndTranscirbeCommand}"
|
||||
CommandParameter="结束录制" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/CANView.xaml.cs
Normal file
36
BOB/Views/Dialogs/CANView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// CANView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CANView : UserControl
|
||||
{
|
||||
public CANView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.DeviceSetting"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:converters="clr-namespace:BOB.Converters"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:behavior="clr-namespace:Common.Behaviors;assembly=Common"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Background="White"
|
||||
Panel.ZIndex="1000"
|
||||
mc:Ignorable="d"
|
||||
Height="290"
|
||||
Width="450">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<UserControl.Resources>
|
||||
<converters:DeviceNameConverter x:Key="DeviceNameConverter" />
|
||||
<converters:StringToVisibilityConverter x:Key="StringToVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<GroupBox Header="{Binding Title}"
|
||||
Padding="10,15,10,0"
|
||||
behavior:WindowDragBehavior.EnableWindowDrag="True">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollViewer>
|
||||
<StackPanel>
|
||||
<StackPanel Height="30"
|
||||
Visibility="{Binding Device.ErrorMessage, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Orientation="Horizontal"
|
||||
Margin="7,7,0,7">
|
||||
<TextBlock Text="{Binding Device.ErrorMessage}"
|
||||
Padding="0,11"
|
||||
Height="30"
|
||||
Foreground="Red" />
|
||||
</StackPanel>
|
||||
<StackPanel Height="30"
|
||||
Orientation="Horizontal"
|
||||
Margin="7">
|
||||
<Label Content="设备名称"
|
||||
VerticalAlignment="Bottom"
|
||||
Width="85" />
|
||||
<TextBox Text="{Binding Device.Name}"
|
||||
VerticalAlignment="Bottom"
|
||||
materialDesign:HintAssist.Hint="设备名称"
|
||||
Width="120" />
|
||||
</StackPanel>
|
||||
<StackPanel Height="30"
|
||||
Orientation="Horizontal"
|
||||
Margin="7">
|
||||
<Label Content="通讯协议类型"
|
||||
VerticalAlignment="Bottom"
|
||||
Width="85" />
|
||||
<ComboBox ItemsSource="{Binding Types}"
|
||||
SelectedItem="{Binding Device.Type,UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalAlignment="Bottom"
|
||||
Width="120"
|
||||
materialDesign:HintAssist.Hint="通讯协议类型"
|
||||
IsEnabled="{Binding IsAdd}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<prism:InvokeCommandAction Command="{Binding SelectionChangedCommand}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Height="30"
|
||||
Orientation="Horizontal"
|
||||
Margin="7">
|
||||
<Label Content="设备描述"
|
||||
Width="85"
|
||||
VerticalAlignment="Bottom" />
|
||||
<TextBox Text="{Binding Device.Description}"
|
||||
VerticalAlignment="Bottom"
|
||||
materialDesign:HintAssist.Hint="设备描述"
|
||||
Width="120" />
|
||||
</StackPanel>
|
||||
<Label Content="连接参数"
|
||||
Height="30"
|
||||
Margin="7"
|
||||
VerticalContentAlignment="Bottom" />
|
||||
<ItemsControl ItemsSource="{Binding DeviceConnectSettings}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Height="30"
|
||||
Margin="0,7">
|
||||
<Label Content="{Binding Name}"
|
||||
Width="75"
|
||||
Margin="40,0,4,0"
|
||||
VerticalContentAlignment="Bottom" />
|
||||
<TextBox VerticalAlignment="Bottom"
|
||||
Visibility="{Binding Name, Converter={StaticResource DeviceNameConverter}}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding Value}"
|
||||
Width="120" />
|
||||
<ComboBox VerticalAlignment="Bottom"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Visibility="{Binding Name, Converter={StaticResource DeviceNameConverter}, ConverterParameter=Inverse}"
|
||||
ItemsSource="{Binding Name, Converter={StaticResource DeviceNameConverter}, ConverterParameter=Items}"
|
||||
SelectedItem="{Binding Value}"
|
||||
Width="120" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<StackPanel Grid.Row="1"
|
||||
Orientation="Horizontal"
|
||||
FlowDirection="RightToLeft"
|
||||
Margin="5,10,5,15">
|
||||
<Button Content="取消"
|
||||
Width="70"
|
||||
Command="{Binding CancelCommand}" />
|
||||
<Button Content="保存"
|
||||
Width="70"
|
||||
Margin="20,0"
|
||||
Command="{Binding SaveCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
132
BOB/Views/Dialogs/EAEL9080View.xaml
Normal file
132
BOB/Views/Dialogs/EAEL9080View.xaml
Normal file
@ -0,0 +1,132 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.EAEL9080View"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:oxy1="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
|
||||
xmlns:ucs="clr-namespace:BOB.Views.UserControls"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Background="White"
|
||||
Height="850"
|
||||
Width="900"
|
||||
>
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<Grid MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="220" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="350" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 实时监控 -->
|
||||
<GroupBox x:Name="实时监控区"
|
||||
Header="实时监控"
|
||||
Padding="0,0,0,0">
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电压MV,Mode=TwoWay}"
|
||||
Grid.Column="0" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电流MV,Mode=TwoWay}"
|
||||
Grid.Column="1" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 功率MV,Mode=TwoWay}"
|
||||
Grid.Column="2" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 实时曲线 -->
|
||||
<GroupBox Header="实时曲线"
|
||||
Grid.Row="1"
|
||||
Padding="0,0,0,0">
|
||||
<oxy:PlotView Model="{Binding 曲线Model}">
|
||||
<oxy:PlotView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="视图复位"
|
||||
Command="{Binding ResetViewCommand}" />
|
||||
</ContextMenu>
|
||||
</oxy:PlotView.ContextMenu>
|
||||
</oxy:PlotView>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 调试选项 -->
|
||||
<GroupBox Header="调试选项"
|
||||
Grid.Row="2">
|
||||
<TreeView Margin="10">
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding 连接命令}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding 断开命令}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="查询">
|
||||
<TreeViewItem Header="查询设备标识">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="查询设备标识"
|
||||
Margin="5"
|
||||
Command="{Binding 查询设备信息命令}" />
|
||||
<Label Content="结果"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding 设备标识字符串}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint="设备标识字符串"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="设置">
|
||||
<TreeViewItem Header="远程">
|
||||
<Button Content="设置为远程模式"
|
||||
Command="{Binding 设置为远程模式命令}" />
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="模式切换">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="负载模式切换"
|
||||
Command="{Binding 设置负载工作模式命令}"
|
||||
Margin="5" />
|
||||
<ComboBox MinWidth="200"
|
||||
ItemsSource="{Binding 负载模式枚举}"
|
||||
SelectedItem="{Binding 负载模式}"
|
||||
materialDesign:HintAssist.Hint="负载模式"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="输出">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding 电源输出开命令}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding 电源输出关命令}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
</GroupBox>
|
||||
<StackPanel Grid.Row="2" VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding 关闭命令}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/EAEL9080View.xaml.cs
Normal file
36
BOB/Views/Dialogs/EAEL9080View.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// EAEL9080View.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class EAEL9080View : UserControl
|
||||
{
|
||||
public EAEL9080View()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
BOB/Views/Dialogs/IOBoardView.xaml
Normal file
94
BOB/Views/Dialogs/IOBoardView.xaml
Normal file
@ -0,0 +1,94 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.IOBoardView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<GroupBox Header="IO板卡手动设置"
|
||||
Padding="0,0,0,0"
|
||||
MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
<Grid >
|
||||
<TreeView Margin="10">
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding ConnectCommand}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding DisconnectCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="输出">
|
||||
<TreeViewItem Header="单通道设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Margin="5"
|
||||
Command="{Binding PowerOnCommand}" />
|
||||
<Button Content="关"
|
||||
Margin="5"
|
||||
Command="{Binding PowerOffCommand}" />
|
||||
<Label Content="输出地址"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<ComboBox SelectedItem="{Binding SelectedAddress, Mode=TwoWay}"
|
||||
ItemsSource="{Binding AddressList}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
MinWidth="100"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="全通道设置">
|
||||
<StackPanel>
|
||||
<Label Content="偏移"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding Offset}"
|
||||
MinWidth="100"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="状态"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding BatchWriteStatus}"
|
||||
MinWidth="100"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置"
|
||||
Margin="5"
|
||||
Command="{Binding SetCommand}" />
|
||||
<Button Content="读取"
|
||||
Margin="5"
|
||||
Command="{Binding ReadCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
<StackPanel Grid.Row="2"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/IOBoardView.xaml.cs
Normal file
36
BOB/Views/Dialogs/IOBoardView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// IOBoardView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class IOBoardView : UserControl
|
||||
{
|
||||
public IOBoardView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
188
BOB/Views/Dialogs/IT6724CView.xaml
Normal file
188
BOB/Views/Dialogs/IT6724CView.xaml
Normal file
@ -0,0 +1,188 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.IT6724CView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:ucs="clr-namespace:BOB.Views.UserControls"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<Grid MouseLeftButtonDown="MouseLeftButtoDown">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="220" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="350" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox x:Name="实时监控区"
|
||||
Header="实时监控"
|
||||
Padding="0,0,0,0">
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电压MV,Mode=TwoWay}"
|
||||
Grid.Column="0" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电流MV,Mode=TwoWay}"
|
||||
Grid.Column="1" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 功率MV,Mode=TwoWay}"
|
||||
Grid.Column="2" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 实时曲线 -->
|
||||
<GroupBox Header="实时曲线"
|
||||
Grid.Row="1"
|
||||
Padding="0,0,0,0">
|
||||
<oxy:PlotView Model="{Binding 曲线Model}">
|
||||
<oxy:PlotView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="视图复位"
|
||||
Command="{Binding ResetViewCommand}" />
|
||||
</ContextMenu>
|
||||
</oxy:PlotView.ContextMenu>
|
||||
</oxy:PlotView>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="调试选项"
|
||||
Grid.Row="2">
|
||||
<TreeView Margin="10">
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding ConnectCommand}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding DisconnectCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="查询">
|
||||
<TreeViewItem Header="查询设备标识">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="查询设备标识"
|
||||
Margin="5"
|
||||
Command="{Binding QueryDeviceInfoCommand}" />
|
||||
<Label Content="结果"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding 设备标识字符串}"
|
||||
MinWidth="100"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="设置">
|
||||
<TreeViewItem Header="远程">
|
||||
<Button Content="设置为远程模式"
|
||||
Command="{Binding SetRemoteModeCommand}"
|
||||
Margin="5" />
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="输出">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding PowerOnCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding PowerOffCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电压(V)"
|
||||
Command="{Binding SetOutputVoltageCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding 输出电压}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电流(A)"
|
||||
Command="{Binding SetOutputCurrentCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding 输出电流}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="电流保护(OCP)">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding EnableOCPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding DisableOCPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="清除报警"
|
||||
Command="{Binding ClearOCPAlarmCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电流保护(A)"
|
||||
Command="{Binding SetOCPCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding OCP电流}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="电压保护(OVP)">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding EnableOVPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding DisableOVPCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="清除报警"
|
||||
Command="{Binding ClearOVPAlarmCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置电压保护(V)"
|
||||
Command="{Binding SetOVPCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding OVP电压}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
</GroupBox>
|
||||
<StackPanel Grid.Row="2"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
37
BOB/Views/Dialogs/IT6724CView.xaml.cs
Normal file
37
BOB/Views/Dialogs/IT6724CView.xaml.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// IT6724CView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class IT6724CView : UserControl
|
||||
{
|
||||
public IT6724CView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
private void MouseLeftButtoDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
BOB/Views/Dialogs/LQ7500-DView.xaml
Normal file
21
BOB/Views/Dialogs/LQ7500-DView.xaml
Normal file
@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.LQ7500_DView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<Grid MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/LQ7500-DView.xaml.cs
Normal file
36
BOB/Views/Dialogs/LQ7500-DView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// LQ7500_DView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class LQ7500_DView : UserControl
|
||||
{
|
||||
public LQ7500_DView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
BOB/Views/Dialogs/PSB11000View.xaml
Normal file
189
BOB/Views/Dialogs/PSB11000View.xaml
Normal file
@ -0,0 +1,189 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.PSB11000View"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
xmlns:ucs="clr-namespace:BOB.Views.UserControls"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<Grid MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="220" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="350" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox x:Name="实时监控区"
|
||||
Header="实时监控"
|
||||
Padding="0,0,0,0">
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电压MV,Mode=TwoWay}"
|
||||
Grid.Column="0" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 电流MV,Mode=TwoWay}"
|
||||
Grid.Column="1" />
|
||||
<ucs:NumericalDisplay DataContext="{Binding 功率MV,Mode=TwoWay}"
|
||||
Grid.Column="2" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="实时曲线"
|
||||
Grid.Row="1"
|
||||
Padding="0,0,0,0">
|
||||
<oxy:PlotView Model="{Binding 曲线Model}">
|
||||
<oxy:PlotView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="视图复位"
|
||||
Command="{Binding ResetViewCommand}" />
|
||||
</ContextMenu>
|
||||
</oxy:PlotView.ContextMenu>
|
||||
</oxy:PlotView>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="调试选项"
|
||||
Grid.Row="2">
|
||||
<TreeView Margin="10">
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding ConnectCommand}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding DisconnectCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="查询">
|
||||
<TreeViewItem Header="查询设备标识">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="查询设备标识"
|
||||
Margin="5"
|
||||
Command="{Binding QueryDeviceInfoCommand}" />
|
||||
<Label Content="结果"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding 设备标识字符串}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="设置">
|
||||
<TreeViewItem Header="远程">
|
||||
<Button Content="设置为远程模式"
|
||||
Command="{Binding SetRemoteModeCommand}" />
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="模式切换">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="工作模式切换"
|
||||
Command="{Binding SwitchWorkingModeCommand}"
|
||||
Margin="5" />
|
||||
<ComboBox MinWidth="200"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
ItemsSource="{Binding 工作模式枚举}"
|
||||
SelectedItem="{Binding 工作模式}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="直流源模式切换"
|
||||
Command="{Binding SwitchDCSourceModeCommand}"
|
||||
Margin="5" />
|
||||
<ComboBox MinWidth="200"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
ItemsSource="{Binding 直流源模式枚举}"
|
||||
SelectedItem="{Binding 直流源模式}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="负载模式切换"
|
||||
Command="{Binding SwitchLoadModeCommand}"
|
||||
Margin="5" />
|
||||
<ComboBox MinWidth="200"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
ItemsSource="{Binding 负载模式枚举}"
|
||||
SelectedItem="{Binding 负载模式}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="输出">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开"
|
||||
Command="{Binding PowerOnCommand}"
|
||||
Margin="5" />
|
||||
<Button Content="关"
|
||||
Command="{Binding PowerOffCommand}"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置CC模式电压(V)"
|
||||
Command="{Binding SetCCVoltageCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding 输出电压}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置CC模式电流(A)"
|
||||
Command="{Binding SetCCCurrentCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding 输出电流}"
|
||||
MinWidth="100"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设置OCP电流(A)"
|
||||
Command="{Binding SetOCPCurrentCommand}"
|
||||
Margin="5" />
|
||||
<Label Content="值:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding OCP电流}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Add similar blocks for other settings (OVP, OPP, etc.) -->
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
</GroupBox>
|
||||
<StackPanel Grid.Row="2"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/PSB11000View.xaml.cs
Normal file
36
BOB/Views/Dialogs/PSB11000View.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// PSB11000View.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class PSB11000View : UserControl
|
||||
{
|
||||
public PSB11000View()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
208
BOB/Views/Dialogs/SQ0030G1DView.xaml
Normal file
208
BOB/Views/Dialogs/SQ0030G1DView.xaml
Normal file
@ -0,0 +1,208 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.SQ0030G1DView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<GroupBox Header="AC源手动设置"
|
||||
Padding="0,0,0,0"
|
||||
MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
<Grid >
|
||||
<TreeView Margin="10">
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding ConnectCommand}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding DisconnectCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="电压开关设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="开启"
|
||||
Margin="5"
|
||||
Command="{Binding OpenPowerSupplyCommand}" />
|
||||
<Button Content="关闭"
|
||||
Margin="5"
|
||||
Command="{Binding ClosePowerSupplyCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="设置">
|
||||
<TreeViewItem Header="设定三相电压输出">
|
||||
<TreeViewItem Header="设定三相电压档位">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="低档"
|
||||
Margin="5"
|
||||
Command="{Binding SetVoltageLevelLowCommand}" />
|
||||
<Button Content="高档"
|
||||
Margin="5"
|
||||
Command="{Binding SetVoltageLevelHighCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="输出">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Button Content="设定三相输出电压"
|
||||
Margin="5"
|
||||
Command="{Binding SetThreePhaseVoltageCommand}" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="U相输出电压"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding UPhaseVoltage}"
|
||||
MinWidth="50"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="V"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="V相输出电压"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding VPhaseVoltage}"
|
||||
MinWidth="50"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="V"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="W相输出电压"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding WPhaseVoltage}"
|
||||
MinWidth="50"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="V"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="设定通用功能输出">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设定通用功能输出电压"
|
||||
Margin="5"
|
||||
Command="{Binding SetCommonOutputVoltageCommand}" />
|
||||
<Label Content="输出电压"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding CommonOutputVoltage}"
|
||||
MinWidth="50"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="V"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设定通用功能输出频率"
|
||||
Margin="5"
|
||||
Command="{Binding SetCommonOutputFrequencyCommand}" />
|
||||
<Label Content="输出频率"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding CommonOutputFrequency}"
|
||||
MinWidth="50"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="Hz"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="设定步阶功能输出">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设定步阶功能输出电压"
|
||||
Margin="5"
|
||||
Command="{Binding SetStepOutputVoltageCommand}" />
|
||||
<Label Content="组号"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding StepOutputVoltageGroup}"
|
||||
MinWidth="50"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="输出电压"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding StepOutputVoltage}"
|
||||
MinWidth="50"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="V"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="设定步阶功能输出频率"
|
||||
Margin="5"
|
||||
Command="{Binding SetStepOutputFrequencyCommand}" />
|
||||
<Label Content="组号"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding StepOutputFrequencyGroup}"
|
||||
MinWidth="50"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="输出频率"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding StepOutputFrequency}"
|
||||
MinWidth="50"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
<Label Content="Hz"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
<StackPanel Grid.Row="2"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/SQ0030G1DView.xaml.cs
Normal file
36
BOB/Views/Dialogs/SQ0030G1DView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// SQ0030G1DView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SQ0030G1DView : UserControl
|
||||
{
|
||||
public SQ0030G1DView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
BOB/Views/Dialogs/WS-68030-380TView.xaml
Normal file
75
BOB/Views/Dialogs/WS-68030-380TView.xaml
Normal file
@ -0,0 +1,75 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.WS_68030_380TView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<GroupBox Header="AC载手动设置"
|
||||
Padding="0,0,0,0"
|
||||
MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
<Grid >
|
||||
<TreeView Margin="10">
|
||||
<TreeViewItem Header="连接状态设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="连接"
|
||||
Margin="5"
|
||||
Command="{Binding ConnectCommand}" />
|
||||
<Button Content="断开"
|
||||
Margin="5"
|
||||
Command="{Binding DisconnectCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="上下载设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="加载"
|
||||
Margin="5"
|
||||
Command="{Binding LoadCommand}" />
|
||||
<Button Content="卸载"
|
||||
Margin="5"
|
||||
Command="{Binding UnloadCommand}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
|
||||
<TreeViewItem Header="功率设置">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="读取功率"
|
||||
Margin="5"
|
||||
Command="{Binding ReadPowerCommand}" />
|
||||
<Button Content="设置功率"
|
||||
Margin="5"
|
||||
Command="{Binding SetPowerCommand}" />
|
||||
<Label Content="功率"
|
||||
Margin="5"
|
||||
VerticalContentAlignment="Center" />
|
||||
<TextBox Text="{Binding CurrentPowerDisplay}"
|
||||
MinWidth="100"
|
||||
Margin="5"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
VerticalContentAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
<StackPanel Grid.Row="2"
|
||||
VerticalAlignment="Bottom">
|
||||
<Button Content="关闭"
|
||||
Width="70"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/WS-68030-380TView.xaml.cs
Normal file
36
BOB/Views/Dialogs/WS-68030-380TView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// WS_68030_380TView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class WS_68030_380TView : UserControl
|
||||
{
|
||||
public WS_68030_380TView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
BOB/Views/Dialogs/ZXKSView.xaml
Normal file
21
BOB/Views/Dialogs/ZXKSView.xaml
Normal file
@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="BOB.Views.Dialogs.ZXKSView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.Dialogs"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Background="White"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Height="850"
|
||||
Width="900">
|
||||
<prism:Dialog.WindowStyle>
|
||||
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||
TargetType="Window" />
|
||||
</prism:Dialog.WindowStyle>
|
||||
<Grid MouseLeftButtonDown="MouseLeftButtonDown">
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
BOB/Views/Dialogs/ZXKSView.xaml.cs
Normal file
36
BOB/Views/Dialogs/ZXKSView.xaml.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// ZXKSView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ZXKSView : UserControl
|
||||
{
|
||||
public ZXKSView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Window.GetWindow(this)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
BOB/Views/MonitorView.xaml
Normal file
139
BOB/Views/MonitorView.xaml
Normal file
@ -0,0 +1,139 @@
|
||||
<UserControl x:Class="BOB.Views.MonitorView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:vs="clr-namespace:BOB.Views"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:oxy="http://oxyplot.org/wpf"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
d:DesignHeight="1080"
|
||||
d:DesignWidth="1920">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
|
||||
<GroupBox Header="自定义监视曲线"
|
||||
Grid.Row="0"
|
||||
Margin="5"
|
||||
Padding="0">
|
||||
<oxy:PlotView x:Name="CustomPlotView"
|
||||
|
||||
Model="{Binding CurveModel}"
|
||||
Background="Transparent">
|
||||
<oxy:PlotView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="视图复位"
|
||||
Command="{Binding ResetViewCommand}" />
|
||||
|
||||
</ContextMenu>
|
||||
</oxy:PlotView.ContextMenu>
|
||||
</oxy:PlotView>
|
||||
</GroupBox>
|
||||
|
||||
|
||||
<GroupBox Header="编辑曲线"
|
||||
Grid.Row="1"
|
||||
Margin="5"
|
||||
Padding="0"
|
||||
Height="120">
|
||||
<Grid>
|
||||
<!-- 创建4个列来平分区域 -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<!-- 第一个 StackPanel -->
|
||||
<ColumnDefinition Width="*" />
|
||||
<!-- 第二个 StackPanel -->
|
||||
<ColumnDefinition Width="*" />
|
||||
<!-- 第三个 StackPanel -->
|
||||
<ColumnDefinition Width="*" />
|
||||
<!-- 第四个 StackPanel -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 第一个 StackPanel - 曲线名称和添加曲线按钮 -->
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Column="0"
|
||||
Margin="30 10">
|
||||
<TextBlock Text="曲线名称:"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox Name="SignalComboBox"
|
||||
SelectedItem="{Binding SelectCurve,Mode=TwoWay}"
|
||||
MaxWidth="200"
|
||||
MinWidth="120"
|
||||
Margin="10"
|
||||
ItemsSource="{Binding DeviceSingleList}"
|
||||
VerticalAlignment="Center"
|
||||
materialDesign:HintAssist.Hint="曲线名称" />
|
||||
|
||||
<Button Content="添加曲线"
|
||||
Height="40"
|
||||
Command="{Binding AddSignalCommand}"
|
||||
Margin="10,0,10,0" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 第二个 StackPanel - 已有曲线和删除曲线按钮 -->
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Column="1"
|
||||
Margin="30 10">
|
||||
<TextBlock Text="已有曲线:"
|
||||
materialDesign:HintAssist.Hint="已有曲线"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox MaxWidth="200"
|
||||
MinWidth="120"
|
||||
SelectedItem="{Binding SelectDeleteCurve,Mode=TwoWay}"
|
||||
Margin="10"
|
||||
ItemsSource="{Binding CurSingleList}"
|
||||
materialDesign:HintAssist.Hint="已有曲线"
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
|
||||
<Button Content="删除曲线"
|
||||
Height="40"
|
||||
Command="{Binding RemoveSignalCommand}"
|
||||
Margin="10,0,10,0" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 第三个 StackPanel - 曲线默认保存路径 -->
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Column="2"
|
||||
Margin="30 10">
|
||||
<TextBlock Text="曲线保存路径:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding FilePath}"
|
||||
MaxWidth="200"
|
||||
MinWidth="90"
|
||||
Margin="15 0"
|
||||
VerticalAlignment="Center"
|
||||
Cursor="" />
|
||||
<Button Content="更改"
|
||||
Command="{Binding ChanegPathCommand}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 第四个 StackPanel - 保存时间选中 -->
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Column="3"
|
||||
Margin="30 10">
|
||||
<TextBlock Text="保存时间选中:"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox MaxWidth="100"
|
||||
MinWidth="60"
|
||||
Margin="10"
|
||||
Text="{Binding SelectedSaveDays,Mode=TwoWay}"
|
||||
VerticalAlignment="Center"
|
||||
materialDesign:HintAssist.Hint="保存天数" />
|
||||
<Button Content="保存"
|
||||
Command="{Binding SaveCommand}" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -13,18 +13,16 @@ using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BOB.Views.Dialogs
|
||||
namespace BOB.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// DeviceSetting.xaml 的交互逻辑
|
||||
/// MonitorView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class DeviceSetting : UserControl
|
||||
public partial class MonitorView : UserControl
|
||||
{
|
||||
public DeviceSetting()
|
||||
public MonitorView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@
|
||||
<TabItem Header="设备">
|
||||
<DataGrid Padding="10"
|
||||
Background="Transparent"
|
||||
ItemsSource="{Binding Program.Devices}"
|
||||
ItemsSource="{Binding DeviceInfoModel}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
@ -90,12 +90,12 @@
|
||||
<Setter Property="Fill"
|
||||
Value="Transparent" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Connected}"
|
||||
<DataTrigger Binding="{Binding IsConnected}"
|
||||
Value="True">
|
||||
<Setter Property="Fill"
|
||||
Value="LimeGreen" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Connected}"
|
||||
<DataTrigger Binding="{Binding IsConnected}"
|
||||
Value="False">
|
||||
<Setter Property="Fill"
|
||||
Value="Red" />
|
||||
@ -109,25 +109,26 @@
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTextColumn Header="设备名称"
|
||||
Binding="{Binding Name}" />
|
||||
<DataGridTextColumn Header="备注"
|
||||
Binding="{Binding Description}" />
|
||||
</DataGrid.Columns>
|
||||
Binding="{Binding DeviceName}" />
|
||||
<DataGridTemplateColumn Header="是否启用">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsEnabled}" IsEnabled="False" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
</DataGrid.Columns>
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="新增"
|
||||
Command="{Binding DeviceAddCommand}" />
|
||||
<MenuItem Header="编辑"
|
||||
Command="{Binding DeviceEditCommand}"
|
||||
/>
|
||||
<MenuItem Header="删除"
|
||||
Foreground="Red"
|
||||
Command="{Binding DeviceDeleteCommand}"
|
||||
/>
|
||||
Command="{Binding DeviceEditCommand}" />
|
||||
<MenuItem Header="重新连接"
|
||||
Command="{Binding ReconnnectCommand}" />
|
||||
<MenuItem Header="关闭"
|
||||
Command="{Binding CloseCommand}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
|
||||
</DataGrid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
<UserControl x:Class="BOB.Views.ProgressView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800">
|
||||
<Grid Background="Transparent">
|
||||
<StackPanel Width="150"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 100"
|
||||
>
|
||||
<ProgressBar Width="80"
|
||||
Height="80"
|
||||
Margin="20"
|
||||
IsIndeterminate="True"
|
||||
Style="{StaticResource MaterialDesignCircularProgressBar}" />
|
||||
<TextBlock FontSize="30" Text="加载中......" HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -11,7 +11,7 @@
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
WindowStyle="None"
|
||||
Title="ShellView"
|
||||
Title="{Binding Title}"
|
||||
d:DesignHeight="1080"
|
||||
d:DesignWidth="1920">
|
||||
<WindowChrome.WindowChrome>
|
||||
@ -38,15 +38,30 @@
|
||||
Margin="16"
|
||||
Foreground="{DynamicResource PrimaryHueMidBrush}" />
|
||||
<Separator Margin="0,0,0,8" />
|
||||
<Button Content="系统设置"
|
||||
<Button Content="程序界面"
|
||||
Command="{Binding NavigateCommand}"
|
||||
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
|
||||
Style="{StaticResource MaterialDesignFlatButton}"
|
||||
Margin="8" />
|
||||
|
||||
<Button Content="监控界面"
|
||||
Command="{Binding NavigateCommand}"
|
||||
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
|
||||
Style="{StaticResource MaterialDesignFlatButton}"
|
||||
Margin="8" />
|
||||
|
||||
<Button Content="数据管理"
|
||||
Command="{Binding NavigateCommand}"
|
||||
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
|
||||
Style="{StaticResource MaterialDesignFlatButton}"
|
||||
Margin="8" />
|
||||
|
||||
<Button Content="更新信息"
|
||||
Command="{Binding NavigateCommand}"
|
||||
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
|
||||
Style="{StaticResource MaterialDesignFlatButton}"
|
||||
Margin="8" />
|
||||
|
||||
</StackPanel>
|
||||
</materialDesign:DrawerHost.LeftDrawerContent>
|
||||
<Grid>
|
||||
@ -113,29 +128,17 @@
|
||||
<materialDesign:PackIcon Kind="Tools"
|
||||
Foreground="White" />
|
||||
</MenuItem.Icon>
|
||||
<MenuItem Header="系统设置"
|
||||
Foreground="Black" />
|
||||
<MenuItem Header="数据"
|
||||
Foreground="Black">
|
||||
<MenuItem Header="数据查询"
|
||||
Foreground="Black" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="同星CAN"
|
||||
Foreground="Black">
|
||||
<MenuItem Header="连接/断开"
|
||||
Foreground="Black" />
|
||||
<MenuItem Header="通道映射"
|
||||
Command="{Binding SettingChannelCommand}"
|
||||
Foreground="Black" />
|
||||
<MenuItem Header="加载数据库"
|
||||
Foreground="Black" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="调试"
|
||||
Foreground="Black">
|
||||
<MenuItem Header="自动运行"
|
||||
Foreground="Black" />
|
||||
<MenuItem Header="清空数据库"
|
||||
<MenuItem Header="CAN调试界面"
|
||||
Command="{Binding NavigateToCanPageCommand}"
|
||||
Foreground="Black" />
|
||||
</MenuItem>
|
||||
|
||||
</MenuItem>
|
||||
|
||||
<!-- 程序运行控制 -->
|
||||
@ -237,20 +240,25 @@
|
||||
Identifier="Root">
|
||||
<!-- 主内容区 -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="29*" />
|
||||
<ColumnDefinition Width="424*" />
|
||||
<ColumnDefinition Width="91*" />
|
||||
<ColumnDefinition Width="57*" />
|
||||
<ColumnDefinition Width="1318*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl prism:RegionManager.RegionName="ShellViewManager"
|
||||
Grid.ColumnSpan="5" />
|
||||
/>
|
||||
<Border x:Name="Overlay"
|
||||
Background="#40000000"
|
||||
Visibility="Collapsed"
|
||||
Panel.ZIndex="10"
|
||||
Grid.ColumnSpan="5" />
|
||||
Panel.ZIndex="1">
|
||||
<StackPanel Width="150"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 100">
|
||||
<ProgressBar Width="80"
|
||||
Height="80"
|
||||
Margin="20"
|
||||
IsIndeterminate="True"
|
||||
Style="{StaticResource MaterialDesignCircularProgressBar}" />
|
||||
<TextBlock FontSize="30"
|
||||
Text="加载中......"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</Grid>
|
||||
|
||||
@ -26,8 +26,6 @@ namespace BOB.Views
|
||||
public ShellView(IEventAggregator eventAggregator)
|
||||
{
|
||||
InitializeComponent();
|
||||
//注册等待消息窗口
|
||||
eventAggregator.GetEvent<WaitingEvent>().Subscribe(ShowWaiting);
|
||||
//注册灰度遮罩层
|
||||
eventAggregator.GetEvent<OverlayEvent>().Subscribe(ShowOverlay);
|
||||
}
|
||||
@ -36,13 +34,7 @@ namespace BOB.Views
|
||||
{
|
||||
Overlay.Visibility = arg ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
private void ShowWaiting(bool arg)
|
||||
{
|
||||
DialogHost.IsOpen = arg;
|
||||
|
||||
if (DialogHost.IsOpen)
|
||||
DialogHost.DialogContent = new ProgressView();
|
||||
}
|
||||
|
||||
|
||||
private void ColorZone_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
|
||||
30
BOB/Views/UpdateInfoView.xaml
Normal file
30
BOB/Views/UpdateInfoView.xaml
Normal file
@ -0,0 +1,30 @@
|
||||
<UserControl x:Class="BOB.Views.UpdateInfoView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Margin="20">
|
||||
<ListView ItemsSource="{Binding UpdateList}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Margin="5"
|
||||
Orientation="Vertical">
|
||||
<TextBlock Text="{Binding Time}"
|
||||
FontWeight="Bold"
|
||||
Foreground="#673ab7" />
|
||||
<TextBlock Text="{Binding Message}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,3,0,10" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
28
BOB/Views/UpdateInfoView.xaml.cs
Normal file
28
BOB/Views/UpdateInfoView.xaml.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// UpdateInfoView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class UpdateInfoView : UserControl
|
||||
{
|
||||
public UpdateInfoView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
74
BOB/Views/UserControls/NumericalDisplay.xaml
Normal file
74
BOB/Views/UserControls/NumericalDisplay.xaml
Normal file
@ -0,0 +1,74 @@
|
||||
<UserControl x:Class="BOB.Views.UserControls.NumericalDisplay"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BOB.Views.UserControls"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800">
|
||||
|
||||
<Grid>
|
||||
<Border Background="{Binding BackgroundColor}"
|
||||
CornerRadius="16"
|
||||
Padding="16"
|
||||
Margin="5">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="8"
|
||||
ShadowDepth="4"
|
||||
Opacity="0.3" />
|
||||
</Border.Effect>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1.3*" />
|
||||
<RowDefinition Height="6.2*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 通道号 -->
|
||||
<Viewbox>
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="Bold">
|
||||
<Run Text="{Binding ChannelNumber}" />
|
||||
</TextBlock>
|
||||
</Viewbox>
|
||||
|
||||
<!-- 温度 -->
|
||||
<Viewbox Grid.Row="1">
|
||||
<TextBlock Text="{Binding MonitorValue, StringFormat='0.00'}"
|
||||
FontSize="40"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{Binding TextColor}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Viewbox>
|
||||
|
||||
<!-- 上下限 -->
|
||||
<Viewbox Grid.Row="2">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Visibility="{Binding LimitsVisibility}">
|
||||
<TextBlock Text="下限: "
|
||||
FontSize="12"
|
||||
Foreground="Gray" />
|
||||
<TextBlock Text="{Binding LowerLimit, StringFormat='0.00'}"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Foreground="Gray"
|
||||
Margin="0,0,10,0" />
|
||||
<TextBlock Text="上限: "
|
||||
FontSize="12"
|
||||
Foreground="Gray" />
|
||||
<TextBlock Text="{Binding UpperLimit, StringFormat='0.00'}"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Foreground="Gray" />
|
||||
</StackPanel>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
28
BOB/Views/UserControls/NumericalDisplay.xaml.cs
Normal file
28
BOB/Views/UserControls/NumericalDisplay.xaml.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace BOB.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值显示卡控件.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class NumericalDisplay : UserControl
|
||||
{
|
||||
public NumericalDisplay()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
20
CAN驱动/CAN驱动.csproj
Normal file
20
CAN驱动/CAN驱动.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Interop.TSMasterAPI">
|
||||
<HintPath>..\CanDriver\bin\Debug\net8.0\Interop.TSMasterAPI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
269
CAN驱动/DBCParse.cs
Normal file
269
CAN驱动/DBCParse.cs
Normal file
@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using TSMaster;
|
||||
|
||||
namespace CAN驱动
|
||||
{
|
||||
public struct can_network
|
||||
{
|
||||
[JsonInclude]
|
||||
public string network_name;
|
||||
[JsonInclude]
|
||||
public can_node[] can_nodes;
|
||||
|
||||
}
|
||||
public struct can_node
|
||||
{
|
||||
[JsonInclude]
|
||||
public string node_name;
|
||||
[JsonInclude]
|
||||
public can_message[] tx_can_Messages;
|
||||
[JsonInclude]
|
||||
public can_message[] rx_can_Messages;
|
||||
}
|
||||
public struct can_message
|
||||
{
|
||||
[JsonInclude]
|
||||
public string message_name;
|
||||
[JsonInclude]
|
||||
public string[] signals;
|
||||
}
|
||||
|
||||
public class _Msg_
|
||||
{
|
||||
public int msg_type { get; set; }
|
||||
public int msg_id { get; set; }
|
||||
public int msg_cyclic { get; set; }
|
||||
public byte msg_dlc { get; set; }
|
||||
public string msg_name { get; set; }
|
||||
public string[] signal_Name { get; set; }
|
||||
public int msg_brs { get; set; }
|
||||
public TLIBCANFD ACANFD;
|
||||
}
|
||||
public enum Msg_Type
|
||||
{
|
||||
CAN = 0,
|
||||
CANFD = 1,
|
||||
}
|
||||
/// <summary>
|
||||
/// DBC 文件信息类型枚举,用于指定 tsdb_get_can_db_info 查询的内容类型。
|
||||
/// </summary>
|
||||
public enum DBCINFO
|
||||
{
|
||||
/// <summary>网络名称</summary>
|
||||
NETWORK_Name = 0,
|
||||
|
||||
/// <summary>CAN 报文总数</summary>
|
||||
CAN_MSG_COUNT = 11,
|
||||
/// <summary>CAN FD 报文总数</summary>
|
||||
CANFD_MSG_COUNT = 12,
|
||||
/// <summary>节点总数</summary>
|
||||
NODE_COUNT = 14,
|
||||
|
||||
/// <summary>信号名称</summary>
|
||||
SIGNAL_NAME = 33,
|
||||
|
||||
/// <summary>CAN 报文类型</summary>
|
||||
CAN_MSG_TYPE = 40,
|
||||
/// <summary>CAN 报文 DLC(数据长度码)</summary>
|
||||
CAN_MSG_DLC = 41,
|
||||
/// <summary>CAN 报文 ID</summary>
|
||||
CAN_MSG_ID = 42,
|
||||
/// <summary>CAN 报文周期</summary>
|
||||
CAN_MSG_CYCLIC = 43,
|
||||
/// <summary>CAN 报文名称</summary>
|
||||
CAN_MSG_NAME = 44,
|
||||
/// <summary>CAN 报文信号数量</summary>
|
||||
CAN_MSG_SIGNAL_COUNT = 47,
|
||||
/// <summary>CAN 报文信号名称索引</summary>
|
||||
CAN_MSG_SIGNAL_NAME_INDEX = 48,
|
||||
|
||||
/// <summary>CAN FD 报文类型</summary>
|
||||
CANFD_MSG_TYPE = 60,
|
||||
/// <summary>CAN FD 报文 DLC(数据长度码)</summary>
|
||||
CANFD_MSG_DLC = 61,
|
||||
/// <summary>CAN FD 报文 ID</summary>
|
||||
CANFD_MSG_ID = 62,
|
||||
/// <summary>CAN FD 报文周期</summary>
|
||||
CANFD_MSG_CYCLIC = 63,
|
||||
/// <summary>CAN FD 报文名称</summary>
|
||||
CANFD_MSG_NAME = 64,
|
||||
/// <summary>CAN FD 报文信号数量</summary>
|
||||
CANFD_MSG_SIGNAL_COUNT = 67,
|
||||
/// <summary>CAN FD 报文信号名称索引</summary>
|
||||
CANFD_MSG_SIGNAL_NAME_INDEX = 68,
|
||||
|
||||
/// <summary>节点名称</summary>
|
||||
NODE_Name = 101,
|
||||
/// <summary>节点发送 CAN 报文数量</summary>
|
||||
NODE_TX_CAN_COUNT = 103,
|
||||
/// <summary>节点发送 CAN 报文索引</summary>
|
||||
NODE_TX_CAN_MESSAGE_INDEX = 104,
|
||||
/// <summary>节点接收 CAN 报文数量</summary>
|
||||
NODE_RX_CAN_COUNT = 105,
|
||||
/// <summary>节点接收 CAN 报文索引</summary>
|
||||
NODE_RX_CAN_MESSAGE_INDEX = 106,
|
||||
/// <summary>节点发送 CAN FD 报文数量</summary>
|
||||
NODE_TX_CANFD_COUNT = 107,
|
||||
/// <summary>节点发送 CAN FD 报文索引</summary>
|
||||
NODE_TX_CANFD_MESSAGE_INDEX = 108,
|
||||
/// <summary>节点接收 CAN FD 报文数量</summary>
|
||||
NODE_RX_CANFD_COUNT = 109,
|
||||
/// <summary>节点接收 CAN FD 报文索引</summary>
|
||||
NODE_RX_CANFD_MESSAGE_INDEX = 110,
|
||||
}
|
||||
|
||||
public class DBCParse
|
||||
{
|
||||
public static List<List<_Msg_>> MsgDatabase { get; set; } =
|
||||
[.. Enumerable.Range(0, 12).Select(_ => new List<_Msg_>())];
|
||||
public static can_network can_Network;
|
||||
public static string tsdb_get_can_db_info(uint ADatabaseId, int AType, int AIndex, int ASubIndex)
|
||||
{
|
||||
nint tmpInt = new nint();
|
||||
int ret = TsMasterApi.tsdb_get_can_db_info(ADatabaseId, AType, AIndex, ASubIndex, ref tmpInt);
|
||||
if (ret == 0)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(tmpInt) ?? "";
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void parse(uint Aid, int channel)
|
||||
{
|
||||
int CANcount = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_COUNT, 0, 0));
|
||||
for (int i = 0; i < CANcount; i++)
|
||||
{
|
||||
_Msg_ temp = new _Msg_();
|
||||
temp.msg_type = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_TYPE, i, 0));
|
||||
temp.msg_dlc = byte.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_DLC, i, 0));
|
||||
temp.msg_id = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_ID, i, 0));
|
||||
temp.msg_name = tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_NAME, i, 0);
|
||||
temp.msg_cyclic = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_CYCLIC, i, 0));
|
||||
temp.signal_Name = new string[int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, i, 0))];
|
||||
for (int signalcount = 0; signalcount < temp.signal_Name.Length; signalcount++)
|
||||
{
|
||||
temp.signal_Name[signalcount] = tsdb_get_can_db_info(Aid, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, i, signalcount)), 0);
|
||||
}
|
||||
temp.msg_brs = 0;
|
||||
temp.ACANFD = new TLIBCANFD(APP_CHANNEL.CHN1,
|
||||
temp.msg_id,
|
||||
true,
|
||||
temp.msg_type == 1 || temp.msg_type == 4 ? true : false,
|
||||
false, temp.msg_dlc,
|
||||
temp.msg_type < 2 ? false : true,
|
||||
false);
|
||||
MsgDatabase[channel].Add(temp);
|
||||
|
||||
}
|
||||
|
||||
CANcount = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_COUNT, 0, 0));
|
||||
for (int i = 0; i < CANcount; i++)
|
||||
{
|
||||
_Msg_ temp = new _Msg_();
|
||||
temp.msg_type = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_TYPE, i, 0));
|
||||
temp.msg_dlc = byte.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_DLC, i, 0));
|
||||
temp.msg_id = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_ID, i, 0));
|
||||
temp.msg_name = tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_NAME, i, 0);
|
||||
temp.msg_cyclic = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_CYCLIC, i, 0));
|
||||
temp.signal_Name = new string[int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, i, 0))];
|
||||
for (int signalcount = 0; signalcount < temp.signal_Name.Length; signalcount++)
|
||||
{
|
||||
temp.signal_Name[signalcount] = tsdb_get_can_db_info(Aid, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, i, signalcount)), 0);
|
||||
}
|
||||
temp.msg_brs = int.Parse(tsdb_get_can_db_info(Aid, 69, i, 0));
|
||||
temp.ACANFD = new TLIBCANFD(APP_CHANNEL.CHN1, temp.msg_id, true, temp.msg_type == 1 || temp.msg_type == 4 ? true : false, false, temp.msg_dlc, temp.msg_type < 2 ? false : true, temp.msg_brs == 1 ? true : false);
|
||||
MsgDatabase[channel].Add(temp);
|
||||
}
|
||||
MsgDatabase[channel].Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
|
||||
}
|
||||
|
||||
public static void rbs_parse(uint AID, int channel)
|
||||
{
|
||||
can_Network = new can_network();
|
||||
can_Network.network_name = tsdb_get_can_db_info(AID, (int)DBCINFO.NETWORK_Name, 0, 0);
|
||||
int Node_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_COUNT, 0, 0));
|
||||
can_Network.can_nodes = new can_node[Node_count];
|
||||
for (int i = 0; i < Node_count; i++)
|
||||
{
|
||||
can_Network.can_nodes[i].node_name = tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_Name, i, 0);
|
||||
int tx_can_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CAN_COUNT, i, 0));
|
||||
int tx_canfd_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CANFD_COUNT, i, 0));
|
||||
|
||||
int rx_can_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CAN_COUNT, i, 0));
|
||||
int rx_canfd_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CANFD_COUNT, i, 0));
|
||||
|
||||
//获取tx_can结构体
|
||||
can_Network.can_nodes[i].tx_can_Messages = new can_message[tx_can_count + tx_canfd_count];
|
||||
|
||||
can_Network.can_nodes[i].rx_can_Messages = new can_message[rx_can_count + rx_canfd_count];
|
||||
//获取报文名以及信号名
|
||||
//1 get can_message idnex
|
||||
//2 get can message name
|
||||
//3 get signal count
|
||||
//4 get signal name
|
||||
int tx_index = -1;
|
||||
for (int tx_can = 0; tx_can < tx_can_count; tx_can++)
|
||||
{
|
||||
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CAN_MESSAGE_INDEX, i, tx_can));
|
||||
can_Network.can_nodes[i].tx_can_Messages[tx_can].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_NAME, can_message_idnex, 0);
|
||||
|
||||
can_Network.can_nodes[i].tx_can_Messages[tx_can].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
|
||||
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].tx_can_Messages[tx_can].signals.Length; signalcount++)
|
||||
{
|
||||
can_Network.can_nodes[i].tx_can_Messages[tx_can].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
|
||||
}
|
||||
|
||||
tx_index = tx_can;
|
||||
}
|
||||
for (int tx_can = 0; tx_can < tx_canfd_count; tx_can++, tx_index++)
|
||||
{
|
||||
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CANFD_MESSAGE_INDEX, i, tx_can));
|
||||
can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_NAME, can_message_idnex, 0);
|
||||
|
||||
can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
|
||||
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals.Length; signalcount++)
|
||||
{
|
||||
can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
int rx_index = -1;
|
||||
for (int tx_can = 0; tx_can < rx_can_count; tx_can++)
|
||||
{
|
||||
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CAN_MESSAGE_INDEX, i, tx_can));
|
||||
can_Network.can_nodes[i].rx_can_Messages[tx_can].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_NAME, can_message_idnex, 0);
|
||||
|
||||
can_Network.can_nodes[i].rx_can_Messages[tx_can].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
|
||||
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].rx_can_Messages[tx_can].signals.Length; signalcount++)
|
||||
{
|
||||
can_Network.can_nodes[i].rx_can_Messages[tx_can].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
|
||||
}
|
||||
|
||||
rx_index = tx_can;
|
||||
}
|
||||
for (int tx_can = 0; tx_can < rx_canfd_count; tx_can++, rx_index++)
|
||||
{
|
||||
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CANFD_MESSAGE_INDEX, i, tx_can));
|
||||
can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_NAME, can_message_idnex, 0);
|
||||
|
||||
can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
|
||||
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals.Length; signalcount++)
|
||||
{
|
||||
can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
BIN
CAN驱动/Interop.TSMasterAPI.dll
Normal file
BIN
CAN驱动/Interop.TSMasterAPI.dll
Normal file
Binary file not shown.
BIN
CAN驱动/TSMaster.dll
Normal file
BIN
CAN驱动/TSMaster.dll
Normal file
Binary file not shown.
1048
CAN驱动/同星驱动类.cs
Normal file
1048
CAN驱动/同星驱动类.cs
Normal file
File diff suppressed because it is too large
Load Diff
12
Common/PubEvent/ChangeCurrentTagEvent.cs
Normal file
12
Common/PubEvent/ChangeCurrentTagEvent.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Common.PubEvent
|
||||
{
|
||||
public class ChangeCurrentTagEvent:PubSubEvent<string>
|
||||
{
|
||||
}
|
||||
}
|
||||
12
Common/PubEvent/ConnectionChangeEvent.cs
Normal file
12
Common/PubEvent/ConnectionChangeEvent.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Common.PubEvent
|
||||
{
|
||||
public class ConnectionChangeEvent:PubSubEvent<(string,bool)>
|
||||
{
|
||||
}
|
||||
}
|
||||
13
Common/PubEvent/CurveDataEvent.cs
Normal file
13
Common/PubEvent/CurveDataEvent.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Common.PubEvent
|
||||
{
|
||||
public class CurveDataEvent:PubSubEvent<(string, Dictionary<string,double>)>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
12
Common/PubEvent/StartProcessEvent.cs
Normal file
12
Common/PubEvent/StartProcessEvent.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Common.PubEvent
|
||||
{
|
||||
public class StartProcessEvent:PubSubEvent<(string,bool)>
|
||||
{
|
||||
}
|
||||
}
|
||||
BIN
DeviceCommand.zip
Normal file
BIN
DeviceCommand.zip
Normal file
Binary file not shown.
30
DeviceCommand/Base/IModbusDevice.cs
Normal file
30
DeviceCommand/Base/IModbusDevice.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using NModbus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public interface IModbusDevice
|
||||
{
|
||||
public TcpClient TcpClient { get; set; }
|
||||
public SerialPort SerialPort { get; set; }
|
||||
public IModbusMaster Modbus { get; set; }
|
||||
Task<bool> ConnectAsync(CancellationToken ct = default);
|
||||
void Close();
|
||||
|
||||
Task WriteSingleRegisterAsync(byte slaveAddress, ushort registerAddress, ushort value, CancellationToken ct = default);
|
||||
Task WriteMultipleRegistersAsync(byte slaveAddress, ushort startAddress, ushort[] values, CancellationToken ct = default);
|
||||
Task<ushort[]> ReadHoldingRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default);
|
||||
|
||||
Task WriteSingleCoilAsync(byte slaveAddress, ushort coilAddress, bool value, CancellationToken ct = default);
|
||||
Task<bool[]> ReadCoilsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default);
|
||||
|
||||
Task<ushort[]> ReadInputRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
}
|
||||
19
DeviceCommand/Base/ISerialPort.cs
Normal file
19
DeviceCommand/Base/ISerialPort.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public interface ISerialPort
|
||||
{
|
||||
public SerialPort SerialPort { get; set; }
|
||||
Task<bool> ConnectAsync(CancellationToken ct = default);
|
||||
|
||||
void Close();
|
||||
|
||||
Task SendAsync(string data, CancellationToken ct = default);
|
||||
|
||||
Task<string> myReadAsync(string delimiter = "\n", CancellationToken ct = default);
|
||||
}
|
||||
}
|
||||
25
DeviceCommand/Base/ITCP.cs
Normal file
25
DeviceCommand/Base/ITCP.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public interface ITcp
|
||||
{
|
||||
public TcpClient TcpClient { get; set; }
|
||||
Task<bool> ConnectAsync(CancellationToken ct = default);
|
||||
|
||||
void Close();
|
||||
|
||||
Task SendAsync(byte[] buffer, CancellationToken ct = default);
|
||||
|
||||
Task SendAsync(string str, CancellationToken ct = default);
|
||||
|
||||
Task<byte[]> ReadAsync(int length, CancellationToken ct = default);
|
||||
|
||||
Task<string> ReadAsync(string delimiter = "\n", CancellationToken ct = default);
|
||||
|
||||
Task<string> WriteReadAsync(string command, string delimiter = "\n", CancellationToken ct = default);
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,13 @@
|
||||
using NModbus.Serial;
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public class ModbusRtu
|
||||
public class ModbusRtu:IModbusDevice
|
||||
{
|
||||
public string PortName { get; private set; } = "COM1";
|
||||
public int BaudRate { get; private set; } = 9600;
|
||||
@ -17,14 +18,13 @@ namespace DeviceCommand.Base
|
||||
public int ReadTimeout { get; private set; } = 3000;
|
||||
public int WriteTimeout { get; private set; } = 3000;
|
||||
|
||||
public SerialPort SerialPort { get; private set; } = new SerialPort();
|
||||
public IModbusMaster Modbus { get; private set; }
|
||||
public SerialPort SerialPort { get; set; } = new SerialPort();
|
||||
public TcpClient TcpClient { get; set; }
|
||||
public IModbusMaster Modbus { get; set; }
|
||||
|
||||
private readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
protected readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
|
||||
public void ConfigureDevice(string portName, int baudRate, int dataBits = 8,
|
||||
StopBits stopBits = StopBits.One, Parity parity = Parity.None,
|
||||
int readTimeout = 3000, int writeTimeout = 3000)
|
||||
public void ConfigureDevice(string portName, int baudRate, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, int readTimeout = 3000, int writeTimeout = 3000)
|
||||
{
|
||||
PortName = portName;
|
||||
BaudRate = baudRate;
|
||||
@ -35,7 +35,7 @@ namespace DeviceCommand.Base
|
||||
WriteTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
public virtual async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
@ -61,7 +61,7 @@ namespace DeviceCommand.Base
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
public virtual void Close()
|
||||
{
|
||||
if (SerialPort.IsOpen)
|
||||
SerialPort.Close();
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using NModbus;
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
@ -7,16 +8,17 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public class ModbusTcp
|
||||
public class ModbusTcp : IModbusDevice
|
||||
{
|
||||
public string IPAddress { get; private set; } = "127.0.0.1";
|
||||
public int Port { get; private set; } = 502;
|
||||
public int SendTimeout { get; private set; } = 3000;
|
||||
public int ReceiveTimeout { get; private set; } = 3000;
|
||||
public TcpClient TcpClient { get; private set; } = new TcpClient();
|
||||
public IModbusMaster Modbus { get; private set; }
|
||||
public SerialPort SerialPort { get; set; }
|
||||
public TcpClient TcpClient { get; set; } = new TcpClient();
|
||||
public IModbusMaster Modbus { get; set; }
|
||||
|
||||
private readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
protected readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
|
||||
public void ConfigureDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
||||
{
|
||||
@ -26,7 +28,7 @@ namespace DeviceCommand.Base
|
||||
ReceiveTimeout = receiveTimeout;
|
||||
}
|
||||
|
||||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
public virtual async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
@ -41,7 +43,6 @@ namespace DeviceCommand.Base
|
||||
TcpClient.Dispose();
|
||||
TcpClient = new TcpClient();
|
||||
}
|
||||
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
Modbus = new ModbusFactory().CreateMaster(TcpClient);
|
||||
return true;
|
||||
@ -51,7 +52,7 @@ namespace DeviceCommand.Base
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public void Close()
|
||||
public virtual void Close()
|
||||
{
|
||||
if (TcpClient.Connected) TcpClient.Close();
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public class Serial_Port
|
||||
public class Serial_Port : ISerialPort
|
||||
{
|
||||
public string PortName { get; set; } = "COM1";
|
||||
public int BaudRate { get; set; } = 9600;
|
||||
@ -15,12 +15,10 @@ namespace DeviceCommand.Base
|
||||
public Parity Parity { get; set; } = Parity.None;
|
||||
public int ReadTimeout { get; set; } = 3000;
|
||||
public int WriteTimeout { get; set; } = 3000;
|
||||
public SerialPort _SerialPort { get; private set; } = new SerialPort();
|
||||
private readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
public SerialPort SerialPort { get; set; } = new SerialPort();
|
||||
protected readonly SemaphoreSlim commLock = new(1, 1);
|
||||
|
||||
public void ConfigureDevice(string portName, int baudRate, int dataBits = 8,
|
||||
StopBits stopBits = StopBits.One, Parity parity = Parity.None,
|
||||
int readTimeout = 3000, int writeTimeout = 3000)
|
||||
public void ConfigureDevice(string portName, int baudRate, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, int readTimeout = 3000, int writeTimeout = 3000)
|
||||
{
|
||||
PortName = portName;
|
||||
BaudRate = baudRate;
|
||||
@ -30,45 +28,48 @@ namespace DeviceCommand.Base
|
||||
ReadTimeout = readTimeout;
|
||||
WriteTimeout = writeTimeout;
|
||||
}
|
||||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
public virtual async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
await commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (_SerialPort.IsOpen) _SerialPort.Close();
|
||||
if (SerialPort.IsOpen) SerialPort.Close();
|
||||
|
||||
_SerialPort.PortName = PortName;
|
||||
_SerialPort.BaudRate = BaudRate;
|
||||
_SerialPort.DataBits = DataBits;
|
||||
_SerialPort.StopBits = StopBits;
|
||||
_SerialPort.Parity = Parity;
|
||||
_SerialPort.ReadTimeout = ReadTimeout;
|
||||
_SerialPort.WriteTimeout = WriteTimeout;
|
||||
SerialPort.PortName = PortName;
|
||||
SerialPort.BaudRate = BaudRate;
|
||||
SerialPort.DataBits = DataBits;
|
||||
SerialPort.StopBits = StopBits;
|
||||
SerialPort.Parity = Parity;
|
||||
SerialPort.ReadTimeout = ReadTimeout;
|
||||
SerialPort.WriteTimeout = WriteTimeout;
|
||||
|
||||
_SerialPort.Open();
|
||||
SerialPort.Open();
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
commLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
public virtual void Close()
|
||||
{
|
||||
if (_SerialPort.IsOpen) _SerialPort.Close();
|
||||
if (SerialPort.IsOpen) SerialPort.Close();
|
||||
}
|
||||
|
||||
public async Task SendAsync(string data, CancellationToken ct = default)
|
||||
public virtual async Task SendAsync(string data, CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
await commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (!_SerialPort.IsOpen) return;
|
||||
if (!SerialPort.IsOpen)
|
||||
{
|
||||
throw new InvalidOperationException("串口未打开,无法进行操作。");
|
||||
}
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(data);
|
||||
|
||||
var timeoutTask = Task.Delay(WriteTimeout > 0 ? WriteTimeout : Timeout.Infinite, ct);
|
||||
var sendTask = Task.Run(() => _SerialPort.Write(bytes, 0, bytes.Length), ct);
|
||||
var sendTask = Task.Run(() => SerialPort.Write(bytes, 0, bytes.Length), ct);
|
||||
|
||||
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
||||
if (completedTask == timeoutTask) throw new TimeoutException($"写入操作在 {WriteTimeout} ms内未完成");
|
||||
@ -76,16 +77,23 @@ namespace DeviceCommand.Base
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
commLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> ReadAsync(string delimiter = "\n", CancellationToken ct = default)
|
||||
public async Task<string> ReadAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
return await myReadAsync(ct: ct).WaitAsync(TimeSpan.FromMilliseconds(ReadTimeout), ct);
|
||||
}
|
||||
|
||||
public async Task<string> myReadAsync(string delimiter = "\n", CancellationToken ct = default)
|
||||
{
|
||||
await commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (!_SerialPort.IsOpen) return null;
|
||||
if (!SerialPort.IsOpen)
|
||||
{
|
||||
throw new InvalidOperationException("串口未打开,无法进行操作。");
|
||||
}
|
||||
|
||||
delimiter ??= "\n";
|
||||
var sb = new StringBuilder();
|
||||
@ -93,9 +101,9 @@ namespace DeviceCommand.Base
|
||||
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
if (_SerialPort.BytesToRead > 0)
|
||||
if (SerialPort.BytesToRead > 0)
|
||||
{
|
||||
int bytesRead = _SerialPort.Read(buffer, 0, buffer.Length);
|
||||
int bytesRead = SerialPort.Read(buffer, 0, buffer.Length);
|
||||
sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
|
||||
|
||||
int index = sb.ToString().IndexOf(delimiter, StringComparison.Ordinal);
|
||||
@ -114,7 +122,7 @@ namespace DeviceCommand.Base
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
commLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,14 +8,14 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Base
|
||||
{
|
||||
public class Tcp
|
||||
public class Tcp: ITcp
|
||||
{
|
||||
public string IPAddress { get; private set; } = "127.0.0.1";
|
||||
public int Port { get; private set; } = 502;
|
||||
public int SendTimeout { get; private set; } = 3000;
|
||||
public int ReceiveTimeout { get; private set; } = 3000;
|
||||
public TcpClient TcpClient { get; private set; } = new TcpClient();
|
||||
private readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
public string IPAddress { get; set; }
|
||||
public int Port { get; set; }
|
||||
public int SendTimeout { get; set; }
|
||||
public int ReceiveTimeout { get; set; }
|
||||
public TcpClient TcpClient { get; set; } = new TcpClient();
|
||||
protected readonly SemaphoreSlim _commLock = new(1, 1);
|
||||
|
||||
public void ConfigureDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
||||
{
|
||||
@ -25,20 +25,14 @@ namespace DeviceCommand.Base
|
||||
ReceiveTimeout = receiveTimeout;
|
||||
}
|
||||
|
||||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
public virtual async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
var remoteEndPoint = (IPEndPoint)TcpClient.Client.RemoteEndPoint!;
|
||||
if (remoteEndPoint.Address.MapToIPv4().ToString() == IPAddress && remoteEndPoint.Port == Port)
|
||||
return true;
|
||||
|
||||
TcpClient.Close();
|
||||
TcpClient.Dispose();
|
||||
TcpClient = new TcpClient();
|
||||
|
||||
}
|
||||
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
@ -50,9 +44,13 @@ namespace DeviceCommand.Base
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
public virtual void Close()
|
||||
{
|
||||
if(TcpClient.Connected) TcpClient.Close();
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected) TcpClient.Close();
|
||||
}
|
||||
|
||||
public async Task SendAsync(byte[] buffer, CancellationToken ct = default)
|
||||
@ -60,7 +58,10 @@ namespace DeviceCommand.Base
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (!TcpClient.Connected) return;
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
NetworkStream stream = TcpClient.GetStream();
|
||||
|
||||
var timeoutTask = Task.Delay(SendTimeout > 0 ? SendTimeout : Timeout.Infinite, ct);
|
||||
@ -79,6 +80,11 @@ namespace DeviceCommand.Base
|
||||
|
||||
public async Task SendAsync(string str, CancellationToken ct = default)
|
||||
{
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
|
||||
await SendAsync(Encoding.UTF8.GetBytes(str), ct);
|
||||
}
|
||||
|
||||
@ -87,7 +93,11 @@ namespace DeviceCommand.Base
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (!TcpClient.Connected) return null!;
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
|
||||
NetworkStream stream = TcpClient.GetStream();
|
||||
byte[] buffer = new byte[length];
|
||||
int offset = 0;
|
||||
@ -116,7 +126,11 @@ namespace DeviceCommand.Base
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (!TcpClient.Connected) return null!;
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
|
||||
delimiter ??= "\n";
|
||||
var sb = new StringBuilder();
|
||||
byte[] buffer = new byte[1024];
|
||||
@ -153,6 +167,11 @@ namespace DeviceCommand.Base
|
||||
|
||||
public async Task<string> WriteReadAsync(string command, string delimiter = "\n", CancellationToken ct = default)
|
||||
{
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
|
||||
await SendAsync(command, ct);
|
||||
return await ReadAsync(delimiter, ct);
|
||||
}
|
||||
|
||||
217
DeviceCommand/Device/Backfeed.cs
Normal file
217
DeviceCommand/Device/Backfeed.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using Common.Attributes;
|
||||
using Model;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
[BOBCommand]
|
||||
public class Backfeed
|
||||
{
|
||||
public string CurrentDevice { get; set; }
|
||||
private E36233A _E36233A { get; set; }
|
||||
private IT6724CReverse _IT6724CReverse { get; set; }
|
||||
public object CurrentInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
return _E36233A;
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
return _IT6724CReverse;
|
||||
else
|
||||
throw new InvalidOperationException("还没初始化实例");
|
||||
}
|
||||
}
|
||||
public Backfeed(ICommunicationConfig config)
|
||||
{
|
||||
if (config is TcpConfig tcpConfig)
|
||||
{
|
||||
_E36233A = new E36233A(tcpConfig.IPAddress, tcpConfig.Port, tcpConfig.WriteTimeout, tcpConfig.ReadTimeout);
|
||||
CurrentDevice = "E36233A";
|
||||
}
|
||||
else if (config is SerialPortConfig serialPortConfig)
|
||||
{
|
||||
_IT6724CReverse = new IT6724CReverse(serialPortConfig.COMPort, serialPortConfig.BaudRate, serialPortConfig.DataBit, serialPortConfig.StopBit, serialPortConfig.ParityBit, serialPortConfig.ReadTimeout, serialPortConfig.WriteTimeout);
|
||||
CurrentDevice = "IT6724CReverse";
|
||||
}
|
||||
}
|
||||
|
||||
#region 统一接口 - 设置命令
|
||||
|
||||
// 清除输出保护
|
||||
public virtual async Task 清除输出保护(CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.清除输出保护(ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.清除输出保护(ct);
|
||||
}
|
||||
|
||||
// 设置电源输出
|
||||
public virtual async Task 设置电源输出(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电源输出(开关, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电源输出(开关, ct);
|
||||
}
|
||||
|
||||
// 设置为远程模式
|
||||
public virtual async Task 设置为远程模式(CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置为远程模式(ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置为远程模式(ct);
|
||||
}
|
||||
|
||||
// 蜂鸣器测试
|
||||
public virtual async Task 蜂鸣器测试(CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.蜂鸣器测试(ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.蜂鸣器测试(ct);
|
||||
}
|
||||
|
||||
// 设置电流
|
||||
public virtual async Task 设置电流(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电流(电流, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电流(电流, ct);
|
||||
}
|
||||
|
||||
// 设置电流保护OCP电流
|
||||
public virtual async Task 设置电流保护OCP电流(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电流保护OCP电流(电流, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电流保护OCP电流(电流, ct);
|
||||
}
|
||||
|
||||
// 设置OCP开关
|
||||
public virtual async Task 设置OCP开关(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置OCP开关(开关, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置OCP开关(开关, ct);
|
||||
}
|
||||
|
||||
// 设置电压
|
||||
public virtual async Task 设置电压(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电压(电压, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电压(电压, ct);
|
||||
}
|
||||
|
||||
// 设置电压保护OVP电压
|
||||
public virtual async Task 设置电压保护OVP电压(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电压保护OVP电压(电压, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电压保护OVP电压(电压, ct);
|
||||
}
|
||||
|
||||
// 设置OVP开关
|
||||
public virtual async Task 设置OVP开关(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置OVP开关(开关, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置OVP开关(开关, ct);
|
||||
}
|
||||
|
||||
// 设置功率保护功率
|
||||
public virtual async Task 设置功率保护功率(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置功率保护功率(电压, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置功率保护功率(电压, ct);
|
||||
}
|
||||
|
||||
// 设置功率保护开关
|
||||
public virtual async Task 设置功率保护开关(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置功率保护开关(开关, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置功率保护开关(开关, ct);
|
||||
}
|
||||
|
||||
// 设置电流斜率
|
||||
public virtual async Task 设置电流斜率(double 上升斜率, double 下降斜率, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电流斜率(上升斜率, 下降斜率, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电流斜率(上升斜率, 下降斜率, ct);
|
||||
}
|
||||
|
||||
// 设置电压斜率
|
||||
public virtual async Task 设置电压斜率(double 上升斜率, double 下降斜率, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.设置电压斜率(上升斜率, 下降斜率, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.设置电压斜率(上升斜率, 下降斜率, ct);
|
||||
}
|
||||
|
||||
// 发送自定义命令
|
||||
public virtual async Task 发送自定义命令(string 指令, CancellationToken ct = default)
|
||||
{
|
||||
if (CurrentDevice == "E36233A")
|
||||
await _E36233A.发送自定义命令(指令, ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
await _IT6724CReverse.发送自定义命令(指令, ct);
|
||||
}
|
||||
public virtual async Task<double> 查询实时电压(CancellationToken ct = default)
|
||||
{
|
||||
double value = 0;
|
||||
|
||||
if (CurrentDevice == "E36233A")
|
||||
value = await _E36233A.查询电压(ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
value = await _IT6724CReverse.查询实时电压(ct);
|
||||
|
||||
return Math.Round(value, 1);
|
||||
}
|
||||
|
||||
public virtual async Task<double> 查询实时电流(CancellationToken ct = default)
|
||||
{
|
||||
double value = 0;
|
||||
|
||||
if (CurrentDevice == "E36233A")
|
||||
value = await _E36233A.查询电流(ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
value = await _IT6724CReverse.查询实时电流(ct);
|
||||
|
||||
return Math.Round(value, 1);
|
||||
}
|
||||
|
||||
public virtual async Task<double> 查询实时功率(CancellationToken ct = default)
|
||||
{
|
||||
double value = 0;
|
||||
|
||||
if (CurrentDevice == "E36233A")
|
||||
value = await _E36233A.查询功率(ct);
|
||||
else if (CurrentDevice == "IT6724CReverse")
|
||||
value = await _IT6724CReverse.查询实时功率(ct);
|
||||
|
||||
return Math.Round(value, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,436 +1,260 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
//是德
|
||||
[BOBCommand]
|
||||
public class E36233A:Tcp
|
||||
public class E36233A : Tcp
|
||||
{
|
||||
public E36233A()
|
||||
public E36233A(string ipAddress, int port, int sendTimeout, int receiveTimeout)
|
||||
{
|
||||
ConfigureDevice("127.0.0.1", 502, 3000, 3000);
|
||||
ConnectAsync();
|
||||
ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
|
||||
}
|
||||
#region SCPI 常用命令方法
|
||||
#region 心跳
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
TcpClient.Close();
|
||||
StopHeartbeat();
|
||||
}
|
||||
}
|
||||
// 启动设备的心跳
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null)
|
||||
return;
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
_cancellationTokenSource = new();
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
// 停止设备的心跳
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await 设置为远程模式();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
if (MaxReconnectAttempts < ReConnectionAttempts)
|
||||
{
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool resultConnect = await ConnectAsync(ct);
|
||||
if (resultConnect)
|
||||
{
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region 设置命令(不自动切换通道)
|
||||
|
||||
/// <summary>
|
||||
/// 查询仪器标识,返回制造商、型号、序列号、固件版本
|
||||
/// 设置当前操作通道
|
||||
/// </summary>
|
||||
public Task<string> QueryIDAsync(CancellationToken ct = default)
|
||||
public async Task 设置通道(int 通道, CancellationToken ct = default)
|
||||
{
|
||||
return SendCommandAndReadAsync("*IDN?", ct);
|
||||
await SendAsync($"INST:NSEL {通道}\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复出厂设置,不清除错误队列
|
||||
/// 查询当前通道
|
||||
/// </summary>
|
||||
public Task SendResetAsync(CancellationToken ct = default)
|
||||
public async Task<string> 查询当前通道(CancellationToken ct = default)
|
||||
{
|
||||
return SendAsync("*RST", ct);
|
||||
await SendAsync("INST:NSEL?\n", ct);
|
||||
return await ReadAsync(ct: ct);
|
||||
}
|
||||
|
||||
public async Task 清除输出保护(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("OUTP:PROT:CLE\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电源输出(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"OUTP {(开关 ? "ON" : "OFF")}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置为远程模式(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("SYST:REM\n", ct);
|
||||
}
|
||||
|
||||
public async Task 蜂鸣器测试(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("SYST:BEEP\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电流(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CURR {电流}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电流保护OCP电流(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CURR:PROT {电流}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置OCP开关(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CURR:PROT:STAT {(开关 ? "ON" : "OFF")}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电压(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"VOLT {电压}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电压保护OVP电压(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"VOLT:PROT {电压}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置OVP开关(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"VOLT:PROT:STAT {(开关 ? "ON" : "OFF")}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置功率保护功率(double 功率值, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"POW:PROT {功率值}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置功率保护开关(bool 开关, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"POW:PROT:STAT {(开关 ? "ON" : "OFF")}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电流斜率(double 上升斜率, double 下降斜率, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CURR:SLEW:UP {上升斜率}\n", ct);
|
||||
await SendAsync($"CURR:SLEW:DOWN {下降斜率}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 设置电压斜率(double 上升斜率, double 下降斜率, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"VOLT:SLEW:UP {上升斜率}\n", ct);
|
||||
await SendAsync($"VOLT:SLEW:DOWN {下降斜率}\n", ct);
|
||||
}
|
||||
|
||||
public async Task 发送自定义命令(string 指令, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"{指令}\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 存储当前仪器状态到指定位置(0~9)
|
||||
/// 查询设备基本信息
|
||||
/// </summary>
|
||||
public Task SaveStateAsync(int slot, CancellationToken ct = default)
|
||||
public async Task<string> 查询设备信息(CancellationToken ct = default)
|
||||
{
|
||||
if (slot < 0 || slot > 9) throw new ArgumentOutOfRangeException(nameof(slot));
|
||||
return SendAsync($"*SAV {slot}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用指定位置的仪器状态(0~9)
|
||||
/// </summary>
|
||||
public Task RecallStateAsync(int slot, CancellationToken ct = default)
|
||||
{
|
||||
if (slot < 0 || slot > 9) throw new ArgumentOutOfRangeException(nameof(slot));
|
||||
return SendAsync($"*RCL {slot}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 操作完成标记,发送命令等待操作完成
|
||||
/// </summary>
|
||||
public Task SendOPCAsync(CancellationToken ct = default)
|
||||
{
|
||||
return SendAsync("*OPC", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询操作完成标记,返回 "1" 表示完成
|
||||
/// </summary>
|
||||
public async Task<bool> QueryOPCAsync(CancellationToken ct = default)
|
||||
{
|
||||
var result = await SendCommandAndReadAsync("*OPC?", ct);
|
||||
return result == "1";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除状态寄存器与错误队列
|
||||
/// </summary>
|
||||
public Task ClearStatusAsync(CancellationToken ct = default)
|
||||
{
|
||||
return SendAsync("*CLS", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询状态字节(STB),返回状态值
|
||||
/// </summary>
|
||||
public async Task<int> QueryStatusByteAsync(CancellationToken ct = default)
|
||||
{
|
||||
var result = await SendCommandAndReadAsync("*STB?", ct);
|
||||
return int.TryParse(result, out var value) ? value : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用方法:发送命令并读取响应
|
||||
/// </summary>
|
||||
private async Task<string> SendCommandAndReadAsync(string command, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"{command}\r\n", ct);
|
||||
return await ReadAsync("\n", ct);
|
||||
await SendAsync("*IDN?\n", ct);
|
||||
return await ReadAsync(ct: ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 通道与输出控制命令
|
||||
#region 查询命令
|
||||
|
||||
/// <summary>
|
||||
/// 选择操作通道
|
||||
/// 查询当前电压测量值
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 1 或 2</param>
|
||||
public Task SelectChannelAsync(int channel, CancellationToken ct = default)
|
||||
public async Task<double> 查询电压(CancellationToken ct = default)
|
||||
{
|
||||
if (channel < 1 || channel > 2) throw new ArgumentOutOfRangeException(nameof(channel));
|
||||
return SendAsync($"INST:SEL CH{channel}\r\n", ct);
|
||||
await SendAsync("MEAS:VOLT?\n", ct);
|
||||
string result = await ReadAsync(ct: ct);
|
||||
return double.Parse(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启/关闭输出
|
||||
/// 查询当前电流测量值
|
||||
/// </summary>
|
||||
/// <param name="state">true 表示开,false 表示关</param>
|
||||
/// <param name="channels">通道列表,如 "1", "1:2"</param>
|
||||
public Task SetOutputStateAsync(bool state, string channels = "1", CancellationToken ct = default)
|
||||
public async Task<double> 查询电流(CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(channels)) throw new ArgumentNullException(nameof(channels));
|
||||
string cmd = $"OUTP {(state ? "ON" : "OFF")}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
await SendAsync("MEAS:CURR?\n", ct);
|
||||
string result = await ReadAsync(ct: ct);
|
||||
return double.Parse(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出上升延迟设置
|
||||
/// 查询当前功率测量值
|
||||
/// </summary>
|
||||
/// <param name="delay">延迟时间 0~3600 秒</param>
|
||||
/// <param name="channels">通道列表,如 "1", "1:2"</param>
|
||||
public Task SetOutputRiseDelayAsync(double delay, string channels = "1", CancellationToken ct = default)
|
||||
public async Task<double> 查询功率(CancellationToken ct = default)
|
||||
{
|
||||
if (delay < 0 || delay > 3600) throw new ArgumentOutOfRangeException(nameof(delay));
|
||||
string cmd = $"OUTP:DEL:RISE {delay}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出下降延迟设置
|
||||
/// </summary>
|
||||
/// <param name="delay">延迟时间 0~3600 秒</param>
|
||||
/// <param name="channels">通道列表,如 "1", "1:2"</param>
|
||||
public Task SetOutputFallDelayAsync(double delay, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
if (delay < 0 || delay > 3600) throw new ArgumentOutOfRangeException(nameof(delay));
|
||||
string cmd = $"OUTP:DEL:FALL {delay}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置串/并联模式
|
||||
/// </summary>
|
||||
/// <param name="mode">OFF(独立)、SER(串联)、PAR(并联)</param>
|
||||
public Task SetOutputPairModeAsync(string mode, CancellationToken ct = default)
|
||||
{
|
||||
if (mode != "OFF" && mode != "SER" && mode != "PAR")
|
||||
throw new ArgumentException("模式必须为 OFF, SER, PAR", nameof(mode));
|
||||
return SendAsync($"OUTP:PAIR {mode}\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通道耦合控制
|
||||
/// </summary>
|
||||
/// <param name="channelList">ALL(全耦合)、NONE(无耦合)、或指定通道,如 @1:2</param>
|
||||
public Task SetChannelCoupleAsync(string channelList, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(channelList)) throw new ArgumentNullException(nameof(channelList));
|
||||
return SendAsync($"OUTP:COUP:CHAN {channelList}\r\n", ct);
|
||||
await SendAsync("MEAS:POW?\n", ct);
|
||||
string result = await ReadAsync(ct: ct);
|
||||
return double.Parse(result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 电压 / 电流参数设置命令
|
||||
|
||||
/// <summary>
|
||||
/// 设置立即电压(单通道或多通道)
|
||||
/// </summary>
|
||||
public Task SetVoltageAsync(double voltage, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
if (voltage < 0 || voltage > 30.9) throw new ArgumentOutOfRangeException(nameof(voltage));
|
||||
string cmd = $"SOUR:VOLT {voltage}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置立即电流(单通道或多通道)
|
||||
/// </summary>
|
||||
public Task SetCurrentAsync(double current, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
if (current < 0 || current > 20.6) throw new ArgumentOutOfRangeException(nameof(current));
|
||||
string cmd = $"SOUR:CURR {current}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置触发电压(步进/序列模式使用)
|
||||
/// </summary>
|
||||
public Task SetTriggeredVoltageAsync(double voltage, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:TRIG {voltage}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置触发电流(步进/序列模式使用)
|
||||
/// </summary>
|
||||
public Task SetTriggeredCurrentAsync(double current, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:CURR:TRIG {current}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置电压模式(FIX/STEP/LIST)
|
||||
/// </summary>
|
||||
public Task SetVoltageModeAsync(string mode, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
if (mode != "FIX" && mode != "STEP" && mode != "LIST") throw new ArgumentException("模式必须为 FIX, STEP, LIST", nameof(mode));
|
||||
string cmd = $"SOUR:VOLT:MODE {mode}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置电流模式(FIX/STEP/LIST)
|
||||
/// </summary>
|
||||
public Task SetCurrentModeAsync(string mode, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
if (mode != "FIX" && mode != "STEP" && mode != "LIST") throw new ArgumentException("模式必须为 FIX, STEP, LIST", nameof(mode));
|
||||
string cmd = $"SOUR:CURR:MODE {mode}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置过压保护 OVP(110% 最大电压内)
|
||||
/// </summary>
|
||||
public Task SetOVPAsync(double voltage, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:PROT {voltage}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置过流保护 OCP(110% 最大电流内)
|
||||
/// </summary>
|
||||
public Task SetOCPAsync(double current, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:CURR:PROT {current}, (@{channels})\r\n";
|
||||
return SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量与状态查询命令
|
||||
|
||||
/// <summary>
|
||||
/// 测量指定通道的实际电压
|
||||
/// </summary>
|
||||
public async Task<double> MeasureVoltageAsync(string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"MEAS:VOLT? (@{channels})\r\n";
|
||||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||||
return double.TryParse(result, out var voltage) ? voltage : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测量指定通道的实际电流
|
||||
/// </summary>
|
||||
public async Task<double> MeasureCurrentAsync(string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"MEAS:CURR? (@{channels})\r\n";
|
||||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||||
return double.TryParse(result, out var current) ? current : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询错误队列(FIFO 返回下一个错误)
|
||||
/// </summary>
|
||||
public async Task<string> QueryNextErrorAsync(CancellationToken ct = default)
|
||||
{
|
||||
string cmd = "SYST:ERR? \r\n";
|
||||
return await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询 OVP(过压保护)状态,返回 true 表示触发
|
||||
/// </summary>
|
||||
public async Task<bool> QueryOVPTrippedAsync(string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:PROT:TRIP? (@{channels})\r\n";
|
||||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||||
return result == "1";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询 OCP(过流保护)状态,返回 true 表示触发
|
||||
/// </summary>
|
||||
public async Task<bool> QueryOCPTrippedAsync(string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:CURR:PROT:TRIP? (@{channels})\r\n";
|
||||
string result = await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||||
return result == "1";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询远程 / 本地模式,返回 LOC / REM / RWL
|
||||
/// </summary>
|
||||
public async Task<string> QueryRemoteLocalStateAsync(CancellationToken ct = default)
|
||||
{
|
||||
string cmd = "SYST:COMM:RLST?\r\n";
|
||||
return await SendAsync(cmd, ct).ContinueWith(_ => ReadAsync(ct: ct)).Unwrap();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 电压/电流序列设置与触发
|
||||
|
||||
/// <summary>
|
||||
/// 设置通道的电压序列
|
||||
/// </summary>
|
||||
/// <param name="voltages">电压序列,逗号分隔</param>
|
||||
/// <param name="channels">通道列表,如 "1" 或 "1:2"</param>
|
||||
public async Task SetVoltageListAsync(double[] voltages, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string values = string.Join(",", voltages);
|
||||
string cmd = $"SOUR:LIST:VOLT {values}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置通道的电流序列
|
||||
/// </summary>
|
||||
public async Task SetCurrentListAsync(double[] currents, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string values = string.Join(",", currents);
|
||||
string cmd = $"SOUR:LIST:CURR {values}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置每步的 dwell 时间序列
|
||||
/// </summary>
|
||||
public async Task SetDwellListAsync(double[] dwellTimes, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string values = string.Join(",", dwellTimes);
|
||||
string cmd = $"SOUR:LIST:DWEL {values}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置序列循环次数
|
||||
/// </summary>
|
||||
/// <param name="count">循环次数,1~9999 或 "INF"</param>
|
||||
public async Task SetSequenceCountAsync(string count, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:LIST:COUN {count}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动序列触发
|
||||
/// </summary>
|
||||
public async Task StartSequenceAsync(string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"INIT (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置序列触发源
|
||||
/// </summary>
|
||||
/// <param name="source">IMMediate、BUS、PIN1、PIN2、PIN3</param>
|
||||
public async Task SetTriggerSourceAsync(string source, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"TRIG:SOUR {source}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 特殊功能命令
|
||||
|
||||
/// <summary>
|
||||
/// 设置远端 sensing 模式
|
||||
/// </summary>
|
||||
/// <param name="mode">INTernal(本地2线)、EXTernal(远端4线)</param>
|
||||
/// <param name="channels">通道列表,如 "1" 或 "1:2"</param>
|
||||
public async Task SetRemoteSensingAsync(string mode, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:SENS {mode}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置电压上升斜率
|
||||
/// </summary>
|
||||
/// <param name="slewRate">单位 V/s</param>
|
||||
/// <param name="channels">通道列表</param>
|
||||
public async Task SetVoltageRiseSlewAsync(double slewRate, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:SLEW:RIS {slewRate}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置电压下降斜率
|
||||
/// </summary>
|
||||
public async Task SetVoltageFallSlewAsync(double slewRate, string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:SLEW:FALL {slewRate}, (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动数据日志
|
||||
/// </summary>
|
||||
/// <param name="filename">日志文件路径,如 Internal:/log1.dlog</param>
|
||||
public async Task StartDataLogAsync(string filename, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"INIT:DLOG \"{filename}\"\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除保护状态(OVP/OCP)
|
||||
/// </summary>
|
||||
/// <param name="channels">通道列表</param>
|
||||
public async Task ClearProtectionAsync(string channels = "1", CancellationToken ct = default)
|
||||
{
|
||||
string cmd = $"SOUR:VOLT:PROT:CLE (@{channels})\r\n";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,490 +1,323 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Logger;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
[BOBCommand]
|
||||
public class EAEL9080:ModbusTcp
|
||||
public class EAEL9080 : Tcp
|
||||
{
|
||||
public EAEL9080()
|
||||
public EAEL9080(string IpAddress, int port, int SendTimeout, int ReceiveTimeout)
|
||||
{
|
||||
ConfigureDevice("127.0.0.1", 502, 3000, 3000);
|
||||
ConnectAsync();
|
||||
}
|
||||
#region 一、基础控制与远程模式寄存器
|
||||
public async Task SetRemoteControlAsync(bool activate, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(activate ? 0xFF00 : 0x0000);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 402, value, ct);
|
||||
ConfigureDevice(IpAddress, port, SendTimeout, ReceiveTimeout);
|
||||
}
|
||||
|
||||
public async Task SetOutputAsync(bool on, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
#region 心跳
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(on ? 0xFF00 : 0x0000);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 405, value, ct);
|
||||
}
|
||||
|
||||
public async Task SetWorkModeAsync(bool useResistanceMode, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(useResistanceMode ? 0xFF00 : 0x0000);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 409, value, ct);
|
||||
}
|
||||
|
||||
public async Task ResetAlarmAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(slaveAddress, 411, 0xFF00, ct);
|
||||
}
|
||||
|
||||
public async Task WriteUserTextAsync(string text, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return;
|
||||
|
||||
text = text.Length > 40 ? text[..40] : text;
|
||||
int frameCount = (int)Math.Ceiling(text.Length / 4.0);
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
string frame = text.Substring(i * 4, Math.Min(4, text.Length - i * 4));
|
||||
ushort[] values = new ushort[frame.Length];
|
||||
for (int j = 0; j < frame.Length; j++)
|
||||
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
values[j] = frame[j];
|
||||
return true;
|
||||
}
|
||||
await WriteMultipleRegistersAsync(slaveAddress, (ushort)(171 + i), values, ct);
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public async Task<bool> QueryRemoteControlAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
public override void Close()
|
||||
{
|
||||
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 402, 1, ct);
|
||||
return result[0] == 0xFF00;
|
||||
}
|
||||
|
||||
public async Task<bool> QueryOutputAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 405, 1, ct);
|
||||
return result[0] == 0xFF00;
|
||||
}
|
||||
|
||||
public async Task<bool> QueryWorkModeAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 409, 1, ct);
|
||||
return result[0] == 0xFF00; // true 表示 UIR(电阻模式),false 表示 UIP
|
||||
}
|
||||
|
||||
public async Task<ushort[]> ReadUserTextAsync(byte slaveAddress = 1, int length = 40, CancellationToken ct = default)
|
||||
{
|
||||
int frameCount = (int)Math.Ceiling(length / 4.0);
|
||||
ushort[] textValues = new ushort[length];
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
ushort[] frame = await ReadHoldingRegistersAsync(slaveAddress, (ushort)(171 + i), 4, ct);
|
||||
for (int j = 0; j < frame.Length && (i * 4 + j) < length; j++)
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
TcpClient.Close();
|
||||
StopHeartbeat();
|
||||
}
|
||||
}
|
||||
// 启动设备的心跳
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null)
|
||||
return;
|
||||
if (_cancellationTokenSource == null||_cancellationTokenSource.IsCancellationRequested)
|
||||
_cancellationTokenSource = new();
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
// 停止设备的心跳
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
textValues[i * 4 + j] = frame[j];
|
||||
await 设置远程控制(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
if (MaxReconnectAttempts < ReConnectionAttempts)
|
||||
{
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool resultConnect = await ConnectAsync(ct);
|
||||
if (resultConnect)
|
||||
{
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
return textValues;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 二、电压 / 电流 / 功率 / 电阻设定值寄存器
|
||||
|
||||
public async Task SetVoltageAsync(double voltage, double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询设备信息
|
||||
public virtual async Task<string> 查询设备信息(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(voltage / ratedVoltage * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 500, value, ct);
|
||||
return await WriteReadAsync($"*IDN?\r\n", "\n", ct: ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 重置设备
|
||||
public virtual async Task 重置设备(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 500, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedVoltage;
|
||||
await SendAsync($"*RST\r\n", ct);
|
||||
}
|
||||
public virtual async Task 清除保护状态(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"OUTPut:PROTection:CLEar\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetCurrentAsync(double current, double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 打开输出
|
||||
public virtual async Task 打开输出(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(current / ratedCurrent * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 501, value, ct);
|
||||
await SendAsync($"OUTPut ON\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetCurrentAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 关闭输出
|
||||
public virtual async Task 关闭输出(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 501, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedCurrent;
|
||||
await SendAsync($"OUTPut OFF\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetPowerAsync(double power, double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置远程控制
|
||||
public virtual async Task 设置远程控制(bool 激活, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(power / ratedPower * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 502, value, ct);
|
||||
await SendAsync($"SYSTem:LOCK {(激活 ? "ON" : "OFF")}\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetPowerAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询远程控制状态
|
||||
public virtual async Task<string> 查询远程控制状态(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 502, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedPower;
|
||||
return await WriteReadAsync($"SYSTem:LOCK:OWNer?\r\n", "\n", ct: ct);
|
||||
}
|
||||
|
||||
public async Task SetResistanceAsync(double resistance, double maxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置电压
|
||||
public virtual async Task 设置电压(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(resistance / maxResistance * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 503, value, ct);
|
||||
await SendAsync($"SOURce:VOLTage {电压}V\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetResistanceAsync(double maxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置电流
|
||||
public virtual async Task 设置电流(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 503, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * maxResistance;
|
||||
await SendAsync($"SOURce:CURRent {电流}A\r\n", ct);
|
||||
}
|
||||
|
||||
// sink 模式示例写方法
|
||||
public async Task SetSinkPowerAsync(double power, double sinkRatedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置功率
|
||||
public virtual async Task 设置功率(double 功率, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(power / sinkRatedPower * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 498, value, ct);
|
||||
await SendAsync($"SOURce:POWer {功率}W\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetSinkCurrentAsync(double current, double sinkRatedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置电阻
|
||||
public virtual async Task 设置电阻(double 电阻, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(current / sinkRatedCurrent * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 499, value, ct);
|
||||
await SendAsync($"SOURce:RESistance {电阻}Ω\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetSinkResistanceAsync(double resistance, double sinkMaxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置过压保护
|
||||
public virtual async Task 设置过压保护(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(resistance / sinkMaxResistance * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 504, value, ct);
|
||||
await SendAsync($"SOURce:VOLTage:PROTection {电压}V\r\n", ct);
|
||||
}
|
||||
|
||||
// 读方法
|
||||
public async Task<double> GetSinkPowerAsync(double sinkRatedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置过流保护
|
||||
public virtual async Task 设置过流保护(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 498, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * sinkRatedPower;
|
||||
await SendAsync($"SOURce:CURRent:PROTection {电流}A\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetSinkCurrentAsync(double sinkRatedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置过功率保护
|
||||
public virtual async Task 设置过功率保护(double 功率, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 499, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * sinkRatedCurrent;
|
||||
await SendAsync($"SOURce:POWer:PROTection {功率}W\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetSinkResistanceAsync(double sinkMaxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询电压
|
||||
public virtual async Task<double> 查询电压(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 504, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * sinkMaxResistance;
|
||||
var str = await WriteReadAsync($"MEASure:VOLTage?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
// 查询电流
|
||||
public virtual async Task<double> 查询电流(CancellationToken ct = default)
|
||||
{
|
||||
var str = await WriteReadAsync($"MEASure:CURRent?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
// 查询功率
|
||||
public virtual async Task<double> 查询功率(CancellationToken ct = default)
|
||||
{
|
||||
var str = await WriteReadAsync($"MEASure:POWer?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
// 批量查询电压、电流、功率
|
||||
public virtual async Task<(double 电压, double 电流, double 功率)> 查询批量数据(CancellationToken ct = default)
|
||||
{
|
||||
var str = await WriteReadAsync($"MEASure:ARRay?\r\n", "\n", ct: ct);
|
||||
var values = str.Split(',');
|
||||
return (
|
||||
Convert.ToDouble(values[0]),
|
||||
Convert.ToDouble(values[1]),
|
||||
Convert.ToDouble(values[2])
|
||||
);
|
||||
}
|
||||
|
||||
// 查询标称电压
|
||||
public virtual async Task<double> 查询标称电压(CancellationToken ct = default)
|
||||
{
|
||||
var str = await WriteReadAsync($"SYSTem:NOMinal:VOLTage?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
// 查询标称电流
|
||||
public virtual async Task<double> 查询标称电流(CancellationToken ct = default)
|
||||
{
|
||||
var str = await WriteReadAsync($"SYSTem:NOMinal:CURRent?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
#region 多通道支持
|
||||
// 激活指定通道
|
||||
public virtual async Task 激活通道(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"INST:SEL CH{通道号}\r\n", ct);
|
||||
}
|
||||
|
||||
// 查询当前激活的通道
|
||||
public virtual async Task<string> 查询当前激活通道(CancellationToken ct = default)
|
||||
{
|
||||
return await WriteReadAsync($"INST:SEL?\r\n", "\n", ct);
|
||||
}
|
||||
|
||||
// 激活所有通道
|
||||
public virtual async Task 激活所有通道(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("INST:SEL ALL\r\n", ct);
|
||||
}
|
||||
|
||||
// 设置指定通道电压
|
||||
public virtual async Task 设置通道电压(int 通道号, double 电压, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:VOLT {电压}V\r\n", ct);
|
||||
}
|
||||
|
||||
// 设置指定通道电流
|
||||
public virtual async Task 设置通道电流(int 通道号, double 电流, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:CURR {电流}A\r\n", ct);
|
||||
}
|
||||
|
||||
// 设置指定通道功率
|
||||
public virtual async Task 设置通道功率(int 通道号, double 功率, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:POW {功率}W\r\n", ct);
|
||||
}
|
||||
|
||||
// 设置指定通道 Sink 模式电流
|
||||
public virtual async Task 设置通道Sink电流(int 通道号, double 电流, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:SINK:CURR {电流}A\r\n", ct);
|
||||
}
|
||||
// 启动指定通道输出
|
||||
public virtual async Task 启动通道输出(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:OUTP ON\r\n", ct);
|
||||
}
|
||||
|
||||
// 关闭指定通道输出
|
||||
public virtual async Task 关闭通道输出(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:OUTP OFF\r\n", ct);
|
||||
}
|
||||
|
||||
// 同时启停所有通道输出
|
||||
public virtual async Task 同步启动所有通道输出(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("INST:ALL:OUTP ON\r\n", ct);
|
||||
}
|
||||
|
||||
public virtual async Task 同步关闭所有通道输出(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("INST:ALL:OUTP OFF\r\n", ct);
|
||||
}
|
||||
// 查询指定通道的电压、电流和功率(批量)
|
||||
public virtual async Task<(double 电压, double 电流, double 功率)> 查询通道批量数据(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
var str = await WriteReadAsync($"CH{通道号}:MEAS:ARR?\r\n", "\n", ct);
|
||||
var values = str.Split(',');
|
||||
return (
|
||||
Convert.ToDouble(values[0]), // 电压
|
||||
Convert.ToDouble(values[1]), // 电流
|
||||
Convert.ToDouble(values[2]) // 功率
|
||||
);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 三、设备状态与实际值查询寄存器
|
||||
|
||||
/// <summary>
|
||||
/// 读取设备状态寄存器(32 位)
|
||||
/// Bit 7:DC 输出/输入开启
|
||||
/// Bit 10:远程控制激活
|
||||
/// Bit 12:sink 模式
|
||||
/// </summary>
|
||||
public async Task<uint> ReadDeviceStatusAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 505, 2, ct); // 32位寄存器 = 2 x 16位
|
||||
return (uint)(reg[0] << 16 | reg[1]);
|
||||
}
|
||||
|
||||
public async Task<bool> IsDcOnAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
|
||||
return (status & (1 << 7)) != 0;
|
||||
}
|
||||
|
||||
public async Task<bool> IsRemoteActiveAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
|
||||
return (status & (1 << 10)) != 0;
|
||||
}
|
||||
|
||||
public async Task<bool> IsSinkModeActiveAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
|
||||
return (status & (1 << 12)) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取实际电压值(单位 V)
|
||||
/// 公式: 实际值 = 寄存器值 / 0xCCCC * 额定电压
|
||||
/// </summary>
|
||||
public async Task<double> ReadActualVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 507, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedVoltage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取实际电流值(单位 A)
|
||||
/// sink 模式下可能为负值,需要根据 Bit 12 判断
|
||||
/// </summary>
|
||||
public async Task<double> ReadActualCurrentAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 508, 1, ct);
|
||||
double current = reg[0] / (double)0xCCCC * ratedCurrent;
|
||||
|
||||
if (await IsSinkModeActiveAsync(slaveAddress, ct))
|
||||
current = -current; // sink 模式电流为负
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取实际功率值(单位 W)
|
||||
/// sink 模式下可能为负值
|
||||
/// </summary>
|
||||
public async Task<double> ReadActualPowerAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 509, 1, ct);
|
||||
double power = reg[0] / (double)0xCCCC * ratedPower;
|
||||
|
||||
if (await IsSinkModeActiveAsync(slaveAddress, ct))
|
||||
power = -power;
|
||||
|
||||
return power;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取额定电压(IEEE 754 float)
|
||||
/// </summary>
|
||||
public async Task<float> ReadRatedVoltageAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 121, 2, ct);
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte)(reg[1] & 0xFF);
|
||||
bytes[1] = (byte)(reg[1] >> 8);
|
||||
bytes[2] = (byte)(reg[0] & 0xFF);
|
||||
bytes[3] = (byte)(reg[0] >> 8);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取额定电流(IEEE 754 float)
|
||||
/// </summary>
|
||||
public async Task<float> ReadRatedCurrentAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 122, 2, ct);
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte)(reg[1] & 0xFF);
|
||||
bytes[1] = (byte)(reg[1] >> 8);
|
||||
bytes[2] = (byte)(reg[0] & 0xFF);
|
||||
bytes[3] = (byte)(reg[0] >> 8);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取额定功率(IEEE 754 float)
|
||||
/// </summary>
|
||||
public async Task<float> ReadRatedPowerAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 123, 2, ct);
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte)(reg[1] & 0xFF);
|
||||
bytes[1] = (byte)(reg[1] >> 8);
|
||||
bytes[2] = (byte)(reg[0] & 0xFF);
|
||||
bytes[3] = (byte)(reg[0] >> 8);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 四、保护与报警相关寄存器
|
||||
|
||||
/// <summary>
|
||||
/// 设置过压保护(OVP)阈值
|
||||
/// </summary>
|
||||
public async Task SetOverVoltageLimitAsync(double voltage, double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(voltage / ratedVoltage * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 510, value, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过压保护(OVP)阈值
|
||||
/// </summary>
|
||||
public async Task<double> ReadOverVoltageLimitAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 510, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedVoltage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置过流保护(OCP)阈值
|
||||
/// </summary>
|
||||
public async Task SetOverCurrentLimitAsync(double current, double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(current / ratedCurrent * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 511, value, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过流保护(OCP)阈值
|
||||
/// </summary>
|
||||
public async Task<double> ReadOverCurrentLimitAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 511, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedCurrent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置过功率保护(OPP)阈值
|
||||
/// </summary>
|
||||
public async Task SetOverPowerLimitAsync(double power, double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(power / ratedPower * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 512, value, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过功率保护(OPP)阈值
|
||||
/// </summary>
|
||||
public async Task<double> ReadOverPowerLimitAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 512, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedPower;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 OVP 报警计数器,读取后复位
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOVPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 520, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 OCP 报警计数器
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOCPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 521, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 OPP 报警计数器
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOPPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 522, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过温(OT)报警计数器
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOTCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 523, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 五、函数发生器与特殊功能寄存器
|
||||
|
||||
// 寄存器 850:函数发生器启动/停止
|
||||
public async Task SetFunctionGeneratorAsync(bool start, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = start ? (ushort)0xFF00 : (ushort)0x0000;
|
||||
await WriteSingleRegisterAsync(slaveAddress, 850, value, ct);
|
||||
}
|
||||
|
||||
public async Task<bool> ReadFunctionGeneratorAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 850, 1, ct);
|
||||
return reg[0] == 0xFF00;
|
||||
}
|
||||
|
||||
// 寄存器 851:函数发生器作用于电压
|
||||
public async Task SetFunctionVoltageParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(slaveAddress, 851, 0xFF00, ct);
|
||||
}
|
||||
|
||||
public async Task<bool> ReadFunctionVoltageParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 851, 1, ct);
|
||||
return reg[0] == 0xFF00;
|
||||
}
|
||||
|
||||
// 寄存器 852:函数发生器作用于电流
|
||||
public async Task SetFunctionCurrentParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(slaveAddress, 852, 0xFF00, ct);
|
||||
}
|
||||
|
||||
public async Task<bool> ReadFunctionCurrentParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 852, 1, ct);
|
||||
return reg[0] == 0xFF00;
|
||||
}
|
||||
|
||||
// 寄存器 859~861:序列控制
|
||||
public async Task SetSequenceStartPointAsync(ushort startPoint, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (startPoint < 1 || startPoint > 99) throw new ArgumentOutOfRangeException(nameof(startPoint));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 859, startPoint, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadSequenceStartPointAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 859, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
public async Task SetSequenceEndPointAsync(ushort endPoint, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (endPoint < 1 || endPoint > 99) throw new ArgumentOutOfRangeException(nameof(endPoint));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 860, endPoint, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadSequenceEndPointAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 860, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
public async Task SetSequenceLoopCountAsync(ushort loopCount, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (loopCount > 999) throw new ArgumentOutOfRangeException(nameof(loopCount));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 861, loopCount, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadSequenceLoopCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 861, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
// 寄存器 11000:MPP 跟踪模式
|
||||
public async Task SetMPPModeAsync(ushort mode, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (mode != 0x0001 && mode != 0x0002 && mode != 0x0004) throw new ArgumentOutOfRangeException(nameof(mode));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 11000, mode, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadMPPModeAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 11000, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
140
DeviceCommand/Device/IOBoard.cs
Normal file
140
DeviceCommand/Device/IOBoard.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using NModbus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
[BOBCommand]
|
||||
public class IOBoard : ModbusTcp
|
||||
{
|
||||
public IOBoard(string Ip地址, int 端口, int 发送超时, int 接收超时)
|
||||
{
|
||||
ConfigureDevice(Ip地址, 端口, 发送超时, 接收超时);
|
||||
}
|
||||
#region 心跳
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
Modbus = new ModbusFactory().CreateMaster(TcpClient);
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
TcpClient.Close();
|
||||
StopHeartbeat();
|
||||
}
|
||||
}
|
||||
// 启动设备的心跳
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null)
|
||||
return;
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
_cancellationTokenSource = new();
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
// 停止设备的心跳
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
//await WriteSingleRegisterAsync(1, 0, 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
if (MaxReconnectAttempts < ReConnectionAttempts)
|
||||
{
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool resultConnect = await ConnectAsync(ct);
|
||||
if (resultConnect)
|
||||
{
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public async Task 写输出开关(byte 站号, ushort 开始地址, bool data)
|
||||
{
|
||||
await Modbus.WriteSingleCoilAsync(站号, 开始地址, data);
|
||||
}
|
||||
public async Task 批量写输出开关(byte 站号, ushort 开始地址, bool[] datas)
|
||||
{
|
||||
await Modbus.WriteMultipleCoilsAsync(站号, 开始地址, datas);
|
||||
}
|
||||
public async Task 读输出开关(byte 站号, ushort 开始地址)
|
||||
{
|
||||
await Modbus.ReadCoilsAsync(站号, 开始地址, 1);
|
||||
}
|
||||
public async Task<bool[]> 批量读输出开关(byte 站号, ushort 开始地址,ushort 数量)
|
||||
{
|
||||
return await Modbus.ReadCoilsAsync(站号, 开始地址, 数量);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -10,85 +13,191 @@ namespace DeviceCommand.Device
|
||||
[BOBCommand]
|
||||
public class IT6724C : Serial_Port
|
||||
{
|
||||
public IT6724C()
|
||||
public IT6724C(string COMPort, int BaudRate, int DataBits, StopBits stopBits, Parity parity, int ReadTimeout, int ReceiveTimeout)
|
||||
{
|
||||
ConfigureDevice("COM1", 9600, 8, StopBits.One, Parity.None, 3000, 3000);
|
||||
ConnectAsync();
|
||||
ConfigureDevice(COMPort, BaudRate, DataBits, stopBits, parity, ReadTimeout, ReceiveTimeout);
|
||||
}
|
||||
#region 心跳
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (SerialPort.IsOpen)
|
||||
SerialPort.Close();
|
||||
|
||||
SerialPort.PortName = PortName;
|
||||
SerialPort.BaudRate = BaudRate;
|
||||
SerialPort.DataBits = DataBits;
|
||||
SerialPort.StopBits = StopBits;
|
||||
SerialPort.Parity = Parity;
|
||||
SerialPort.ReadTimeout = ReadTimeout;
|
||||
SerialPort.WriteTimeout = WriteTimeout;
|
||||
if (SerialPort.IsOpen) return true;
|
||||
SerialPort.Open();
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
commLock.Release();
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
StopHeartbeat();
|
||||
if (SerialPort.IsOpen) SerialPort.Close();
|
||||
}
|
||||
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null && !_heartbeatTask.IsCompleted)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
catch { }
|
||||
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await 设置为远程模式(ct);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
|
||||
if (ReConnectionAttempts > MaxReconnectAttempts)
|
||||
{
|
||||
LoggerHelper.InfoWithNotify("IT6724C重连多次失败");
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool ok = await ConnectAsync(ct);
|
||||
if (ok)
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region 设置命令
|
||||
|
||||
/// <summary>
|
||||
/// 设置输出状态,true 为开,false 为关
|
||||
/// 设置电源输出状态,true 为开,false 为关
|
||||
/// </summary>
|
||||
public Task SetOutputAsync(bool state, CancellationToken ct = default)
|
||||
=> SendAsync($"OUTPut {(state ? 1 : 0)}\r\n", ct);
|
||||
public virtual async Task 设置电源输出(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"OUTPut {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 切换到远程控制模式
|
||||
/// </summary>
|
||||
public Task SetRemoteModeAsync(CancellationToken ct = default)
|
||||
=> SendAsync("SYSTem:REMote\r\n", ct);
|
||||
public virtual async Task 设置为远程模式(CancellationToken ct = default)
|
||||
=>await SendAsync("SYSTem:REMote\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 蜂鸣器测试
|
||||
/// </summary>
|
||||
public Task BeeperTestAsync(CancellationToken ct = default)
|
||||
=> SendAsync("SYSTem:BEEPer\r\n", ct);
|
||||
public virtual async Task 蜂鸣器测试(CancellationToken ct = default)
|
||||
=>await SendAsync("SYSTem:BEEPer\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 设置输出电流(单位:A)
|
||||
/// </summary>
|
||||
public Task SetCurrentAsync(double current, CancellationToken ct = default)
|
||||
=> SendAsync($"CURRent {current}\r\n", ct);
|
||||
public virtual async Task 设置电流(double 电流, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent {电流}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 设置过流保护电流(OCP,单位:A)
|
||||
/// </summary>
|
||||
public Task SetOCPCurrentAsync(double current, CancellationToken ct = default)
|
||||
=> SendAsync($"CURRent:PROTection {current}\r\n", ct);
|
||||
public virtual async Task 设置电流保护OCP电流(double 电流, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent:PROTection {电流}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 设置过流保护状态,true 为启用,false 为禁用
|
||||
/// </summary>
|
||||
public Task SetOCPStateAsync(bool state, CancellationToken ct = default)
|
||||
=> SendAsync($"CURRent:PROTection:STATe {(state ? 1 : 0)}\r\n", ct);
|
||||
public virtual async Task 设置OCP开关(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent:PROTection:STATe {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 清除过流保护触发状态
|
||||
/// </summary>
|
||||
public Task ClearOCPAsync(CancellationToken ct = default)
|
||||
=> SendAsync("CURRent:PROTection:CLEar\r\n", ct);
|
||||
public virtual async Task 清除电流保护(CancellationToken ct = default)
|
||||
=>await SendAsync("CURRent:PROTection:CLEar\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 设置输出电压(单位:V)
|
||||
/// </summary>
|
||||
public Task SetVoltageAsync(double voltage, CancellationToken ct = default)
|
||||
=> SendAsync($"VOLTage {voltage}\r\n", ct);
|
||||
public virtual async Task 设置电压(double 电压, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLTage {电压}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 设置过压保护电压(OVP,单位:V)
|
||||
/// </summary>
|
||||
public Task SetOVPVoltageAsync(double voltage, CancellationToken ct = default)
|
||||
=> SendAsync($"VOLT:PROTection {voltage}\r\n", ct);
|
||||
public virtual async Task 设置电压保护OVP电压(double 电压, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLT:PROTection {电压}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 设置过压保护状态,true 为启用,false 为禁用
|
||||
/// </summary>
|
||||
public Task SetOVPStateAsync(bool state, CancellationToken ct = default)
|
||||
=> SendAsync($"VOLT:PROTection:STATe {(state ? 1 : 0)}\r\n", ct);
|
||||
public virtual async Task 设置OVP开关(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLT:PROTection:STATe {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 清除过压保护触发状态
|
||||
/// </summary>
|
||||
public Task ClearOVPAsync(CancellationToken ct = default)
|
||||
=> SendAsync("VOLT:PROTection:CLEar\r\n", ct);
|
||||
public virtual async Task 清除电压保护(CancellationToken ct = default)
|
||||
=> await SendAsync("VOLT:PROTection:CLEar\r\n", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 发送自定义命令
|
||||
/// </summary>
|
||||
public Task SendCustomCommandAsync(string command, CancellationToken ct = default)
|
||||
=> SendAsync($"{command}\r\n", ct);
|
||||
public virtual async Task 发送自定义命令(string 指令, CancellationToken ct = default)
|
||||
=>await SendAsync($"{指令}\r\n", ct);
|
||||
|
||||
#endregion
|
||||
|
||||
@ -97,7 +206,7 @@ namespace DeviceCommand.Device
|
||||
/// <summary>
|
||||
/// 查询仪器标识,返回制造商、型号、序列号、固件版本
|
||||
/// </summary>
|
||||
public async Task<string> QueryIDAsync(CancellationToken ct = default)
|
||||
public virtual async Task<string> 查询设备信息(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("*IDN?\r\n", ct);
|
||||
return await ReadAsync(ct: ct);
|
||||
@ -106,7 +215,7 @@ namespace DeviceCommand.Device
|
||||
/// <summary>
|
||||
/// 查询过流保护是否触发,返回 true 表示触发
|
||||
/// </summary>
|
||||
public async Task<bool> QueryOCPTrippedAsync(CancellationToken ct = default)
|
||||
public virtual async Task<bool> 查询电流保护状态(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("CURRent:PROTection:TRIPed?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
@ -116,7 +225,7 @@ namespace DeviceCommand.Device
|
||||
/// <summary>
|
||||
/// 查询过压保护是否触发,返回 true 表示触发
|
||||
/// </summary>
|
||||
public async Task<bool> QueryOVPTrippedAsync(CancellationToken ct = default)
|
||||
public virtual async Task<bool> 查询电压保护状态(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("VOLT:PROTection:TRIPed?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
@ -126,7 +235,7 @@ namespace DeviceCommand.Device
|
||||
/// <summary>
|
||||
/// 查询实际输出电流(单位:A)
|
||||
/// </summary>
|
||||
public async Task<double> QueryCurrentAsync(CancellationToken ct = default)
|
||||
public virtual async Task<double> 查询实时电流(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("MEASure:CURRent?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
@ -136,7 +245,7 @@ namespace DeviceCommand.Device
|
||||
/// <summary>
|
||||
/// 查询实际输出电压(单位:V)
|
||||
/// </summary>
|
||||
public async Task<double> QueryVoltageAsync(CancellationToken ct = default)
|
||||
public virtual async Task<double> 查询实时电压(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("MEASure:VOLTage?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
@ -146,7 +255,7 @@ namespace DeviceCommand.Device
|
||||
/// <summary>
|
||||
/// 查询实际输出功率(单位:W)
|
||||
/// </summary>
|
||||
public async Task<double> QueryPowerAsync(CancellationToken ct = default)
|
||||
public virtual async Task<double> 查询实时功率(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("MEASure:POWer?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
@ -154,6 +263,5 @@ namespace DeviceCommand.Device
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
207
DeviceCommand/Device/IT6724CReverse.cs
Normal file
207
DeviceCommand/Device/IT6724CReverse.cs
Normal file
@ -0,0 +1,207 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
[BOBCommand]
|
||||
public class IT6724CReverse : Serial_Port
|
||||
{
|
||||
public IT6724CReverse(string COMPort, int BaudRate, int DataBits, StopBits stopBits, Parity parity, int ReadTimeout, int ReceiveTimeout)
|
||||
{
|
||||
ConfigureDevice(COMPort, BaudRate, DataBits, stopBits, parity, ReadTimeout, ReceiveTimeout);
|
||||
}
|
||||
#region 心跳
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (SerialPort.IsOpen)
|
||||
SerialPort.Close();
|
||||
|
||||
SerialPort.PortName = PortName;
|
||||
SerialPort.BaudRate = BaudRate;
|
||||
SerialPort.DataBits = DataBits;
|
||||
SerialPort.StopBits = StopBits;
|
||||
SerialPort.Parity = Parity;
|
||||
SerialPort.ReadTimeout = ReadTimeout;
|
||||
SerialPort.WriteTimeout = WriteTimeout;
|
||||
if (SerialPort.IsOpen) return true;
|
||||
SerialPort.Open();
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
commLock.Release();
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
StopHeartbeat();
|
||||
if (SerialPort.IsOpen) SerialPort.Close();
|
||||
}
|
||||
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null && !_heartbeatTask.IsCompleted)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
catch { }
|
||||
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await 设置为远程模式(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
|
||||
if (ReConnectionAttempts > MaxReconnectAttempts)
|
||||
{
|
||||
LoggerHelper.InfoWithNotify("IT6724C重连多次失败");
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool ok = await ConnectAsync(ct);
|
||||
if (ok)
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设置命令
|
||||
|
||||
public virtual async Task 清除输出保护(CancellationToken ct = default)
|
||||
=>await SendAsync("PROTection:CLEar\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电源输出(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"OUTPut {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置为远程模式(CancellationToken ct = default)
|
||||
=>await SendAsync("SYSTem:REMote\r\n", ct);
|
||||
|
||||
public virtual async Task 蜂鸣器测试(CancellationToken ct = default)
|
||||
=>await SendAsync("SYSTem:BEEPer\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电流(double 电流, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent {电流}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电流保护OCP电流(double 电流, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent:PROTection {电流}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置OCP开关(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent:PROTection:STATe {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电压(double 电压, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLTage {电压}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电压保护OVP电压(double 电压, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLT:PROTection {电压}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置OVP开关(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLT:PROTection:STATe {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置功率保护功率(double 电压, CancellationToken ct = default)
|
||||
=>await SendAsync($"POWer:PROTection {电压}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置功率保护开关(bool 开关, CancellationToken ct = default)
|
||||
=>await SendAsync($"POWer:PROTection:STATe {(开关 ? 1 : 0)}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电流斜率(double 上升斜率, double 下降斜率, CancellationToken ct = default)
|
||||
=>await SendAsync($"CURRent:SLEW {上升斜率},{下降斜率}\r\n", ct);
|
||||
|
||||
public virtual async Task 设置电压斜率(double 上升斜率, double 下降斜率, CancellationToken ct = default)
|
||||
=>await SendAsync($"VOLTage:SLEW {上升斜率},{下降斜率}\r\n", ct);
|
||||
|
||||
public virtual async Task 发送自定义命令(string 指令, CancellationToken ct = default)
|
||||
=>await SendAsync($"{指令}\r\n", ct);
|
||||
public virtual async Task<string> 查询设备信息(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("*IDN?\r\n", ct);
|
||||
return await ReadAsync(ct: ct);
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询实际输出电流(单位:A)
|
||||
/// </summary>
|
||||
public virtual async Task<double> 查询实时电流(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("MEASure:CURRent?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
return Convert.ToDouble(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询实际输出电压(单位:V)
|
||||
/// </summary>
|
||||
public virtual async Task<double> 查询实时电压(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("MEASure:VOLTage?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
return Convert.ToDouble(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询实际输出功率(单位:W)
|
||||
/// </summary>
|
||||
public virtual async Task<double> 查询实时功率(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync("MEASure:POWer?\r\n", ct);
|
||||
var result = await ReadAsync(ct: ct);
|
||||
return Convert.ToDouble(result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Net;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
@ -10,136 +13,240 @@ namespace DeviceCommand.Device
|
||||
[BOBCommand]
|
||||
public class LQ7500_D : ModbusRtu
|
||||
{
|
||||
public LQ7500_D()
|
||||
public LQ7500_D(string 串口, int 波特率, int 数据位, StopBits 停止位, Parity 校验位, int 读取超时, int 接收超时)
|
||||
{
|
||||
ConfigureDevice("COM1", 9600);
|
||||
ConnectAsync();
|
||||
ConfigureDevice(串口, 波特率, 数据位, 停止位, 校验位, 读取超时, 接收超时);
|
||||
}
|
||||
public byte SlaveAddress { get; set; } = 1; // default slave address
|
||||
#region 心跳
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SerialPort.IsOpen)
|
||||
SerialPort.Close();
|
||||
|
||||
SerialPort.PortName = PortName;
|
||||
SerialPort.BaudRate = BaudRate;
|
||||
SerialPort.DataBits = DataBits;
|
||||
SerialPort.StopBits = StopBits;
|
||||
SerialPort.Parity = Parity;
|
||||
SerialPort.ReadTimeout = ReadTimeout;
|
||||
SerialPort.WriteTimeout = WriteTimeout;
|
||||
if (SerialPort.IsOpen) return true;
|
||||
SerialPort.Open();
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
StopHeartbeat();
|
||||
if (SerialPort.IsOpen) SerialPort.Close();
|
||||
}
|
||||
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null && !_heartbeatTask.IsCompleted)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
catch { }
|
||||
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await WriteSingleRegisterAsync(1,0,1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
|
||||
if (ReConnectionAttempts > MaxReconnectAttempts)
|
||||
{
|
||||
LoggerHelper.InfoWithNotify("IT6724C重连多次失败");
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool ok = await ConnectAsync(ct);
|
||||
if (ok)
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
#endregion
|
||||
|
||||
public byte 从站地址 { get; set; } = 1; // 默认从站地址
|
||||
|
||||
private static readonly int[] Pow10Table =
|
||||
{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
private async Task EnsureConnectionAsync()
|
||||
private async Task 确保连接()
|
||||
{
|
||||
if (SerialPort == null || !SerialPort.IsOpen)
|
||||
await ConnectAsync();
|
||||
}
|
||||
|
||||
#region Read Methods
|
||||
#region 读取方法
|
||||
|
||||
public async Task<ushort> ReadTemperatureResolutionAsync()
|
||||
public virtual async Task<ushort> 读取温度分辨率()
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
return (await ReadHoldingRegistersAsync(SlaveAddress, 35, 1))[0];
|
||||
await 确保连接();
|
||||
return (await ReadHoldingRegistersAsync(从站地址, 35, 1))[0];
|
||||
}
|
||||
|
||||
public async Task<double> ReadInternalSensorTemperatureAsync(ushort resolution = 0)
|
||||
public virtual async Task<double> 读取内部传感器温度(ushort 分辨率 = 0)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
if (resolution == 0) resolution = await ReadTemperatureResolutionAsync();
|
||||
var data = await ReadHoldingRegistersAsync(SlaveAddress, 0, 1);
|
||||
return Math.Round(data[0] / (double)Pow10Table[resolution], resolution + 1);
|
||||
await 确保连接();
|
||||
if (分辨率 == 0) 分辨率 = await 读取温度分辨率();
|
||||
var data = await ReadHoldingRegistersAsync(从站地址, 0, 1);
|
||||
return Math.Round(data[0] / (double)Pow10Table[分辨率], 分辨率 + 1);
|
||||
}
|
||||
|
||||
public async Task<double> ReadExternalSensorTemperatureAsync(ushort resolution = 0)
|
||||
public virtual async Task<double> 读取外部传感器温度(ushort 分辨率 = 0)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
if (resolution == 0) resolution = await ReadTemperatureResolutionAsync();
|
||||
var data = await ReadHoldingRegistersAsync(SlaveAddress, 1, 1);
|
||||
return data[0] / (double)Pow10Table[resolution];
|
||||
await 确保连接();
|
||||
if (分辨率 == 0) 分辨率 = await 读取温度分辨率();
|
||||
var data = await ReadHoldingRegistersAsync(从站地址, 1, 1);
|
||||
return data[0] / (double)Pow10Table[分辨率];
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadFaultCodeAsync()
|
||||
public virtual async Task<ushort> 读取故障代码()
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
return (await ReadHoldingRegistersAsync(SlaveAddress, 1, 1))[0];
|
||||
await 确保连接();
|
||||
return (await ReadHoldingRegistersAsync(从站地址, 1, 1))[0];
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadDeviceStatusAsync()
|
||||
public virtual async Task<ushort> 读取设备状态()
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
return (await ReadHoldingRegistersAsync(SlaveAddress, 3, 1))[0];
|
||||
await 确保连接();
|
||||
return (await ReadHoldingRegistersAsync(从站地址, 3, 1))[0];
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadPumpStatusAsync()
|
||||
public virtual async Task<ushort> 读取泵状态()
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
return (await ReadHoldingRegistersAsync(SlaveAddress, 4, 1))[0];
|
||||
await 确保连接();
|
||||
return (await ReadHoldingRegistersAsync(从站地址, 4, 1))[0];
|
||||
}
|
||||
|
||||
public async Task<double> ReadFlowAsync()
|
||||
public virtual async Task<double> 读取流量()
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
var data = await ReadHoldingRegistersAsync(SlaveAddress, 17, 1);
|
||||
await 确保连接();
|
||||
var data = await ReadHoldingRegistersAsync(从站地址, 17, 1);
|
||||
return Math.Round(data[0] / 10.0, 1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Write Methods
|
||||
#region 写入方法
|
||||
|
||||
public async Task WriteFlowSettingAsync(double value)
|
||||
public virtual async Task 写入流量设置(double 值)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
short temp = (short)(value * 10);
|
||||
await 确保连接();
|
||||
short temp = (short)(值 * 10);
|
||||
ushort result = Unsafe.As<short, ushort>(ref temp);
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 24, result);
|
||||
await WriteSingleRegisterAsync(从站地址, 24, result);
|
||||
}
|
||||
|
||||
public async Task WriteDeviceStatusAsync(bool on)
|
||||
public virtual async Task 写入设备状态(bool 开)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 3, (ushort)(on ? 1 : 0));
|
||||
await 确保连接();
|
||||
await WriteSingleRegisterAsync(从站地址, 3, (ushort)(开 ? 1 : 0));
|
||||
}
|
||||
|
||||
public async Task WritePumpStatusAsync(bool on)
|
||||
public virtual async Task 写入泵状态(bool 开)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 4, (ushort)(on ? 1 : 0));
|
||||
await 确保连接();
|
||||
await WriteSingleRegisterAsync(从站地址, 4, (ushort)(开 ? 1 : 0));
|
||||
}
|
||||
|
||||
public async Task SetTemperatureAsync(double temperature)
|
||||
public virtual async Task 设置温度(double 温度)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
short temp = (short)(temperature * 100);
|
||||
await 确保连接();
|
||||
short temp = (short)(温度 * 100);
|
||||
ushort result = Unsafe.As<short, ushort>(ref temp);
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 2, result);
|
||||
await WriteSingleRegisterAsync(从站地址, 2, result);
|
||||
}
|
||||
|
||||
public async Task SetTemperatureUpperLimitAsync(double temperature)
|
||||
public virtual async Task 设置温度上限(double 温度)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
short temp = (short)(temperature * 100);
|
||||
await 确保连接();
|
||||
short temp = (short)(温度 * 100);
|
||||
ushort result = Unsafe.As<short, ushort>(ref temp);
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 5, result);
|
||||
await WriteSingleRegisterAsync(从站地址, 5, result);
|
||||
}
|
||||
|
||||
public async Task SetTemperatureLowerLimitAsync(double temperature)
|
||||
public virtual async Task 设置温度下限(double 温度)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
short temp = (short)(temperature * 100);
|
||||
await 确保连接();
|
||||
short temp = (short)(温度 * 100);
|
||||
ushort result = Unsafe.As<short, ushort>(ref temp);
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 6, result);
|
||||
await WriteSingleRegisterAsync(从站地址, 6, result);
|
||||
}
|
||||
|
||||
public async Task SetSoftwareOverTemperatureAsync(double upper, double lower)
|
||||
public virtual async Task 设置软件超温(double 上限温度, double 下限温度)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
short v1 = (short)(upper * 100);
|
||||
short v2 = (short)(lower * 100);
|
||||
await 确保连接();
|
||||
short v1 = (short)(上限温度 * 100);
|
||||
short v2 = (short)(下限温度 * 100);
|
||||
ushort[] data = MemoryMarshal.Cast<short, ushort>(new short[] { v1, v2 }).ToArray();
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 30, data[0]);
|
||||
await WriteSingleRegisterAsync(从站地址, 30, data[0]);
|
||||
await Task.Delay(5);
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 31, data[1]);
|
||||
await WriteSingleRegisterAsync(从站地址, 31, data[1]);
|
||||
}
|
||||
|
||||
public async Task SetHardwareOverTemperatureAsync(double upper)
|
||||
public virtual async Task 设置硬件超温(double 上限温度)
|
||||
{
|
||||
await EnsureConnectionAsync();
|
||||
short v1 = (short)(upper * 100);
|
||||
await 确保连接();
|
||||
short v1 = (short)(上限温度 * 100);
|
||||
ushort result = Unsafe.As<short, ushort>(ref v1);
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 32, result);
|
||||
await WriteSingleRegisterAsync(从站地址, 32, result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -1,489 +1,323 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
[BOBCommand]
|
||||
public class PSB11000: ModbusTcp
|
||||
public class PSB11000 : Tcp
|
||||
{
|
||||
public PSB11000()
|
||||
public PSB11000(string IpAddress, int port, int SendTimeout, int ReceiveTimeout)
|
||||
{
|
||||
ConfigureDevice("127.0.0.1", 502, 3000, 3000);
|
||||
ConnectAsync();
|
||||
ConfigureDevice(IpAddress, port, SendTimeout, ReceiveTimeout);
|
||||
}
|
||||
#region 一、基础控制与远程模式寄存器
|
||||
public async Task SetRemoteControlAsync(bool activate, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
#region 心跳
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(activate ? 0xFF00 : 0x0000);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 402, value, ct);
|
||||
}
|
||||
|
||||
public async Task SetOutputAsync(bool on, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(on ? 0xFF00 : 0x0000);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 405, value, ct);
|
||||
}
|
||||
|
||||
public async Task SetWorkModeAsync(bool useResistanceMode, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(useResistanceMode ? 0xFF00 : 0x0000);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 409, value, ct);
|
||||
}
|
||||
|
||||
public async Task ResetAlarmAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(slaveAddress, 411, 0xFF00, ct);
|
||||
}
|
||||
|
||||
public async Task WriteUserTextAsync(string text, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return;
|
||||
|
||||
text = text.Length > 40 ? text[..40] : text;
|
||||
int frameCount = (int)Math.Ceiling(text.Length / 4.0);
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
string frame = text.Substring(i * 4, Math.Min(4, text.Length - i * 4));
|
||||
ushort[] values = new ushort[frame.Length];
|
||||
for (int j = 0; j < frame.Length; j++)
|
||||
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
values[j] = frame[j];
|
||||
return true;
|
||||
}
|
||||
await WriteMultipleRegistersAsync(slaveAddress, (ushort)(171 + i), values, ct);
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public async Task<bool> QueryRemoteControlAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
public override void Close()
|
||||
{
|
||||
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 402, 1, ct);
|
||||
return result[0] == 0xFF00;
|
||||
}
|
||||
|
||||
public async Task<bool> QueryOutputAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 405, 1, ct);
|
||||
return result[0] == 0xFF00;
|
||||
}
|
||||
|
||||
public async Task<bool> QueryWorkModeAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 409, 1, ct);
|
||||
return result[0] == 0xFF00; // true 表示 UIR(电阻模式),false 表示 UIP
|
||||
}
|
||||
|
||||
public async Task<ushort[]> ReadUserTextAsync(byte slaveAddress = 1, int length = 40, CancellationToken ct = default)
|
||||
{
|
||||
int frameCount = (int)Math.Ceiling(length / 4.0);
|
||||
ushort[] textValues = new ushort[length];
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
ushort[] frame = await ReadHoldingRegistersAsync(slaveAddress, (ushort)(171 + i), 4, ct);
|
||||
for (int j = 0; j < frame.Length && (i * 4 + j) < length; j++)
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
TcpClient.Close();
|
||||
StopHeartbeat();
|
||||
}
|
||||
}
|
||||
// 启动设备的心跳
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null)
|
||||
return;
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
_cancellationTokenSource = new();
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
// 停止设备的心跳
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
textValues[i * 4 + j] = frame[j];
|
||||
await 设置远程控制(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
if (MaxReconnectAttempts < ReConnectionAttempts)
|
||||
{
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool resultConnect = await ConnectAsync(ct);
|
||||
if (resultConnect)
|
||||
{
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
return textValues;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 二、电压 / 电流 / 功率 / 电阻设定值寄存器
|
||||
|
||||
public async Task SetVoltageAsync(double voltage, double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询设备信息
|
||||
public virtual async Task<string> 查询设备信息(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(voltage / ratedVoltage * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 500, value, ct);
|
||||
return await WriteReadAsync($"*IDN?\r\n", "\n", ct: ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 重置设备
|
||||
public virtual async Task 重置设备(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 500, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedVoltage;
|
||||
await SendAsync($"*RST\r\n", ct);
|
||||
}
|
||||
public virtual async Task 清除保护状态(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"OUTPut:PROTection:CLEar\r\n", ct);
|
||||
}
|
||||
// 打开输出
|
||||
public virtual async Task 打开输出(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"OUTPut ON\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetCurrentAsync(double current, double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 关闭输出
|
||||
public virtual async Task 关闭输出(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(current / ratedCurrent * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 501, value, ct);
|
||||
await SendAsync($"OUTPut OFF\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetCurrentAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置远程控制
|
||||
public virtual async Task 设置远程控制(bool 激活, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 501, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedCurrent;
|
||||
await SendAsync($"SYSTem:LOCK {(激活 ? "ON" : "OFF")}\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetPowerAsync(double power, double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询远程控制状态
|
||||
public virtual async Task<string> 查询远程控制状态(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(power / ratedPower * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 502, value, ct);
|
||||
return await WriteReadAsync($"SYSTem:LOCK:OWNer?\r\n", "\n", ct: ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetPowerAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置电压
|
||||
public virtual async Task 设置电压(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 502, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedPower;
|
||||
await SendAsync($"SOURce:VOLTage {电压}V\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetResistanceAsync(double resistance, double maxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置电流
|
||||
public virtual async Task 设置电流(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(resistance / maxResistance * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 503, value, ct);
|
||||
await SendAsync($"SOURce:CURRent {电流}A\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetResistanceAsync(double maxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置功率
|
||||
public virtual async Task 设置功率(double 功率, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 503, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * maxResistance;
|
||||
await SendAsync($"SOURce:POWer {功率}W\r\n", ct);
|
||||
}
|
||||
|
||||
// sink 模式示例写方法
|
||||
public async Task SetSinkPowerAsync(double power, double sinkRatedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置电阻
|
||||
public virtual async Task 设置电阻(double 电阻, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(power / sinkRatedPower * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 498, value, ct);
|
||||
await SendAsync($"SOURce:RESistance {电阻}Ω\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetSinkCurrentAsync(double current, double sinkRatedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置过压保护
|
||||
public virtual async Task 设置过压保护(double 电压, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(current / sinkRatedCurrent * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 499, value, ct);
|
||||
await SendAsync($"SOURce:VOLTage:PROTection {电压}V\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task SetSinkResistanceAsync(double resistance, double sinkMaxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置过流保护
|
||||
public virtual async Task 设置过流保护(double 电流, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(resistance / sinkMaxResistance * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 504, value, ct);
|
||||
await SendAsync($"SOURce:CURRent:PROTection {电流}A\r\n", ct);
|
||||
}
|
||||
|
||||
// 读方法
|
||||
public async Task<double> GetSinkPowerAsync(double sinkRatedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置过功率保护
|
||||
public virtual async Task 设置过功率保护(double 功率, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 498, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * sinkRatedPower;
|
||||
await SendAsync($"SOURce:POWer:PROTection {功率}W\r\n", ct);
|
||||
}
|
||||
|
||||
public async Task<double> GetSinkCurrentAsync(double sinkRatedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询电压
|
||||
public virtual async Task<double> 查询电压(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 499, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * sinkRatedCurrent;
|
||||
var str = await WriteReadAsync($"MEASure:VOLTage?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
public async Task<double> GetSinkResistanceAsync(double sinkMaxResistance, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询电流
|
||||
public virtual async Task<double> 查询电流(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 504, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * sinkMaxResistance;
|
||||
var str = await WriteReadAsync($"MEASure:CURRent?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 三、设备状态与实际值查询寄存器
|
||||
|
||||
/// <summary>
|
||||
/// 读取设备状态寄存器(32 位)
|
||||
/// Bit 7:DC 输出/输入开启
|
||||
/// Bit 10:远程控制激活
|
||||
/// Bit 12:sink 模式
|
||||
/// </summary>
|
||||
public async Task<uint> ReadDeviceStatusAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询功率
|
||||
public virtual async Task<double> 查询功率(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 505, 2, ct); // 32位寄存器 = 2 x 16位
|
||||
return (uint)(reg[0] << 16 | reg[1]);
|
||||
var str = await WriteReadAsync($"MEASure:POWer?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
public async Task<bool> IsDcOnAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 批量查询电压、电流、功率
|
||||
public virtual async Task<(double 电压, double 电流, double 功率)> 查询批量数据(CancellationToken ct = default)
|
||||
{
|
||||
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
|
||||
return (status & (1 << 7)) != 0;
|
||||
var str = await WriteReadAsync($"MEASure:ARRay?\r\n", "\n", ct: ct);
|
||||
var values = str.Split(',');
|
||||
return (
|
||||
Convert.ToDouble(values[0]),
|
||||
Convert.ToDouble(values[1]),
|
||||
Convert.ToDouble(values[2])
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<bool> IsRemoteActiveAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询标称电压
|
||||
public virtual async Task<double> 查询标称电压(CancellationToken ct = default)
|
||||
{
|
||||
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
|
||||
return (status & (1 << 10)) != 0;
|
||||
var str = await WriteReadAsync($"SYSTem:NOMinal:VOLTage?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
|
||||
public async Task<bool> IsSinkModeActiveAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询标称电流
|
||||
public virtual async Task<double> 查询标称电流(CancellationToken ct = default)
|
||||
{
|
||||
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
|
||||
return (status & (1 << 12)) != 0;
|
||||
var str = await WriteReadAsync($"SYSTem:NOMinal:CURRent?\r\n", "\n", ct: ct);
|
||||
return Convert.ToDouble(str);
|
||||
}
|
||||
#region 多通道支持
|
||||
// 激活指定通道
|
||||
public virtual async Task 激活通道(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"INST:SEL CH{通道号}\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取实际电压值(单位 V)
|
||||
/// 公式: 实际值 = 寄存器值 / 0xCCCC * 额定电压
|
||||
/// </summary>
|
||||
public async Task<double> ReadActualVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询当前激活的通道
|
||||
public virtual async Task<string> 查询当前激活通道(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 507, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedVoltage;
|
||||
return await WriteReadAsync($"INST:SEL?\r\n", "\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取实际电流值(单位 A)
|
||||
/// sink 模式下可能为负值,需要根据 Bit 12 判断
|
||||
/// </summary>
|
||||
public async Task<double> ReadActualCurrentAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 激活所有通道
|
||||
public virtual async Task 激活所有通道(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 508, 1, ct);
|
||||
double current = reg[0] / (double)0xCCCC * ratedCurrent;
|
||||
|
||||
if (await IsSinkModeActiveAsync(slaveAddress, ct))
|
||||
current = -current; // sink 模式电流为负
|
||||
|
||||
return current;
|
||||
await SendAsync("INST:SEL ALL\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取实际功率值(单位 W)
|
||||
/// sink 模式下可能为负值
|
||||
/// </summary>
|
||||
public async Task<double> ReadActualPowerAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置指定通道电压
|
||||
public virtual async Task 设置通道电压(int 通道号, double 电压, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 509, 1, ct);
|
||||
double power = reg[0] / (double)0xCCCC * ratedPower;
|
||||
|
||||
if (await IsSinkModeActiveAsync(slaveAddress, ct))
|
||||
power = -power;
|
||||
|
||||
return power;
|
||||
await SendAsync($"CH{通道号}:VOLT {电压}V\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取额定电压(IEEE 754 float)
|
||||
/// </summary>
|
||||
public async Task<float> ReadRatedVoltageAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置指定通道电流
|
||||
public virtual async Task 设置通道电流(int 通道号, double 电流, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 121, 2, ct);
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte)(reg[1] & 0xFF);
|
||||
bytes[1] = (byte)(reg[1] >> 8);
|
||||
bytes[2] = (byte)(reg[0] & 0xFF);
|
||||
bytes[3] = (byte)(reg[0] >> 8);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
await SendAsync($"CH{通道号}:CURR {电流}A\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取额定电流(IEEE 754 float)
|
||||
/// </summary>
|
||||
public async Task<float> ReadRatedCurrentAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置指定通道功率
|
||||
public virtual async Task 设置通道功率(int 通道号, double 功率, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 122, 2, ct);
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte)(reg[1] & 0xFF);
|
||||
bytes[1] = (byte)(reg[1] >> 8);
|
||||
bytes[2] = (byte)(reg[0] & 0xFF);
|
||||
bytes[3] = (byte)(reg[0] >> 8);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
await SendAsync($"CH{通道号}:POW {功率}W\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取额定功率(IEEE 754 float)
|
||||
/// </summary>
|
||||
public async Task<float> ReadRatedPowerAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 设置指定通道 Sink 模式电流
|
||||
public virtual async Task 设置通道Sink电流(int 通道号, double 电流, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 123, 2, ct);
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte)(reg[1] & 0xFF);
|
||||
bytes[1] = (byte)(reg[1] >> 8);
|
||||
bytes[2] = (byte)(reg[0] & 0xFF);
|
||||
bytes[3] = (byte)(reg[0] >> 8);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
await SendAsync($"CH{通道号}:SINK:CURR {电流}A\r\n", ct);
|
||||
}
|
||||
// 启动指定通道输出
|
||||
public virtual async Task 启动通道输出(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"CH{通道号}:OUTP ON\r\n", ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 四、保护与报警相关寄存器
|
||||
|
||||
/// <summary>
|
||||
/// 设置过压保护(OVP)阈值
|
||||
/// </summary>
|
||||
public async Task SetOverVoltageLimitAsync(double voltage, double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 关闭指定通道输出
|
||||
public virtual async Task 关闭通道输出(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(voltage / ratedVoltage * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 510, value, ct);
|
||||
await SendAsync($"CH{通道号}:OUTP OFF\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过压保护(OVP)阈值
|
||||
/// </summary>
|
||||
public async Task<double> ReadOverVoltageLimitAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 同时启停所有通道输出
|
||||
public virtual async Task 同步启动所有通道输出(CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 510, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedVoltage;
|
||||
await SendAsync("INST:ALL:OUTP ON\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置过流保护(OCP)阈值
|
||||
/// </summary>
|
||||
public async Task SetOverCurrentLimitAsync(double current, double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
public virtual async Task 同步关闭所有通道输出(CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(current / ratedCurrent * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 511, value, ct);
|
||||
await SendAsync("INST:ALL:OUTP OFF\r\n", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过流保护(OCP)阈值
|
||||
/// </summary>
|
||||
public async Task<double> ReadOverCurrentLimitAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
// 查询指定通道的电压、电流和功率(批量)
|
||||
public virtual async Task<(double 电压, double 电流, double 功率)> 查询通道批量数据(int 通道号, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 511, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedCurrent;
|
||||
var str = await WriteReadAsync($"CH{通道号}:MEAS:ARR?\r\n", "\n", ct);
|
||||
var values = str.Split(',');
|
||||
return (
|
||||
Convert.ToDouble(values[0]), // 电压
|
||||
Convert.ToDouble(values[1]), // 电流
|
||||
Convert.ToDouble(values[2]) // 功率
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置过功率保护(OPP)阈值
|
||||
/// </summary>
|
||||
public async Task SetOverPowerLimitAsync(double power, double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = (ushort)(power / ratedPower * 0xCCCC);
|
||||
await WriteSingleRegisterAsync(slaveAddress, 512, value, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过功率保护(OPP)阈值
|
||||
/// </summary>
|
||||
public async Task<double> ReadOverPowerLimitAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 512, 1, ct);
|
||||
return reg[0] / (double)0xCCCC * ratedPower;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 OVP 报警计数器,读取后复位
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOVPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 520, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 OCP 报警计数器
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOCPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 521, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取 OPP 报警计数器
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOPPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 522, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取过温(OT)报警计数器
|
||||
/// </summary>
|
||||
public async Task<ushort> ReadOTCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 523, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 五、函数发生器与特殊功能寄存器
|
||||
|
||||
// 寄存器 850:函数发生器启动/停止
|
||||
public async Task SetFunctionGeneratorAsync(bool start, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort value = start ? (ushort)0xFF00 : (ushort)0x0000;
|
||||
await WriteSingleRegisterAsync(slaveAddress, 850, value, ct);
|
||||
}
|
||||
|
||||
public async Task<bool> ReadFunctionGeneratorAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 850, 1, ct);
|
||||
return reg[0] == 0xFF00;
|
||||
}
|
||||
|
||||
// 寄存器 851:函数发生器作用于电压
|
||||
public async Task SetFunctionVoltageParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(slaveAddress, 851, 0xFF00, ct);
|
||||
}
|
||||
|
||||
public async Task<bool> ReadFunctionVoltageParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 851, 1, ct);
|
||||
return reg[0] == 0xFF00;
|
||||
}
|
||||
|
||||
// 寄存器 852:函数发生器作用于电流
|
||||
public async Task SetFunctionCurrentParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(slaveAddress, 852, 0xFF00, ct);
|
||||
}
|
||||
|
||||
public async Task<bool> ReadFunctionCurrentParamAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 852, 1, ct);
|
||||
return reg[0] == 0xFF00;
|
||||
}
|
||||
|
||||
// 寄存器 859~861:序列控制
|
||||
public async Task SetSequenceStartPointAsync(ushort startPoint, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (startPoint < 1 || startPoint > 99) throw new ArgumentOutOfRangeException(nameof(startPoint));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 859, startPoint, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadSequenceStartPointAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 859, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
public async Task SetSequenceEndPointAsync(ushort endPoint, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (endPoint < 1 || endPoint > 99) throw new ArgumentOutOfRangeException(nameof(endPoint));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 860, endPoint, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadSequenceEndPointAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 860, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
public async Task SetSequenceLoopCountAsync(ushort loopCount, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (loopCount > 999) throw new ArgumentOutOfRangeException(nameof(loopCount));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 861, loopCount, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadSequenceLoopCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 861, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
// 寄存器 11000:MPP 跟踪模式
|
||||
public async Task SetMPPModeAsync(ushort mode, byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (mode != 0x0001 && mode != 0x0002 && mode != 0x0004) throw new ArgumentOutOfRangeException(nameof(mode));
|
||||
await WriteSingleRegisterAsync(slaveAddress, 11000, mode, ct);
|
||||
}
|
||||
|
||||
public async Task<ushort> ReadMPPModeAsync(byte slaveAddress = 1, CancellationToken ct = default)
|
||||
{
|
||||
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 11000, 1, ct);
|
||||
return reg[0];
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,173 +1,203 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using System;
|
||||
using Logger;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DeviceCommand.Device
|
||||
{
|
||||
/// <summary>
|
||||
/// Sequoia SQ0030G1D 控制类(SCPI 指令封装)
|
||||
/// </summary>
|
||||
[BOBCommand]
|
||||
public class SQ0030G1D : Tcp
|
||||
{
|
||||
public SQ0030G1D()
|
||||
public SQ0030G1D(string ip, int port, int sendTimeout, int receiveTimeout)
|
||||
{
|
||||
ConfigureDevice("127.0.0.1", 502, 3000, 3000);
|
||||
ConnectAsync();
|
||||
ConfigureDevice(ip, port, sendTimeout, receiveTimeout);
|
||||
}
|
||||
#region ========== 通用 SCPI 封装 ==========
|
||||
|
||||
/// <summary>
|
||||
/// 发送 SCPI 指令(无返回)
|
||||
/// </summary>
|
||||
protected async Task WriteAsync(string cmd, CancellationToken ct = default)
|
||||
#region 心跳
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync(cmd + "\n", ct);
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
TcpClient.Close();
|
||||
StopHeartbeat();
|
||||
}
|
||||
}
|
||||
// 启动设备的心跳
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null)
|
||||
return;
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
_cancellationTokenSource = new();
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送 SCPI 指令并读取返回
|
||||
/// </summary>
|
||||
protected async Task<string> QueryAsync(string cmd, CancellationToken ct = default)
|
||||
// 停止设备的心跳
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await 设置远程控制();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
if (MaxReconnectAttempts < ReConnectionAttempts)
|
||||
{
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool resultConnect = await ConnectAsync(ct);
|
||||
if (resultConnect)
|
||||
{
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// ===================== 基础封装 =====================
|
||||
|
||||
protected virtual Task 写命令(string cmd, CancellationToken ct = default)
|
||||
=> SendAsync(cmd + "\n", ct);
|
||||
|
||||
protected virtual async Task<string> 查询命令(string cmd, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync(cmd + "\n", ct);
|
||||
return await ReadAsync(ct: ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
// ===================== 1. 基础控制 =====================
|
||||
|
||||
#region ========== 一、设备基础控制 ==========
|
||||
|
||||
/// <summary>
|
||||
/// 查询设备标识 (*IDN?)
|
||||
/// </summary>
|
||||
public async Task<string> GetIdAsync(CancellationToken ct = default)
|
||||
=> await QueryAsync("*IDN?", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 恢复出厂设置(*RST)
|
||||
/// </summary>
|
||||
public async Task ResetAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("*RST", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 保存参数到内存 (*SAV n)
|
||||
/// </summary>
|
||||
public async Task SavePresetAsync(int index, CancellationToken ct = default)
|
||||
=> await WriteAsync($"*SAV {index}", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 从内存调用参数 (*RCL n)
|
||||
/// </summary>
|
||||
public async Task RecallPresetAsync(int index, CancellationToken ct = default)
|
||||
=> await WriteAsync($"*RCL {index}", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 切换到本地模式(SYST:LOC)
|
||||
/// </summary>
|
||||
public async Task SetLocalAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("SYST:LOC", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 切换到远程模式(SYST:REM)
|
||||
/// </summary>
|
||||
public async Task SetRemoteAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("SYST:REM", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 控制输出开关(ON/OFF)
|
||||
/// </summary>
|
||||
public async Task SetOutputAsync(bool on, CancellationToken ct = default)
|
||||
=> await WriteAsync($"OUTP:STAT {(on ? "ON" : "OFF")}", ct);
|
||||
|
||||
/// <summary>
|
||||
/// 查询输出状态(返回 true 表示 ON)
|
||||
/// </summary>
|
||||
public async Task<bool> GetOutputAsync(CancellationToken ct = default)
|
||||
=> (await QueryAsync("OUTP:STAT?", ct)).Trim().ToUpper() == "ON";
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 二、电压控制 ==========
|
||||
|
||||
public async Task SetVoltageAsync(double voltage, CancellationToken ct = default)
|
||||
=> await WriteAsync($"VOLT {voltage}", ct);
|
||||
|
||||
public async Task<double> GetVoltageSettingAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("VOLT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public async Task SetVoltageOffsetAsync(double value, CancellationToken ct = default)
|
||||
=> await WriteAsync($"VOLT:OFFS {value}", ct);
|
||||
|
||||
public async Task<double> GetVoltageOffsetAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("VOLT:OFFS?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public async Task SetVoltageMaxAsync(double value, CancellationToken ct = default)
|
||||
=> await WriteAsync($"VOLT:MAX {value}", ct);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 三、电流控制 ==========
|
||||
|
||||
public async Task SetCurrentAsync(double current, CancellationToken ct = default)
|
||||
=> await WriteAsync($"CURR {current}", ct);
|
||||
|
||||
public async Task<double> GetCurrentSettingAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("CURR?", ct)).Replace("A", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public async Task SetRegenerativeLimitAsync(double value, CancellationToken ct = default)
|
||||
=> await WriteAsync($"CURR:REG {value}", ct);
|
||||
|
||||
public async Task<double> GetRegenerativeLimitAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("CURR:REG?", ct)).Replace("A", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 四、频率控制 ==========
|
||||
|
||||
public async Task SetFrequencyAsync(double freq, CancellationToken ct = default)
|
||||
=> await WriteAsync($"FREQ {freq}", ct);
|
||||
|
||||
public async Task<double> GetFrequencyAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("FREQ?", ct)).Replace("Hz", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 五、功率控制 ==========
|
||||
|
||||
public async Task SetPowerAsync(double power, CancellationToken ct = default)
|
||||
=> await WriteAsync($"POW {power}", ct);
|
||||
|
||||
public async Task<double> GetPowerSettingAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("POW?", ct)).Replace("W", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public async Task SetReactivePowerAsync(double var, CancellationToken ct = default)
|
||||
=> await WriteAsync($"POW:REAC {var}", ct);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 六、测量查询 ==========
|
||||
|
||||
public async Task<double> MeasureVoltageAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("MEAS:VOLT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public async Task<double> MeasureCurrentAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("MEAS:CURR?", ct)).Replace("A", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public async Task<double> MeasurePowerAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("MEAS:POW?", ct)).Replace("W", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>
|
||||
/// 同时测量电压、电流、功率
|
||||
/// </summary>
|
||||
public async Task<(double volt, double curr, double pow)> MeasureArrayAsync(CancellationToken ct = default)
|
||||
public async Task 启动电源()
|
||||
{
|
||||
string result = await QueryAsync("MEAS:ARR?", ct);
|
||||
var parts = result.Split(',');
|
||||
await 写命令($"OUTPut 1\n");
|
||||
}
|
||||
|
||||
public async Task 关闭电源()
|
||||
{
|
||||
await 写命令($"OUTPut 0\n");
|
||||
}
|
||||
|
||||
public virtual Task<string> 获取设备ID(CancellationToken ct = default)
|
||||
=> 查询命令("*IDN?", ct);
|
||||
|
||||
public virtual Task 重置设备(CancellationToken ct = default)
|
||||
=> 写命令("*RST", ct);
|
||||
|
||||
public virtual Task 设置远程控制(CancellationToken ct = default)
|
||||
=> 写命令("SYST:REM", ct);
|
||||
|
||||
public virtual Task 设置本地控制(CancellationToken ct = default)
|
||||
=> 写命令("SYST:LOC", ct);
|
||||
|
||||
public virtual Task 设置输出状态(bool on, CancellationToken ct = default)
|
||||
=> 写命令($"OUTP:STAT {(on ? "ON" : "OFF")}", ct);
|
||||
|
||||
public virtual async Task<bool> 获取输出状态(CancellationToken ct = default)
|
||||
=> (await 查询命令("OUTP:STAT?", ct)).Trim().ToUpper() == "ON";
|
||||
|
||||
// ===================== 2. 电压/频率控制 =====================
|
||||
|
||||
public virtual Task 设置输出电压(double value, CancellationToken ct = default)
|
||||
=> 写命令($"VOLT {value}", ct);
|
||||
|
||||
public virtual async Task<double> 获取输出电压(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("VOLT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public virtual async Task<double> 获取输出频率(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("FREQ?", ct)).Replace("Hz", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
// ===================== 3. 保护 =====================
|
||||
|
||||
public virtual Task 设置过压保护(double v, CancellationToken ct = default)
|
||||
=> 写命令($"VOLT:PROT {v}", ct);
|
||||
|
||||
public virtual async Task<double> 获取过压保护(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("VOLT:PROT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public virtual Task 设置过流保护(double a, CancellationToken ct = default)
|
||||
=> 写命令($"CURR:PROT {a}", ct);
|
||||
|
||||
public virtual async Task<double> 获取过流保护(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("CURR:PROT?", ct)).Replace("A", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public virtual Task 清除保护(CancellationToken ct = default)
|
||||
=> 写命令("SYST:PROT:CLE", ct);
|
||||
|
||||
// ===================== 4. 测量 =====================
|
||||
|
||||
public virtual async Task<double> 测量输出电压(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("MEAS:VOLT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public virtual async Task<double> 测量输出电流(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("MEAS:CURR?", ct)).Replace("A", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public virtual async Task<double> 测量输出功率(CancellationToken ct = default)
|
||||
=> double.Parse((await 查询命令("MEAS:POW?", ct)).Replace("W", ""), CultureInfo.InvariantCulture);
|
||||
|
||||
public virtual async Task<(double volt, double curr, double pow)> 测量所有参数(CancellationToken ct = default)
|
||||
{
|
||||
var parts = (await 查询命令("MEAS:ARR?", ct)).Split(',');
|
||||
return (
|
||||
double.Parse(parts[0].Replace("V", ""), CultureInfo.InvariantCulture),
|
||||
double.Parse(parts[1].Replace("A", ""), CultureInfo.InvariantCulture),
|
||||
@ -175,70 +205,52 @@ namespace DeviceCommand.Device
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<double> MeasureHarmonicAsync(int n, CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync($"MEAS:HARM? {n}", ct)).Replace("%", ""), CultureInfo.InvariantCulture);
|
||||
// 切换到远程控制模式
|
||||
public virtual Task 设置远程控制模式(CancellationToken ct = default)
|
||||
=> 写命令("SYST:REM", ct);
|
||||
|
||||
#endregion
|
||||
// 切换到本地控制模式
|
||||
public virtual Task 设置本地控制模式(CancellationToken ct = default)
|
||||
=> 写命令("SYST:LOC", ct);
|
||||
|
||||
#region ========== 七、保护设定 ==========
|
||||
// 设定三相电压高低档
|
||||
public virtual Task 设置三相电压高低档(int range, CancellationToken ct = default)
|
||||
=> 写命令($"OUTP:RANG {range}", ct); // 设定高低档:166(低档)/333(高档)
|
||||
|
||||
public async Task SetOVPAsync(double v, CancellationToken ct = default)
|
||||
=> await WriteAsync($"VOLT:PROT {v}", ct);
|
||||
// 设定通用输出电压
|
||||
public virtual Task 设置通用输出电压(double value, CancellationToken ct = default)
|
||||
=> 写命令($"VOLT {value}", ct);
|
||||
|
||||
public async Task<double> GetOVPAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("VOLT:PROT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture);
|
||||
// 设定三相输出电压
|
||||
public virtual Task 设置三相输出电压(double U, double V, double W, CancellationToken ct = default)
|
||||
=> 写命令($"VOLT:PHAS A, {U}, B, {V}, C, {W}", ct);
|
||||
|
||||
public async Task SetOCPAsync(double a, CancellationToken ct = default)
|
||||
=> await WriteAsync($"CURR:PROT {a}", ct);
|
||||
// 设定输出频率
|
||||
public virtual Task 设置输出频率(double freq, CancellationToken ct = default)
|
||||
=> 写命令($"FREQ {freq}", ct);
|
||||
|
||||
public async Task<double> GetOCPAsync(CancellationToken ct = default)
|
||||
=> double.Parse((await QueryAsync("CURR:PROT?", ct)).Replace("A", ""), CultureInfo.InvariantCulture);
|
||||
// 设定步阶输出电压
|
||||
public virtual Task 设置步阶输出电压(double targetVoltage, double stepTime, CancellationToken ct = default)
|
||||
=> 写命令($"TRIG:TRAN:VOLT:STEP {targetVoltage}, {stepTime}", ct);
|
||||
|
||||
public async Task<bool> GetOTPStatusAsync(CancellationToken ct = default)
|
||||
=> (await QueryAsync("SYST:PROT:OTP?", ct)).Trim().ToUpper() == "ON";
|
||||
// 设定步阶输出频率
|
||||
public virtual Task 设置步阶输出频率(double targetFrequency, double stepTime, CancellationToken ct = default)
|
||||
=> 写命令($"TRIG:TRAN:FREQ:STEP {targetFrequency}, {stepTime}", ct);
|
||||
|
||||
public async Task ClearProtectionAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("SYST:PROT:CLE", ct);
|
||||
// 设定渐变输出电压
|
||||
public virtual Task 设置渐变输出电压(double startVoltage, double endVoltage, double sweepTime, CancellationToken ct = default)
|
||||
=> 写命令($"TRIG:TRAN:VOLT:SWEEP {startVoltage}, {endVoltage}, {sweepTime}", ct);
|
||||
|
||||
#endregion
|
||||
// 设定渐变输出频率
|
||||
public virtual Task 设置渐变输出频率(double startFreq, double endFreq, double sweepTime, CancellationToken ct = default)
|
||||
=> 写命令($"TRIG:TRAN:FREQ:SWEEP {startFreq}, {endFreq}, {sweepTime}", ct);
|
||||
|
||||
#region ========== 八、电子负载 ==========
|
||||
// 设定软件启动功能起始电压与额定电压
|
||||
public virtual Task 设置软件启动功能起始电压与额定电压(double startVoltage, double ratedVoltage, CancellationToken ct = default)
|
||||
=> 写命令($"PON:VOLT {startVoltage}, {ratedVoltage}", ct);
|
||||
|
||||
public async Task SetLoadModeCurrentAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("LOAD:MODE CURR", ct);
|
||||
|
||||
public async Task SetLoadModePowerAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("LOAD:MODE POW", ct);
|
||||
|
||||
public async Task SetLoadModeRLCAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("LOAD:MODE RLC", ct);
|
||||
|
||||
public async Task SetLoadRLCResistanceAsync(double res, CancellationToken ct = default)
|
||||
=> await WriteAsync($"LOAD:RLC:RES {res}", ct);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 九、瞬态编程 ==========
|
||||
|
||||
public async Task SetTransientStateAsync(bool on, CancellationToken ct = default)
|
||||
=> await WriteAsync($"TRAN:STAT {(on ? "ON" : "OFF")}", ct);
|
||||
|
||||
public async Task SetTransientStepVoltageAsync(int step, double volt, CancellationToken ct = default)
|
||||
=> await WriteAsync($"TRAN:STEP {step}:VOLT {volt}", ct);
|
||||
|
||||
public async Task RunTransientAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("TRAN:RUN", ct);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== 十、多设备同步 ==========
|
||||
|
||||
public async Task SetSyncSourceExternalAsync(CancellationToken ct = default)
|
||||
=> await WriteAsync("SYNC:SOUR EXT", ct);
|
||||
|
||||
public async Task<string> GetSyncStatusAsync(CancellationToken ct = default)
|
||||
=> await QueryAsync("SYNC:STAT?", ct);
|
||||
|
||||
#endregion
|
||||
// 设定软件启动功能起始电压与起始频率
|
||||
public virtual Task 设置软件启动功能起始电压与起始频率(double startVoltage, double startFrequency, CancellationToken ct = default)
|
||||
=> 写命令($"PON:FREQ {startVoltage}, {startFrequency}", ct);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using Common.Attributes;
|
||||
using DeviceCommand.Base;
|
||||
using Logger;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -9,129 +10,142 @@ namespace DeviceCommand.Device
|
||||
[BOBCommand]
|
||||
public class WS_68030_380T : ModbusTcp
|
||||
{
|
||||
public WS_68030_380T()
|
||||
public WS_68030_380T(string IpAddress, int port, int SendTimeout, int ReceiveTimeout)
|
||||
{
|
||||
ConfigureDevice("127.0.0.1", 502, 3000, 3000);
|
||||
ConnectAsync();
|
||||
ConfigureDevice(IpAddress, port, SendTimeout, ReceiveTimeout);
|
||||
}
|
||||
#region 心跳
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task? _heartbeatTask;
|
||||
private const int HeartbeatInterval = 3000;
|
||||
public bool IsActive = false;
|
||||
public int ReConnectionAttempts = 0;
|
||||
public const int MaxReconnectAttempts = 10;
|
||||
public override async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (TcpClient != null && !TcpClient.Connected) TcpClient = new();
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
await TcpClient.ConnectAsync(IPAddress, Port, ct);
|
||||
IsActive = true;
|
||||
StartHeartbeat();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commLock.Release();
|
||||
}
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
if (!TcpClient.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("TCP 没有连接成功");
|
||||
}
|
||||
if (TcpClient.Connected)
|
||||
{
|
||||
TcpClient.Close();
|
||||
StopHeartbeat();
|
||||
}
|
||||
}
|
||||
// 启动设备的心跳
|
||||
public void StartHeartbeat()
|
||||
{
|
||||
if (_heartbeatTask != null)
|
||||
return;
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
_cancellationTokenSource = new();
|
||||
_heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
// 停止设备的心跳
|
||||
public void StopHeartbeat()
|
||||
{
|
||||
IsActive = false;
|
||||
_cancellationTokenSource.Cancel();
|
||||
_heartbeatTask = null;
|
||||
}
|
||||
|
||||
private async Task HeartbeatLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(HeartbeatInterval, ct);
|
||||
|
||||
try
|
||||
{
|
||||
await WriteSingleRegisterAsync(1,0,1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsActive = false;
|
||||
ReConnectionAttempts++;
|
||||
if (MaxReconnectAttempts < ReConnectionAttempts)
|
||||
{
|
||||
StopHeartbeat();
|
||||
return;
|
||||
}
|
||||
await ReconnectDevice(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ReconnectDevice(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool resultConnect = await ConnectAsync(ct);
|
||||
if (resultConnect)
|
||||
{
|
||||
ReConnectionAttempts = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const byte SlaveAddress = 1;
|
||||
|
||||
#region 设置模式
|
||||
public async Task Set_Mode_LocalAuto(CancellationToken ct = default)
|
||||
|
||||
public virtual async Task 设置功率_KW(float 功率, CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 51, 0, ct);
|
||||
var send = ConvertFromFloat(功率);
|
||||
await WriteMultipleRegistersAsync(1, 58, send).WaitAsync(ct);
|
||||
}
|
||||
|
||||
public async Task Set_Mode_LocalManual(CancellationToken ct = default)
|
||||
public virtual async Task 加载(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 51, 1, ct);
|
||||
var tmp = new ushort();
|
||||
ushort send = (ushort)(tmp | (1 << 8));
|
||||
await WriteSingleRegisterAsync(1, 70, send).WaitAsync(ct);
|
||||
}
|
||||
|
||||
public async Task Set_Mode_ATEControl(CancellationToken ct = default)
|
||||
public virtual async Task 卸载(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 51, 2, ct);
|
||||
await WriteSingleRegisterAsync(1, 70, new()).WaitAsync(ct);
|
||||
}
|
||||
|
||||
public async Task Set_AlarmMute(CancellationToken ct = default)
|
||||
public virtual async Task<float> 读取功率_KW(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 52, 1, ct);
|
||||
var re = await ReadHoldingRegistersAsync(1, 58, 2).WaitAsync(ct);
|
||||
return ConvertToFloat(re);
|
||||
}
|
||||
|
||||
public async Task Set_FaultReset(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 53, 1, ct);
|
||||
}
|
||||
|
||||
public async Task Set_SystemStop(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 54, 1, ct);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 负载模式
|
||||
public async Task Set_ATE_Load_CurrentMode(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 100, 0, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_PowerMode(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 100, 1, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_Uninstall(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 103, 0, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_Load(CancellationToken ct = default)
|
||||
{
|
||||
await WriteSingleRegisterAsync(SlaveAddress, 103, 1, ct);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设置电流/功率
|
||||
public async Task Set_ATE_Load_A_Current(float current, CancellationToken ct = default)
|
||||
{
|
||||
var regs = ConvertFromFloat(current);
|
||||
await WriteMultipleRegistersAsync(SlaveAddress, 105, regs, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_A_Power(float power, CancellationToken ct = default)
|
||||
{
|
||||
var regs = ConvertFromFloat(power);
|
||||
await WriteMultipleRegistersAsync(SlaveAddress, 109, regs, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_B_Current(float current, CancellationToken ct = default)
|
||||
{
|
||||
var regs = ConvertFromFloat(current);
|
||||
await WriteMultipleRegistersAsync(SlaveAddress, 115, regs, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_B_Power(float power, CancellationToken ct = default)
|
||||
{
|
||||
var regs = ConvertFromFloat(power);
|
||||
await WriteMultipleRegistersAsync(SlaveAddress, 119, regs, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_C_Current(float current, CancellationToken ct = default)
|
||||
{
|
||||
var regs = ConvertFromFloat(current);
|
||||
await WriteMultipleRegistersAsync(SlaveAddress, 125, regs, ct);
|
||||
}
|
||||
|
||||
public async Task Set_ATE_Load_C_Power(float power, CancellationToken ct = default)
|
||||
{
|
||||
var regs = ConvertFromFloat(power);
|
||||
await WriteMultipleRegistersAsync(SlaveAddress, 129, regs, ct);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 查询
|
||||
public async Task<float> Get_A_Voltage(CancellationToken ct = default)
|
||||
{
|
||||
var regs = await ReadHoldingRegistersAsync(SlaveAddress, 150, 2, ct);
|
||||
return ConvertToFloat(regs);
|
||||
}
|
||||
|
||||
public async Task<float> Get_A_Current(CancellationToken ct = default)
|
||||
{
|
||||
var regs = await ReadHoldingRegistersAsync(SlaveAddress, 152, 2, ct);
|
||||
return ConvertToFloat(regs);
|
||||
}
|
||||
|
||||
public async Task<float> Get_A_ActivePower(CancellationToken ct = default)
|
||||
{
|
||||
var regs = await ReadHoldingRegistersAsync(SlaveAddress, 154, 2, ct);
|
||||
return ConvertToFloat(regs);
|
||||
}
|
||||
|
||||
// …同理其他相和三相测量,直接调用基类 ReadHoldingRegistersAsync
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
private float ConvertToFloat(ushort[] values)
|
||||
protected float ConvertToFloat(ushort[] values)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[3] = (byte)(values[0] >> 8);
|
||||
@ -141,7 +155,7 @@ namespace DeviceCommand.Device
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
private ushort[] ConvertFromFloat(float value)
|
||||
protected ushort[] ConvertFromFloat(float value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
return new ushort[]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user