Initial Push
This commit is contained in:
63
ads-wrapper/.gitattributes
vendored
Normal file
63
ads-wrapper/.gitattributes
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
||||||
363
ads-wrapper/.gitignore
vendored
Normal file
363
ads-wrapper/.gitignore
vendored
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
331
ads-wrapper/AdsManager.cs
Normal file
331
ads-wrapper/AdsManager.cs
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Timers;
|
||||||
|
using TwinCAT;
|
||||||
|
using TwinCAT.Ads;
|
||||||
|
using TwinCAT.Ads.TypeSystem;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
|
||||||
|
namespace Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
// AdsManager Interface for dependency injection
|
||||||
|
public interface IAdsManager
|
||||||
|
{
|
||||||
|
public void Register(string variableName, EventHandler<ValueChangedEventArgs> eventHandler);
|
||||||
|
|
||||||
|
public void Deregister(string variableName, EventHandler<ValueChangedEventArgs> eventHandler);
|
||||||
|
|
||||||
|
public void WriteValue(string variableName, object value);
|
||||||
|
|
||||||
|
public object? ReadValue(string variableName);
|
||||||
|
|
||||||
|
public ISymbolLoader? GetSymbolLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class AdsManager : IDisposable, IAdsManager
|
||||||
|
{
|
||||||
|
enum ConnectionState
|
||||||
|
{
|
||||||
|
DISCONNECTED,
|
||||||
|
CONNECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ads client instance
|
||||||
|
private readonly AdsClient _adsClient = new();
|
||||||
|
|
||||||
|
// Ads symbol loader
|
||||||
|
private ISymbolLoader? _symbolLoader;
|
||||||
|
|
||||||
|
// Last value of online change count
|
||||||
|
private uint? _lastOnlineChangeCount = null;
|
||||||
|
|
||||||
|
// Online change detected
|
||||||
|
private bool _onlineChangeDetected = false;
|
||||||
|
|
||||||
|
// Dictionary with symbols and events for variable changing events
|
||||||
|
private readonly Dictionary<string, List<EventHandler<ValueChangedEventArgs>>> _test = [];
|
||||||
|
|
||||||
|
// Timer to test cyclically if we are still connected
|
||||||
|
private readonly System.Timers.Timer _timer = new();
|
||||||
|
|
||||||
|
// Internal connection state
|
||||||
|
private ConnectionState _state = ConnectionState.DISCONNECTED;
|
||||||
|
|
||||||
|
// Filename with the connection settings
|
||||||
|
private const string _filename = "AdsSettings.json";
|
||||||
|
|
||||||
|
// Settings for the connection
|
||||||
|
private readonly AdsSettings _settings = new();
|
||||||
|
|
||||||
|
// Thread safety lock
|
||||||
|
private static readonly object _lock = new();
|
||||||
|
|
||||||
|
// Json serializer options
|
||||||
|
private readonly JsonSerializerOptions _jsonOptions = new() { WriteIndented = true };
|
||||||
|
|
||||||
|
public AdsManager()
|
||||||
|
{
|
||||||
|
// Read settings file
|
||||||
|
_settings = ReadSettings();
|
||||||
|
|
||||||
|
// Start cyclic connection test
|
||||||
|
_timer.Interval = _settings.ReconnectIntervalMS;
|
||||||
|
_timer.Elapsed += CheckConnection;
|
||||||
|
_timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_timer.Stop();
|
||||||
|
_timer.Dispose();
|
||||||
|
|
||||||
|
_adsClient.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteSettings(AdsSettings settings)
|
||||||
|
{
|
||||||
|
string text = JsonSerializer.Serialize(settings, _jsonOptions);
|
||||||
|
File.WriteAllText(_filename, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AdsSettings ReadSettings()
|
||||||
|
{
|
||||||
|
AdsSettings settings = new();
|
||||||
|
string text;
|
||||||
|
|
||||||
|
if (!File.Exists(_filename))
|
||||||
|
WriteSettings(settings);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = File.ReadAllText(_filename);
|
||||||
|
settings = JsonSerializer.Deserialize<AdsSettings>(text) ?? new AdsSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a callback on variable change
|
||||||
|
public void Register(string variableName, EventHandler<ValueChangedEventArgs> eventHandler)
|
||||||
|
{
|
||||||
|
List<EventHandler<ValueChangedEventArgs>> tempList;
|
||||||
|
|
||||||
|
// Add new variable entry
|
||||||
|
#pragma warning disable CA1854 // Methode „IDictionary.TryGetValue(TKey, out TValue)“ bevorzugen
|
||||||
|
if (!_test.ContainsKey(variableName))
|
||||||
|
#pragma warning restore CA1854 // Methode „IDictionary.TryGetValue(TKey, out TValue)“ bevorzugen
|
||||||
|
{
|
||||||
|
// Add new entry
|
||||||
|
tempList = [eventHandler];
|
||||||
|
_test.Add(variableName, tempList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Append event to variable
|
||||||
|
tempList = _test[variableName];
|
||||||
|
foreach (EventHandler<ValueChangedEventArgs> handler in tempList)
|
||||||
|
{
|
||||||
|
if (handler == eventHandler)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tempList.Add(eventHandler);
|
||||||
|
_test[variableName] = tempList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are already connected, directly register variable
|
||||||
|
if (_state == ConnectionState.CONNECTED)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Symbol? symbol = (Symbol?)_symbolLoader?.Symbols[variableName];
|
||||||
|
if (symbol != null)
|
||||||
|
symbol.ValueChanged += eventHandler;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Variable {variableName} could not be found");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"Variable {variableName} registered");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a registration from the dictionary
|
||||||
|
public void Deregister(string variableName, EventHandler<ValueChangedEventArgs> eventHandler)
|
||||||
|
{
|
||||||
|
List<EventHandler<ValueChangedEventArgs>>? tempList;
|
||||||
|
bool eventRemoved = false;
|
||||||
|
|
||||||
|
if (_test.TryGetValue(variableName, out tempList))
|
||||||
|
{
|
||||||
|
foreach (EventHandler<ValueChangedEventArgs> handler in tempList)
|
||||||
|
{
|
||||||
|
if (handler == eventHandler)
|
||||||
|
{
|
||||||
|
tempList.Remove(eventHandler);
|
||||||
|
|
||||||
|
// If we are connected remove directly remove variable changed event
|
||||||
|
if (_state == ConnectionState.CONNECTED)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Symbol? symbol = (Symbol?)_symbolLoader?.Symbols[variableName];
|
||||||
|
if (symbol != null)
|
||||||
|
symbol.ValueChanged -= eventHandler;
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Variable {variableName} could not be found and deregistered");
|
||||||
|
}
|
||||||
|
Console.WriteLine("Variable {0} deregistered", variableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (eventRemoved)
|
||||||
|
_test[variableName] = tempList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterValueChangedEvents()
|
||||||
|
{
|
||||||
|
if (_symbolLoader == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Symbol symbol;
|
||||||
|
foreach(KeyValuePair<string, List<EventHandler<ValueChangedEventArgs>>> entry in _test)
|
||||||
|
{
|
||||||
|
symbol = (Symbol)_symbolLoader.Symbols[entry.Key];
|
||||||
|
foreach (EventHandler<ValueChangedEventArgs> handler in entry.Value)
|
||||||
|
symbol.ValueChanged += handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteValue(string variableName, object value)
|
||||||
|
{
|
||||||
|
if (_state == ConnectionState.CONNECTED)
|
||||||
|
{
|
||||||
|
_adsClient.TryWriteValue(variableName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? ReadValue(string variableName)
|
||||||
|
{
|
||||||
|
if (_state == ConnectionState.CONNECTED)
|
||||||
|
{
|
||||||
|
_adsClient.TryReadValue(variableName, out object? value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cyclic check if we are still connected to the ads server
|
||||||
|
private void CheckConnection(object? sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
lock(_lock)
|
||||||
|
{
|
||||||
|
// Stop timer
|
||||||
|
_timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case ConnectionState.DISCONNECTED:
|
||||||
|
// Connect if not already connected
|
||||||
|
if (!_adsClient.IsConnected)
|
||||||
|
_adsClient.Connect(_settings.AdsAdress, _settings.AdsPort);
|
||||||
|
|
||||||
|
// Check if we have a connection
|
||||||
|
if (TestIfConnected())
|
||||||
|
{
|
||||||
|
Console.WriteLine("Connected");
|
||||||
|
Console.WriteLine("Reading Symbols ...");
|
||||||
|
|
||||||
|
// Load ads symbols
|
||||||
|
_symbolLoader = SymbolLoaderFactory.Create(_adsClient, SymbolLoaderSettings.Default);
|
||||||
|
|
||||||
|
Console.WriteLine("{0} Symbols read", _symbolLoader.Symbols.Count);
|
||||||
|
|
||||||
|
// Read last online change count
|
||||||
|
lock(_lock)
|
||||||
|
{
|
||||||
|
_lastOnlineChangeCount = (uint)((Symbol)_symbolLoader.Symbols[_settings.OnlineChangeCntVar]).ReadValue();
|
||||||
|
|
||||||
|
// Change state to connected
|
||||||
|
_state = ConnectionState.CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register value changed events
|
||||||
|
RegisterValueChangedEvents();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ConnectionState.CONNECTED:
|
||||||
|
if (!TestIfConnected())
|
||||||
|
{
|
||||||
|
Console.WriteLine("Connection lost");
|
||||||
|
lock (_lock)
|
||||||
|
_state = ConnectionState.DISCONNECTED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
uint onlineChangeCnt = (uint)((Symbol)_symbolLoader!.Symbols[_settings.OnlineChangeCntVar]).ReadValue();
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_onlineChangeDetected = false;
|
||||||
|
if (onlineChangeCnt != _lastOnlineChangeCount)
|
||||||
|
_onlineChangeDetected = true;
|
||||||
|
_lastOnlineChangeCount = (uint)((Symbol)_symbolLoader.Symbols[_settings.OnlineChangeCntVar]).ReadValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reread symbols
|
||||||
|
if (_onlineChangeDetected)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Online change detected. Rereading symbols ...");
|
||||||
|
_symbolLoader = SymbolLoaderFactory.Create(_adsClient, SymbolLoaderSettings.Default);
|
||||||
|
Console.WriteLine("{0} Symbols read", _symbolLoader.Symbols.Count);
|
||||||
|
RegisterValueChangedEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Could not read online change count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
// Restart timer
|
||||||
|
_timer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TestIfConnected()
|
||||||
|
{
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
// Test if connection could be established and is still alive
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Read ads server status
|
||||||
|
StateInfo state = _adsClient.ReadState();
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
catch (AdsErrorException)
|
||||||
|
{
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISymbolLoader? GetSymbolLoader()
|
||||||
|
{
|
||||||
|
return _symbolLoader;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
ads-wrapper/AdsManager.csproj
Normal file
29
ads-wrapper/AdsManager.csproj
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
|
<Title>Ads Manager</Title>
|
||||||
|
<Authors>M.Heisig</Authors>
|
||||||
|
<Company>Heisig GmbH</Company>
|
||||||
|
<Description>Wrapper für den Ads Client von Beckhoff um automatische reconnects und onlinechanges zu behandeln.</Description>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<PackageOutputPath>C:\Users\matthias.heisig\Documents\nuget_packages</PackageOutputPath>
|
||||||
|
<PackageProjectUrl>https://gitlab.cmblu.de/matthias.heisig/ads-wrapper</PackageProjectUrl>
|
||||||
|
<Version>1.0.0.7</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Beckhoff.TwinCAT.Ads" Version="6.1.197" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="README.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath>\</PackagePath>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
25
ads-wrapper/AdsManager.sln
Normal file
25
ads-wrapper/AdsManager.sln
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.8.34525.116
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdsManager", "AdsManager.csproj", "{4B80F068-4E6D-4D2D-831B-8150970600C7}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{4B80F068-4E6D-4D2D-831B-8150970600C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4B80F068-4E6D-4D2D-831B-8150970600C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4B80F068-4E6D-4D2D-831B-8150970600C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4B80F068-4E6D-4D2D-831B-8150970600C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {32AA8544-D809-4C87-81DE-505FDD964D85}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
27
ads-wrapper/AdsSettings.cs
Normal file
27
ads-wrapper/AdsSettings.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Struct with the settings for connecting to the ads server
|
||||||
|
/// </summary>
|
||||||
|
public class AdsSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ads server address
|
||||||
|
/// </summary>
|
||||||
|
public string AdsAdress { get; set; } = "127.0.0.1.1.1";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ads server port
|
||||||
|
/// </summary>
|
||||||
|
public int AdsPort { get; set; } = 851;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Intervall for reconnect tries
|
||||||
|
/// </summary>
|
||||||
|
public int ReconnectIntervalMS { get; set; } = 2000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Variable name for which contains the online change counter
|
||||||
|
/// </summary>
|
||||||
|
public string OnlineChangeCntVar { get; set; } = "TWinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt";
|
||||||
|
}
|
||||||
2
ads-wrapper/README.md
Normal file
2
ads-wrapper/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Ads Manager
|
||||||
|
Ads Wrapper klasse um automatische reconnects und online changes mit einem ADS Server der Beckhoff steuerung zu behandeln.
|
||||||
63
uniper_hmi/.gitattributes
vendored
Normal file
63
uniper_hmi/.gitattributes
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
||||||
367
uniper_hmi/.gitignore
vendored
Normal file
367
uniper_hmi/.gitignore
vendored
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Testproject folders
|
||||||
|
AdsSessionTest/
|
||||||
|
HMI_Export/
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
1
uniper_hmi/AdsSettings.json
Normal file
1
uniper_hmi/AdsSettings.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"AdsAdress":"10.103.32.50.1.1","AdsPort":851,"ReconnectIntervalMS":1000,"OnlineChangeCntVar":"TWinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"}
|
||||||
98
uniper_hmi/README.md
Normal file
98
uniper_hmi/README.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Uniper
|
||||||
|
Uniper maintenance hmi project.
|
||||||
|
|
||||||
|
# Gitflow
|
||||||
|
1. A develop branch is created from main
|
||||||
|
2. A release branch is created from develop
|
||||||
|
3. Feature branches are created from develop
|
||||||
|
4. When a feature is complete it is merged into the develop branch
|
||||||
|
5. When the release branch is done it is merged into develop and main
|
||||||
|
6. If an issue in main is detected a hotfix branch is created from main
|
||||||
|
7. Once the hotfix is complete it is merged to both develop and main
|
||||||
|
|
||||||
|
## Start new feature
|
||||||
|
```
|
||||||
|
git flow feature start feature_branch
|
||||||
|
```
|
||||||
|
oder
|
||||||
|
```
|
||||||
|
git checkout develop
|
||||||
|
git checkout -b feature_branch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Finish a feature
|
||||||
|
```
|
||||||
|
git flow feature finish feature_branch
|
||||||
|
```
|
||||||
|
oder
|
||||||
|
```
|
||||||
|
git checkout develop
|
||||||
|
git merge feature_branch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Making a release
|
||||||
|
```
|
||||||
|
git flow release start 0.1.0
|
||||||
|
```
|
||||||
|
oder
|
||||||
|
```
|
||||||
|
git checkout develop
|
||||||
|
git checkout -b release/0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Finishing a release
|
||||||
|
```
|
||||||
|
git flow release finish '0.1.0'
|
||||||
|
```
|
||||||
|
oder
|
||||||
|
```
|
||||||
|
git checkout main
|
||||||
|
git merge release/0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Starting a Hotfix
|
||||||
|
```
|
||||||
|
git flow hotfix start hotfix_branch
|
||||||
|
```
|
||||||
|
oder
|
||||||
|
```
|
||||||
|
git checkout main
|
||||||
|
git checkout -b hotfix_branch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Finishing a Hotfix
|
||||||
|
```
|
||||||
|
git flow hotfix finish hotfix_branch
|
||||||
|
```
|
||||||
|
oder
|
||||||
|
```
|
||||||
|
git checkout main
|
||||||
|
git merge hotfix_branch
|
||||||
|
git checkout develop
|
||||||
|
git merge hotfix_branch
|
||||||
|
git branch -D hotfix_branch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow example
|
||||||
|
```
|
||||||
|
git checkout main
|
||||||
|
git checkout -b develop
|
||||||
|
git checkout -b feature_branch
|
||||||
|
# work happens on feature branch
|
||||||
|
git checkout develop
|
||||||
|
git merge feature_branch
|
||||||
|
git checkout main
|
||||||
|
git merge develop
|
||||||
|
git branch -d feature_branch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hotfix example
|
||||||
|
```
|
||||||
|
git checkout main
|
||||||
|
git checkout -b hotfix_branch
|
||||||
|
# work is done commits are added to the hotfix_branch
|
||||||
|
git checkout develop
|
||||||
|
git merge hotfix_branch
|
||||||
|
git checkout main
|
||||||
|
git merge hotfix_branch
|
||||||
|
```
|
||||||
25
uniper_hmi/Uniper.sln
Normal file
25
uniper_hmi/Uniper.sln
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.8.34408.163
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniperHMI", "UniperHMI\UniperHMI.csproj", "{8D725B27-1242-4C66-ACD8-45F02098C7D3}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8D725B27-1242-4C66-ACD8-45F02098C7D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8D725B27-1242-4C66-ACD8-45F02098C7D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8D725B27-1242-4C66-ACD8-45F02098C7D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8D725B27-1242-4C66-ACD8-45F02098C7D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {13973C5F-C164-4478-A4B1-1694557CC459}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
17
uniper_hmi/UniperHMI/App.xaml
Normal file
17
uniper_hmi/UniperHMI/App.xaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<Application x:Class="UniperHMI.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:UniperHMI">
|
||||||
|
<Application.Resources>
|
||||||
|
<!-- MahApps Metro style themes -->
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<!-- Theme setting -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Dark.Blue.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
46
uniper_hmi/UniperHMI/App.xaml.cs
Normal file
46
uniper_hmi/UniperHMI/App.xaml.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using TcEventLoggerAdsProxyLib;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
public static IHost? AppHost { get; private set; }
|
||||||
|
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
AppHost = Host.CreateDefaultBuilder()
|
||||||
|
.ConfigureServices((hostContext, services) =>
|
||||||
|
{
|
||||||
|
services.AddSingleton<MainWindow>();
|
||||||
|
services.AddSingleton<MainWindowVM>();
|
||||||
|
services.AddSingleton<IAdsManager, AdsManager>();
|
||||||
|
services.AddTransient<AutomaticModePageVM>();
|
||||||
|
services.AddTransient<BatteryOverviewPageVM>();
|
||||||
|
services.AddTransient<StringOverviewPageVM>();
|
||||||
|
services.AddTransient<ModuleOverviewPageVM>();
|
||||||
|
services.AddSingleton<TcEventLogger>();
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
await AppHost!.StartAsync();
|
||||||
|
|
||||||
|
var startupForm = AppHost.Services.GetRequiredService<MainWindow>();
|
||||||
|
startupForm.Show();
|
||||||
|
|
||||||
|
base.OnStartup(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async void OnExit(ExitEventArgs e)
|
||||||
|
{
|
||||||
|
await AppHost!.StopAsync();
|
||||||
|
|
||||||
|
base.OnExit(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
uniper_hmi/UniperHMI/AssemblyInfo.cs
Normal file
10
uniper_hmi/UniperHMI/AssemblyInfo.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
33
uniper_hmi/UniperHMI/DateTimeToEventTimeConverter.cs
Normal file
33
uniper_hmi/UniperHMI/DateTimeToEventTimeConverter.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
public class DateTimeToEventTimeConverter : IValueConverter
|
||||||
|
{
|
||||||
|
// 599264352000000000 ticks is a date used by beckhoff for events that didnt happen up to this point
|
||||||
|
public const long NoTime = 599264352000000000;
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is DateTime dt)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (dt.Ticks == NoTime)
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CultureInfo cultureInfo = CultureInfo.CurrentCulture;
|
||||||
|
return dt.ToString("G", cultureInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new InvalidOperationException("Target must be of type DateTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml
Normal file
12
uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<Window x:Class="HMIToolkit.AnalogMotorWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:HMIToolkit"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="AnalogMotorWindow" SizeToContent="WidthAndHeight">
|
||||||
|
<Grid>
|
||||||
|
<local:AnalogMotorControl />
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
14
uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml.cs
Normal file
14
uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace HMIToolkit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für AnalogMotorWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AnalogMotorWindow : Window
|
||||||
|
{
|
||||||
|
public AnalogMotorWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml
Normal file
12
uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<Window xmlns:HMIToolkit="clr-namespace:HMIToolkit" x:Class="UniperHMI.BinaryValveWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="BinaryValveWindow" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
|
||||||
|
<Grid>
|
||||||
|
<HMIToolkit:BinaryValveControl />
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
15
uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml.cs
Normal file
15
uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für BinaryValveWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class BinaryValveWindow : Window
|
||||||
|
{
|
||||||
|
public BinaryValveWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
uniper_hmi/UniperHMI/HMIToolkit/FeedbackToColorConverter.cs
Normal file
46
uniper_hmi/UniperHMI/HMIToolkit/FeedbackToColorConverter.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace HMIToolkit;
|
||||||
|
|
||||||
|
class FeedbackToColorConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public Object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (targetType != typeof(System.Windows.Media.Brush))
|
||||||
|
throw new InvalidOperationException("The target must be a brush");
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning disable CS8604 // Mögliches Nullverweisargument.
|
||||||
|
int num = int.Parse(value.ToString());
|
||||||
|
#pragma warning restore CS8604 // Mögliches Nullverweisargument.
|
||||||
|
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return System.Windows.Media.Brushes.Green;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return System.Windows.Media.Brushes.GreenYellow;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return System.Windows.Media.Brushes.DarkOrange;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return System.Windows.Media.Brushes.DarkRed;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<UserControl x:Class="HMIToolkit.AnalogMotorControl"
|
||||||
|
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:HMIToolkit"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:AnalogMotorControlVM, IsDesignTimeCreatable=True}"
|
||||||
|
Width="Auto"
|
||||||
|
Height="Auto">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<local:FeedbackToColorConverter x:Key="feedbackConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<d:DesignerProperties.DesignStyle>
|
||||||
|
<Style TargetType="UserControl">
|
||||||
|
<!-- Property="Background" Value="White" /> -->
|
||||||
|
<Setter Property="Height" Value="Auto" />
|
||||||
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
</Style>
|
||||||
|
</d:DesignerProperties.DesignStyle>
|
||||||
|
<Grid>
|
||||||
|
<Grid Margin="5" ShowGridLines="False">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Label Grid.Row="0" Content="{Binding SName}" HorizontalAlignment="Center" FontSize="24" FontWeight="Bold"/>
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Label Grid.Row="1" Content="Interlocks:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Grid Grid.Row="2">
|
||||||
|
<local:IntlkButtonControl DataContext="{Binding Interlocks}"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Label Grid.Row="3" Content="Setpoint:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<local:AnalogValue DataContext="{Binding Setpoint}" Grid.Row="4"/>
|
||||||
|
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<Label Grid.Row="5" Content="Process value:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<local:AnalogValue DataContext="{Binding ProcessValue}" Grid.Row="6"/>
|
||||||
|
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<Grid Grid.Row="7">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Control:" Margin="0,0,0,-3" />
|
||||||
|
<Button x:Name="btnOpen" DataContext="{Binding StartButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Background="{Binding IFeedback, Converter={StaticResource feedbackConverter}}" Grid.Row="1" Grid.Column="0" Content="Start" Height="80" Width="80" Margin="0,0,5,5" />
|
||||||
|
<Button x:Name="btnClose" DataContext="{Binding StopButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Background="{Binding IFeedback, Converter={StaticResource feedbackConverter}}" Grid.Row="1" Grid.Column="1" Content="Stop" Height="80" Width="80" Margin="0,-5,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 8 -->
|
||||||
|
<Grid Grid.Row="8">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Mode:" Margin="0,0,0,-3" />
|
||||||
|
<Button x:Name="btnAuto" DataContext="{Binding AutomaticButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="0" Content="Auto" Height="80" Width="80" Margin="0,0,5,0"/>
|
||||||
|
<Button x:Name="btnManual" DataContext="{Binding ManualButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="1" Content="Man" Height="80" Width="80" Margin="0,-5,0,-5"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für AnalogMotorControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AnalogMotorControl : UserControl
|
||||||
|
{
|
||||||
|
public AnalogMotorControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public sealed partial class AnalogMotorControlVM : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string sName = "No Name";
|
||||||
|
|
||||||
|
public HMIControlButtonVM? AutomaticButton { get; private set; }
|
||||||
|
public HMIControlButtonVM? ManualButton { get; private set; }
|
||||||
|
public HMIControlButtonVM StartButton { get; private set; }
|
||||||
|
public HMIControlButtonVM StopButton { get; private set; }
|
||||||
|
public IntlkControlVM? Interlocks { get; private set; }
|
||||||
|
public AnalogValueVM? Setpoint { get; private set; }
|
||||||
|
public AnalogValueVM? ProcessValue { get; private set; }
|
||||||
|
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public AnalogMotorControlVM()
|
||||||
|
{
|
||||||
|
AutomaticButton = new HMIControlButtonVM();
|
||||||
|
ManualButton = new HMIControlButtonVM();
|
||||||
|
StartButton = new HMIControlButtonVM();
|
||||||
|
StopButton = new HMIControlButtonVM();
|
||||||
|
Interlocks = new IntlkControlVM();
|
||||||
|
Setpoint = new AnalogValueVM();
|
||||||
|
ProcessValue = new AnalogValueVM();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnalogMotorControlVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
AutomaticButton = new HMIControlButtonVM(_adsManager, _variableName + ".stAutomaticButton");
|
||||||
|
ManualButton = new HMIControlButtonVM(_adsManager, _variableName + ".stManualButton");
|
||||||
|
StartButton = new HMIControlButtonVM(_adsManager, _variableName + ".stStartButton");
|
||||||
|
StopButton = new HMIControlButtonVM(_adsManager, _variableName + ".stStopButton");
|
||||||
|
Interlocks = new IntlkControlVM(_adsManager, _variableName + ".stInterlock");
|
||||||
|
Setpoint = new AnalogValueVM(_adsManager, _variableName + ".stSetpoint", false);
|
||||||
|
ProcessValue = new AnalogValueVM(_adsManager, _variableName + ".stProcessValue", true);
|
||||||
|
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".sName", NameChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName + ".sName", NameChanged);
|
||||||
|
_adsManager = null;
|
||||||
|
|
||||||
|
AutomaticButton?.Dispose();
|
||||||
|
AutomaticButton = null;
|
||||||
|
|
||||||
|
ManualButton?.Dispose();
|
||||||
|
ManualButton = null;
|
||||||
|
|
||||||
|
StartButton?.Dispose();
|
||||||
|
StartButton = null;
|
||||||
|
|
||||||
|
StopButton?.Dispose();
|
||||||
|
StopButton = null;
|
||||||
|
|
||||||
|
Interlocks?.Dispose();
|
||||||
|
Interlocks = null;
|
||||||
|
|
||||||
|
Setpoint?.Dispose();
|
||||||
|
Setpoint = null;
|
||||||
|
|
||||||
|
ProcessValue?.Dispose();
|
||||||
|
ProcessValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NameChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SName = (string)e.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public sealed partial class AnalogRangeValidator : ValidationRule
|
||||||
|
{
|
||||||
|
public float Min { get; set; }
|
||||||
|
|
||||||
|
public float Max { get; set; }
|
||||||
|
|
||||||
|
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
float analogValue = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (((string)value).Length > 0)
|
||||||
|
analogValue = float.Parse((string)value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return new ValidationResult(false, $"Illegal characters or {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((analogValue < Min) || (analogValue > Max))
|
||||||
|
return new ValidationResult(false, $"Please enter a value in the range: {Min}-{Max}.");
|
||||||
|
|
||||||
|
return ValidationResult.ValidResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<UserControl x:Class="HMIToolkit.AnalogValue"
|
||||||
|
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:HMIToolkit"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:AnalogValueVM, IsDesignTimeCreatable=True}"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Width="Auto"
|
||||||
|
Height="Auto">
|
||||||
|
<!-- :DataContext="{d:DesignInstance Type=local:AnalogValueVM, IsDesignTimeCreatable=True}" -->
|
||||||
|
<!-- Style to see things in the designer-->
|
||||||
|
<d:DesignerProperties.DesignStyle>
|
||||||
|
<Style TargetType="UserControl">
|
||||||
|
<!-- Property="Background" Value="White" /> -->
|
||||||
|
<Setter Property="Height" Value="Auto" />
|
||||||
|
<Setter Property="Width" Value="200" />
|
||||||
|
</Style>
|
||||||
|
</d:DesignerProperties.DesignStyle>
|
||||||
|
<Grid Height="Auto">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<!-- <ColumnDefinition Width="Auto" /> -->
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- <Label Grid.Column="0" Content="{Binding SName}" VerticalAlignment="Center" HorizontalAlignment="Left"/> -->
|
||||||
|
|
||||||
|
<TextBox x:Name="tbValue" Text="{Binding RValue, Mode=TwoWay, StringFormat=N2}" Grid.Column="0" MaxLines="1" Width="125" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" IsReadOnly="{Binding Readonly}" />
|
||||||
|
<Label Grid.Column="1" Content="{Binding SUnit}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für AnalogValue.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AnalogValue : UserControl
|
||||||
|
{
|
||||||
|
public bool IsReadonly { get; set; }
|
||||||
|
|
||||||
|
public AnalogValue()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NumberValidation(object sender, TextCompositionEventArgs e)
|
||||||
|
{
|
||||||
|
Regex regex = new("^[-+]?[0-9]*,?[0-9]+$");
|
||||||
|
e.Handled = regex.IsMatch(e.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace HMIToolkit;
|
||||||
|
|
||||||
|
public sealed class InRangeAttribute(string propMin, string propMax) : ValidationAttribute
|
||||||
|
{
|
||||||
|
public string PropMin { get; } = propMin;
|
||||||
|
public string PropMax { get; } = propMax;
|
||||||
|
|
||||||
|
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
object instance = validationContext.ObjectInstance;
|
||||||
|
float minValue = (float)(instance.GetType().GetProperty(PropMin)?.GetValue(instance) ?? 0.0f);
|
||||||
|
float maxValue = (float)(instance.GetType().GetProperty(PropMax)?.GetValue(instance) ?? 0.0f);
|
||||||
|
float tempValue = (float)(value ?? 0.0f);
|
||||||
|
|
||||||
|
if (tempValue <= maxValue && tempValue >= minValue)
|
||||||
|
return ValidationResult.Success;
|
||||||
|
|
||||||
|
return new($"Value has to be greater than {minValue} and smaller then {maxValue}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed partial class AnalogValueVM : ObservableValidator, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string sName;
|
||||||
|
|
||||||
|
// 1 = Ok; 2 = Error
|
||||||
|
[ObservableProperty]
|
||||||
|
private short iStatus;
|
||||||
|
|
||||||
|
private float rValue;
|
||||||
|
|
||||||
|
[InRangeAttribute(nameof(RMin), nameof(RMax))]
|
||||||
|
public float RValue
|
||||||
|
{
|
||||||
|
get => rValue;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref rValue, value, true);
|
||||||
|
if (value >= RMin && value <= RMax)
|
||||||
|
{
|
||||||
|
if (!Readonly)
|
||||||
|
WriteValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteValue(float value)
|
||||||
|
{
|
||||||
|
_adsManager?.WriteValue(_variableName + ".rValue", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string sUnit;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float rMin;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float rMax;
|
||||||
|
|
||||||
|
public bool Readonly { get; private set; }
|
||||||
|
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
public AnalogValueVM()
|
||||||
|
{
|
||||||
|
sName = "No Name:";
|
||||||
|
iStatus = 2;
|
||||||
|
rValue = 0.0f;
|
||||||
|
sUnit = "";
|
||||||
|
Readonly = true;
|
||||||
|
rMin = 0.0f;
|
||||||
|
rMax = 100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnalogValueVM(IAdsManager adsManager, string variableName, bool isReadonly) : this()
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
Readonly = isReadonly;
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".sName", NameChanged);
|
||||||
|
_adsManager.Register(_variableName + ".iStatus", StatusChanged);
|
||||||
|
//if (isReadonly)
|
||||||
|
_adsManager.Register(_variableName + ".rValue", ValueChanged);
|
||||||
|
_adsManager.Register(_variableName + ".sUnit", UnitChanged);
|
||||||
|
_adsManager.Register(_variableName + ".rMin", MinChanged);
|
||||||
|
_adsManager.Register(_variableName + ".rMax", MaxChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName + ".sName", NameChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".iStatus", StatusChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".rValue", ValueChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".sUnit", UnitChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".rMin", MinChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".rMax", MaxChanged);
|
||||||
|
|
||||||
|
_adsManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NameChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
string temp = (string)e.Value;
|
||||||
|
if (temp != String.Empty)
|
||||||
|
SName = temp + ":";
|
||||||
|
else
|
||||||
|
SName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StatusChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
IStatus = (short)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValueChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
RValue = (float)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnitChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SUnit = (string)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MinChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
RMin = (float)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MaxChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
RMax = (float)e.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<UserControl xmlns:AnalogValue="clr-namespace:HMIToolkit" x:Class="HMIToolkit.AnalogValveControl"
|
||||||
|
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:HMIToolkit"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:AnalogValveControlVM, IsDesignTimeCreatable=True}"
|
||||||
|
Width="Auto"
|
||||||
|
Height="Auto">
|
||||||
|
<d:DesignerProperties.DesignStyle>
|
||||||
|
<Style TargetType="UserControl">
|
||||||
|
<!-- Property="Background" Value="White" /> -->
|
||||||
|
<Setter Property="Height" Value="Auto" />
|
||||||
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
</Style>
|
||||||
|
</d:DesignerProperties.DesignStyle>
|
||||||
|
<Grid>
|
||||||
|
<Grid Margin="5" ShowGridLines="False">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Label Grid.Row="0" Content="{Binding SName}" HorizontalAlignment="Center" FontSize="24" FontWeight="Bold"/>
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Label Grid.Row="1" Content="Interlocks:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Grid Grid.Row="2">
|
||||||
|
<local:IntlkButtonControl DataContext="{Binding Interlocks}"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Label Grid.Row="3" Content="Setpoint:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<AnalogValue:AnalogValue DataContext="{Binding Setpoint}" Grid.Row="4"/>
|
||||||
|
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<Label Grid.Row="5" Content="Process value:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<AnalogValue:AnalogValue DataContext="{Binding ProcessValue}" Grid.Row="6"/>
|
||||||
|
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<Grid Grid.Row="7">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Control:" Margin="0,0,0,-3" />
|
||||||
|
<Button x:Name="btnOpen" DataContext="{Binding OpenButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="0" Content="Open" Height="80" Width="80" Margin="0,0,5,5" />
|
||||||
|
<Button x:Name="btnClose" DataContext="{Binding CloseButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="1" Content="Close" Height="80" Width="80" Margin="0,-5,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 8 -->
|
||||||
|
<Grid Grid.Row="8">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Mode:" Margin="0,0,0,-3" />
|
||||||
|
<Button x:Name="btnAuto" DataContext="{Binding AutomaticButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="0" Content="Auto" Height="80" Width="80" Margin="0,0,5,0"/>
|
||||||
|
<Button x:Name="btnManual" DataContext="{Binding ManualButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="1" Content="Man" Height="80" Width="80" Margin="0,-5,0,-5"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
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 HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für AnalogValveControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AnalogValveControl : UserControl
|
||||||
|
{
|
||||||
|
public AnalogValveControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public sealed partial class AnalogValveControlVM : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string sName = "No Name";
|
||||||
|
|
||||||
|
public HMIControlButtonVM? AutomaticButton { get; private set; }
|
||||||
|
public HMIControlButtonVM? ManualButton { get; private set; }
|
||||||
|
public HMIControlButtonVM? OpenButton { get; private set; }
|
||||||
|
public HMIControlButtonVM? CloseButton { get; private set; }
|
||||||
|
public IntlkControlVM? Interlocks { get; private set; }
|
||||||
|
public AnalogValueVM? Setpoint { get; private set; }
|
||||||
|
public AnalogValueVM? ProcessValue { get; private set; }
|
||||||
|
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public AnalogValveControlVM()
|
||||||
|
{
|
||||||
|
AutomaticButton = new HMIControlButtonVM();
|
||||||
|
ManualButton = new HMIControlButtonVM();
|
||||||
|
OpenButton = new HMIControlButtonVM();
|
||||||
|
CloseButton = new HMIControlButtonVM();
|
||||||
|
Interlocks = new IntlkControlVM();
|
||||||
|
Setpoint = new AnalogValueVM();
|
||||||
|
ProcessValue = new AnalogValueVM();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnalogValveControlVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
AutomaticButton = new HMIControlButtonVM(_adsManager, _variableName + ".stAutomaticButton");
|
||||||
|
ManualButton = new HMIControlButtonVM(_adsManager, _variableName + ".stManualButton");
|
||||||
|
OpenButton = new HMIControlButtonVM(_adsManager, _variableName + ".stOpenButton");
|
||||||
|
CloseButton = new HMIControlButtonVM(_adsManager, _variableName + ".stCloseButton");
|
||||||
|
Interlocks = new IntlkControlVM(_adsManager, _variableName + ".stInterlock");
|
||||||
|
Setpoint = new AnalogValueVM(_adsManager, _variableName + ".stSetpoint", false);
|
||||||
|
ProcessValue = new AnalogValueVM(_adsManager, _variableName + ".stProcessValue", true);
|
||||||
|
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".sName", NameChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName + ".sName", NameChanged);
|
||||||
|
_adsManager = null;
|
||||||
|
|
||||||
|
AutomaticButton?.Dispose();
|
||||||
|
AutomaticButton = null;
|
||||||
|
|
||||||
|
ManualButton?.Dispose();
|
||||||
|
ManualButton = null;
|
||||||
|
|
||||||
|
OpenButton?.Dispose();
|
||||||
|
OpenButton = null;
|
||||||
|
|
||||||
|
CloseButton?.Dispose();
|
||||||
|
CloseButton = null;
|
||||||
|
|
||||||
|
Interlocks?.Dispose();
|
||||||
|
Interlocks = null;
|
||||||
|
|
||||||
|
Setpoint?.Dispose();
|
||||||
|
Setpoint = null;
|
||||||
|
|
||||||
|
ProcessValue?.Dispose();
|
||||||
|
ProcessValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NameChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SName = (string)e.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<UserControl x:Class="HMIToolkit.BinaryValveControl"
|
||||||
|
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:HMIToolkit"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:BinaryValveControlVM, IsDesignTimeCreatable=True}"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Height="Auto"
|
||||||
|
Width="Auto">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<local:FeedbackToColorConverter x:Key="feedbackConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<!-- Style to see things in the designer-->
|
||||||
|
<d:DesignerProperties.DesignStyle>
|
||||||
|
<Style TargetType="UserControl">
|
||||||
|
<!-- Property="Background" Value="White" /> -->
|
||||||
|
<Setter Property="Height" Value="Auto" />
|
||||||
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
</Style>
|
||||||
|
</d:DesignerProperties.DesignStyle>
|
||||||
|
|
||||||
|
<Grid Margin="5" ShowGridLines="True">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Label Grid.Row="0" Content="{Binding SName}" HorizontalAlignment="Center" FontSize="24" FontWeight="Bold"/>
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Label Grid.Row="1" Content="Interlocks:" Margin="0,0,0,-3"/>
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Grid Grid.Row="2">
|
||||||
|
<local:IntlkButtonControl DataContext="{Binding Interlocks}"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Grid Grid.Row="3">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Control:" Margin="0,0,0,-3" />
|
||||||
|
<Button x:Name="btnOpen" DataContext="{Binding OpenButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Background="{Binding IFeedback, Converter={StaticResource feedbackConverter}}" Grid.Row="1" Grid.Column="0" Content="Open" Height="80" Width="80" Margin="0,0,5,5" />
|
||||||
|
<Button x:Name="btnClose" DataContext="{Binding CloseButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Background="{Binding IFeedback, Converter={StaticResource feedbackConverter}}" Grid.Row="1" Grid.Column="1" Content="Close" Height="80" Width="80" Margin="0,-5,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<Grid Grid.Row="4">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Mode:" Margin="0,0,0,-3" />
|
||||||
|
<Button x:Name="btnAuto" DataContext="{Binding AutomaticButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="0" Content="Auto" Height="80" Width="80" Margin="0,0,5,0"/>
|
||||||
|
<Button x:Name="btnManual" DataContext="{Binding ManualButton}" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding XRelease}" Grid.Row="1" Grid.Column="1" Content="Man" Height="80" Width="80" Margin="0,-5,0,-5"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
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 HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für BinaryValveControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class BinaryValveControl : UserControl
|
||||||
|
{
|
||||||
|
public BinaryValveControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
// {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.OpenButton}
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public sealed partial class BinaryValveControlVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string sName = "No Name";
|
||||||
|
|
||||||
|
public HMIControlButtonVM? AutomaticButton { get; private set; }
|
||||||
|
public HMIControlButtonVM? ManualButton { get; private set; }
|
||||||
|
public HMIControlButtonVM OpenButton { get; private set; }
|
||||||
|
public HMIControlButtonVM CloseButton { get; private set; }
|
||||||
|
public IntlkControlVM? Interlocks { get; private set; }
|
||||||
|
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public BinaryValveControlVM()
|
||||||
|
{
|
||||||
|
AutomaticButton = new HMIControlButtonVM();
|
||||||
|
ManualButton = new HMIControlButtonVM();
|
||||||
|
OpenButton = new HMIControlButtonVM();
|
||||||
|
CloseButton = new HMIControlButtonVM();
|
||||||
|
Interlocks = new IntlkControlVM();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryValveControlVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
AutomaticButton = new HMIControlButtonVM(_adsManager, _variableName + ".stAutomaticButton");
|
||||||
|
ManualButton = new HMIControlButtonVM(_adsManager, _variableName + ".stManualButton");
|
||||||
|
OpenButton = new HMIControlButtonVM(_adsManager, _variableName + ".stOpenButton");
|
||||||
|
CloseButton = new HMIControlButtonVM(_adsManager, _variableName + ".stCloseButton");
|
||||||
|
Interlocks = new IntlkControlVM(_adsManager, _variableName + ".stInterlock");
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".sName", NameChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName + ".sName", NameChanged);
|
||||||
|
_adsManager = null;
|
||||||
|
|
||||||
|
AutomaticButton?.Dispose();
|
||||||
|
AutomaticButton = null;
|
||||||
|
|
||||||
|
ManualButton?.Dispose();
|
||||||
|
ManualButton = null;
|
||||||
|
|
||||||
|
OpenButton?.Dispose();
|
||||||
|
|
||||||
|
CloseButton?.Dispose();
|
||||||
|
|
||||||
|
Interlocks?.Dispose();
|
||||||
|
Interlocks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NameChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SName = (string)e.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public class BoolToBrushConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (targetType != typeof(Brush))
|
||||||
|
throw new InvalidOperationException("The target must be a brush");
|
||||||
|
|
||||||
|
bool temp = bool.Parse(value.ToString()!);
|
||||||
|
|
||||||
|
return (temp ? Brushes.DarkGreen : Brushes.DarkRed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public sealed partial class HMIControlButtonVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
private readonly string _variableName;
|
||||||
|
|
||||||
|
// Action triggered when the button is about to be clicked
|
||||||
|
public event EventHandler? ButtonClickedStarted;
|
||||||
|
|
||||||
|
// Action triggered when the button is done being clicked
|
||||||
|
public event EventHandler? ButtonClickedEnded;
|
||||||
|
|
||||||
|
// Event when button feedback changed
|
||||||
|
public event EventHandler? FeedbackChanged;
|
||||||
|
|
||||||
|
// Event when release changed
|
||||||
|
public event EventHandler? ReleaseChanged;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool xRelease;
|
||||||
|
|
||||||
|
// 0 = none, 1 = active, 2 = pending, 3 = waring, 4 = error
|
||||||
|
[ObservableProperty]
|
||||||
|
private short iFeedback;
|
||||||
|
|
||||||
|
public HMIControlButtonVM()
|
||||||
|
{
|
||||||
|
_variableName = string.Empty;
|
||||||
|
XRelease = false;
|
||||||
|
IFeedback = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HMIControlButtonVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".xRelease", XReleaseCahnged);
|
||||||
|
_adsManager.Register(_variableName + ".iFeedback", IFeedbackChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName + ".xRelease", XReleaseCahnged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".iFeedback", IFeedbackChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ButtonClicked()
|
||||||
|
{
|
||||||
|
ButtonClickedStarted?.Invoke(this, EventArgs.Empty);
|
||||||
|
_adsManager?.WriteValue(_variableName + ".xRequest", true);
|
||||||
|
ButtonClickedEnded?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void XReleaseCahnged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
XRelease = (bool)e.Value;
|
||||||
|
ReleaseChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IFeedbackChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
IFeedback = (short)e.Value;
|
||||||
|
FeedbackChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<UserControl x:Class="HMIToolkit.IntlkButtonControl"
|
||||||
|
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:HMIToolkit"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:IntlkControlVM, IsDesignTimeCreatable=True}"
|
||||||
|
d:DesignHeight="35" d:DesignWidth="175">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<local:BoolToBrushConverter x:Key="myBoolConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button Grid.Column="0" Padding="0" Command="{Binding ShowProcessIntlksCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label>Process</Label>
|
||||||
|
<Rectangle Width="10" Height="10" Fill="{Binding Path=XProcessIntlkOk, Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Grid.Column="1" Padding="0" Margin="5,0,0,0" Command="{Binding ShowSafetyIntlksCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label>Safety</Label>
|
||||||
|
<Rectangle Width="10" Height="10" Fill="{Binding Path=XSafetyIntlkOk, Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
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 HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für ProcessIntlkButtonControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class IntlkButtonControl : UserControl
|
||||||
|
{
|
||||||
|
public IntlkButtonControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace HMIToolkit;
|
||||||
|
|
||||||
|
public sealed partial class IntlkControlVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool xProcessIntlkOk;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool xSafetyIntlkOk;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private IntlkDetailsVM safetyInterlocksVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private IntlkDetailsVM processInterlocksVM;
|
||||||
|
|
||||||
|
private IntlkDetailsWindow? processIntlksDetailsWindow;
|
||||||
|
private IntlkDetailsWindow? safetyIntlksDetailsWindow;
|
||||||
|
|
||||||
|
private readonly string _variableName;
|
||||||
|
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public IntlkControlVM()
|
||||||
|
{
|
||||||
|
XProcessIntlkOk = false;
|
||||||
|
XSafetyIntlkOk = false;
|
||||||
|
_variableName = string.Empty;
|
||||||
|
safetyInterlocksVM = new();
|
||||||
|
processInterlocksVM = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntlkControlVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
SafetyInterlocksVM = new IntlkDetailsVM(_adsManager, _variableName + ".wSafetyINTLKStatus", _variableName + ".asSafetyINTLKName", "Safety Interlock");
|
||||||
|
ProcessInterlocksVM = new IntlkDetailsVM(_adsManager, _variableName + ".wProcessINTLKStatus", _variableName + ".asProcessINTLKName", "Process Interlock");
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".xProcessINTLKOk", ProcessIntlkOkChanged);
|
||||||
|
_adsManager.Register(_variableName + ".xSafetyINTLKOk", SafetyIntlkOkChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
SafetyInterlocksVM.Dispose();
|
||||||
|
ProcessInterlocksVM.Dispose();
|
||||||
|
|
||||||
|
_adsManager?.Deregister(_variableName + ".xProcessINTLKOk", ProcessIntlkOkChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".xSafetyINTLKOk", SafetyIntlkOkChanged);
|
||||||
|
|
||||||
|
processIntlksDetailsWindow?.Close();
|
||||||
|
safetyIntlksDetailsWindow?.Close();
|
||||||
|
|
||||||
|
_adsManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessIntlkOkChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
XProcessIntlkOk = (bool)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SafetyIntlkOkChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
XSafetyIntlkOk = (bool)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ShowProcessIntlks()
|
||||||
|
{
|
||||||
|
if (_adsManager != null && processIntlksDetailsWindow == null)
|
||||||
|
{
|
||||||
|
processIntlksDetailsWindow = new() { DataContext = ProcessInterlocksVM };
|
||||||
|
processIntlksDetailsWindow.Closed += ProcessIntlksDetailsWindow_Closed;
|
||||||
|
processIntlksDetailsWindow.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
|
||||||
|
processIntlksDetailsWindow.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessIntlksDetailsWindow_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
processIntlksDetailsWindow!.Close();
|
||||||
|
processIntlksDetailsWindow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ShowSafetyIntlks()
|
||||||
|
{
|
||||||
|
if (_adsManager != null && safetyIntlksDetailsWindow == null)
|
||||||
|
{
|
||||||
|
safetyIntlksDetailsWindow = new() { DataContext = SafetyInterlocksVM };
|
||||||
|
safetyIntlksDetailsWindow.Closed += SafetyIntlksDetailsWindow_Closed;
|
||||||
|
safetyIntlksDetailsWindow.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
|
||||||
|
safetyIntlksDetailsWindow.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SafetyIntlksDetailsWindow_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
safetyIntlksDetailsWindow!.Close();
|
||||||
|
safetyIntlksDetailsWindow = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<UserControl x:Class="HMIToolkit.IntlkDetails"
|
||||||
|
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:HMIToolkit"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:IntlkDetailsVM, IsDesignTimeCreatable=True}"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
MinWidth="500" MinHeight="300"
|
||||||
|
d:DesignHeight="300" d:DesignWidth="500"
|
||||||
|
>
|
||||||
|
<UserControl.Resources>
|
||||||
|
<local:BoolToBrushConverter x:Key="myBoolConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid Margin="5" ShowGridLines="True" >
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding InterlockName}" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<!-- <ListBox Grid.Column="0" Grid.Row="1" ItemsSource="{Binding ListBoxItemsLeft}"/> -->
|
||||||
|
|
||||||
|
<!-- <ListBox Grid.Column="1" Grid.Row="1" ItemsSource="{Binding ListBoxItemsRight}" /> -->
|
||||||
|
<Grid Grid.Column="0" Grid.Row="1">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Rectangle Grid.Row="0" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[0], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="0" Grid.Column="1" Content="{Binding InterlockNames[0]}" />
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Rectangle Grid.Row="1" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[1], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="1" Grid.Column="1" Content="{Binding InterlockNames[1]}" />
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Rectangle Grid.Row="2" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[2], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="2" Grid.Column="1" Content="{Binding InterlockNames[2]}" />
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Rectangle Grid.Row="3" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[3], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="3" Grid.Column="1" Content="{Binding InterlockNames[3]}" />
|
||||||
|
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<Rectangle Grid.Row="4" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[4], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="4" Grid.Column="1" Content="{Binding InterlockNames[4]}" />
|
||||||
|
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<Rectangle Grid.Row="5" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[5], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="5" Grid.Column="1" Content="{Binding InterlockNames[5]}" />
|
||||||
|
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<Rectangle Grid.Row="6" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[6], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="6" Grid.Column="1" Content="{Binding InterlockNames[6]}" />
|
||||||
|
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<Rectangle Grid.Row="7" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[7], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="7" Grid.Column="1" Content="{Binding InterlockNames[7]}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid Grid.Column="1" Grid.Row="1">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Rectangle Grid.Row="0" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[8], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="0" Grid.Column="1" Content="{Binding InterlockNames[8]}" />
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Rectangle Grid.Row="1" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[9], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="1" Grid.Column="1" Content="{Binding InterlockNames[9]}" />
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Rectangle Grid.Row="2" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[10], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="2" Grid.Column="1" Content="{Binding InterlockNames[10]}" />
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Rectangle Grid.Row="3" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[11], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="3" Grid.Column="1" Content="{Binding InterlockNames[11]}" />
|
||||||
|
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<Rectangle Grid.Row="4" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[12], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="4" Grid.Column="1" Content="{Binding InterlockNames[12]}" />
|
||||||
|
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<Rectangle Grid.Row="5" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[13], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="5" Grid.Column="1" Content="{Binding InterlockNames[13]}" />
|
||||||
|
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<Rectangle Grid.Row="6" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[14], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="6" Grid.Column="1" Content="{Binding InterlockNames[14]}" />
|
||||||
|
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<Rectangle Grid.Row="7" Grid.Column="0" Width="10" Height="10" Fill="{Binding Path=InterlockStatus[15], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
<Label Grid.Row="7" Grid.Column="1" Content="{Binding InterlockNames[15]}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
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 HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für IntlkDetails.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class IntlkDetails : UserControl
|
||||||
|
{
|
||||||
|
public IntlkDetails()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
public sealed partial class IntlkDetailsVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string interlockName;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private BitArray interlockStatus;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string[] interlockNames;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ListBoxItem[] listBoxItemsLeft;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ListBoxItem[] listBoxItemsRight;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Visibility isVisible;
|
||||||
|
|
||||||
|
private readonly BoolToBrushConverter boolToBrushConverter = new();
|
||||||
|
|
||||||
|
private readonly int numIntlksLeftSide;
|
||||||
|
private readonly int numIntlksRightSide;
|
||||||
|
|
||||||
|
private readonly string _variableNameStatus;
|
||||||
|
private readonly string _variableNameNames;
|
||||||
|
|
||||||
|
private IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public IntlkDetailsVM()
|
||||||
|
{
|
||||||
|
interlockName = "Interlocks";
|
||||||
|
interlockStatus = new BitArray(HMIConstants.NumInterlocks);
|
||||||
|
interlockNames = new string[HMIConstants.NumInterlocks];
|
||||||
|
Array.Fill(interlockNames, "Not used");
|
||||||
|
|
||||||
|
// Split all interlocks into two parts
|
||||||
|
numIntlksLeftSide = (int)Math.Ceiling(HMIConstants.NumInterlocks * 0.5);
|
||||||
|
numIntlksRightSide = HMIConstants.NumInterlocks - numIntlksLeftSide;
|
||||||
|
|
||||||
|
listBoxItemsLeft = new ListBoxItem[numIntlksLeftSide];
|
||||||
|
listBoxItemsRight = new ListBoxItem[numIntlksRightSide];
|
||||||
|
|
||||||
|
_variableNameStatus = System.String.Empty;
|
||||||
|
_variableNameNames = System.String.Empty;
|
||||||
|
|
||||||
|
// CreateContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntlkDetailsVM(IAdsManager adsManager, string variableNameStatus, string variableNameNames, string intlkName) : this()
|
||||||
|
{
|
||||||
|
interlockName = intlkName;
|
||||||
|
_variableNameStatus = variableNameStatus;
|
||||||
|
_variableNameNames = variableNameNames;
|
||||||
|
_adsManager = adsManager;
|
||||||
|
|
||||||
|
interlockStatus = new BitArray(HMIConstants.NumInterlocks);
|
||||||
|
interlockNames = new string[HMIConstants.NumInterlocks];
|
||||||
|
|
||||||
|
_adsManager.Register(_variableNameStatus, InterlockStatusChanged);
|
||||||
|
_adsManager.Register(_variableNameNames, InterlockNamesChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableNameStatus, InterlockStatusChanged);
|
||||||
|
_adsManager?.Deregister(_variableNameNames, InterlockNamesChanged);
|
||||||
|
|
||||||
|
_adsManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private void CreateContent()
|
||||||
|
{
|
||||||
|
// Create left side
|
||||||
|
for (int i = 0; i < HMIConstants.NumInterlocks; i++)
|
||||||
|
{
|
||||||
|
// Create the stack panel
|
||||||
|
StackPanel stackPanel = new StackPanel
|
||||||
|
{
|
||||||
|
Orientation = Orientation.Horizontal
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the box
|
||||||
|
// <Rectangle Width="10" Height="10" Fill="{Binding Path=InterlockStatus[10], Converter={StaticResource myBoolConverter}}" RadiusX="2" RadiusY="2" Margin="0,2,0,0"/>
|
||||||
|
Rectangle rectangle = new Rectangle
|
||||||
|
{
|
||||||
|
Width = 10,
|
||||||
|
Height = 10,
|
||||||
|
RadiusX = 2,
|
||||||
|
RadiusY = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create binding
|
||||||
|
Binding binding = new()
|
||||||
|
{
|
||||||
|
Source = this,
|
||||||
|
Path = new PropertyPath("InterlockStatus[" + i + "]"),
|
||||||
|
Converter = boolToBrushConverter,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set binding
|
||||||
|
rectangle.SetBinding(Rectangle.FillProperty, binding);
|
||||||
|
|
||||||
|
// Create label
|
||||||
|
Label label = new();
|
||||||
|
binding = new()
|
||||||
|
{
|
||||||
|
Source = this,
|
||||||
|
Path = new PropertyPath("InterlockNames[" + i + "]")
|
||||||
|
};
|
||||||
|
label.SetBinding(Label.ContentProperty, binding);
|
||||||
|
|
||||||
|
// Add items to stack panel
|
||||||
|
stackPanel.Children.Add(rectangle);
|
||||||
|
stackPanel.Children.Add(label);
|
||||||
|
|
||||||
|
// Add stack panel to listbox items
|
||||||
|
ListBoxItem tempListBoxItem = new()
|
||||||
|
{
|
||||||
|
Content = stackPanel
|
||||||
|
};
|
||||||
|
if (i < numIntlksLeftSide)
|
||||||
|
ListBoxItemsLeft[i] = tempListBoxItem;
|
||||||
|
else
|
||||||
|
ListBoxItemsRight[i - numIntlksLeftSide] = tempListBoxItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
private void InterlockStatusChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
ushort temp = (ushort)e.Value;
|
||||||
|
InterlockStatus = new BitArray(BitConverter.GetBytes(temp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InterlockNamesChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
InterlockNames = (string[])e.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Window xmlns:AdsSessionTest="clr-namespace:HMIToolkit" x:Class="HMIToolkit.IntlkDetailsWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:HMIToolkit"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
SizeToContent="WidthAndHeight"
|
||||||
|
Title="IntlkDetailsWindow" Height="450" Width="800">
|
||||||
|
<Grid>
|
||||||
|
<AdsSessionTest:IntlkDetails />
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
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.Shapes;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für IntlkDetailsWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class IntlkDetailsWindow : Window
|
||||||
|
{
|
||||||
|
public IntlkDetailsWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace HMIToolkit
|
||||||
|
{
|
||||||
|
// PLC - C#
|
||||||
|
// --------
|
||||||
|
// int - short
|
||||||
|
// word - ushort
|
||||||
|
|
||||||
|
// Constants for interaction with data
|
||||||
|
public static class HMIConstants
|
||||||
|
{
|
||||||
|
public const int StringLength = 81;
|
||||||
|
public const int NumInterlocks = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIAnalogValue
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HMIConstants.StringLength)]
|
||||||
|
public string sName;
|
||||||
|
|
||||||
|
// 1 = Ok, 2 = Error
|
||||||
|
public short iStatus;
|
||||||
|
|
||||||
|
public float rValue;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HMIConstants.StringLength)]
|
||||||
|
public string sUnit;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwinCAT2 Pack = 1, TwinCAT 3 Pack = 0
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIControlButton
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xRequest;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xRelease;
|
||||||
|
|
||||||
|
public short iFeedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwinCAT2 Pack = 1, TwinCAT 3 Pack = 0
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIInterlock
|
||||||
|
{
|
||||||
|
public ushort wProcessINTLKStatus;
|
||||||
|
|
||||||
|
public ushort wSafeyINTLKStatus;
|
||||||
|
|
||||||
|
public ushort wProcessINTLKUsed;
|
||||||
|
|
||||||
|
public ushort wSafeyINTLKUsed;
|
||||||
|
|
||||||
|
// 16 * String(80) = 81 bytes a 16 indexes
|
||||||
|
// combined in one string because reading a two dimensional array is not possible
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = HMIConstants.StringLength * HMIConstants.NumInterlocks)]
|
||||||
|
public byte[] asProcessINTLKName;
|
||||||
|
|
||||||
|
// 16 * String(80) = 81 bytes a 16 indexes
|
||||||
|
// combined in one string because reading a two dimensional array is not possible
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = HMIConstants.StringLength * HMIConstants.NumInterlocks)]
|
||||||
|
public byte[] asSafetyINTLKName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xProcessINTLKOk;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xSafetyINTLKOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwinCAT2 Pack = 1, TwinCAT 3 Pack = 0
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIValveData
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HMIConstants.StringLength)]
|
||||||
|
public string sName;
|
||||||
|
|
||||||
|
public HMIControlButton stAutomaticButton;
|
||||||
|
|
||||||
|
public HMIControlButton stManualButton;
|
||||||
|
|
||||||
|
public HMIControlButton stOpenButton;
|
||||||
|
|
||||||
|
public HMIControlButton stCloseButton;
|
||||||
|
|
||||||
|
// 1 = Opened, 2 = Opening/Closing, 3 = Closed, 4 = Error
|
||||||
|
public short iStatus;
|
||||||
|
|
||||||
|
// 1 = Automatic mode, 2 = Manual mode
|
||||||
|
public short iCurrentMode;
|
||||||
|
|
||||||
|
public HMIInterlock stInterlock;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIAnalogValveData
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HMIConstants.StringLength)]
|
||||||
|
public string sName;
|
||||||
|
|
||||||
|
public HMIControlButton stAutomaticButton;
|
||||||
|
|
||||||
|
public HMIControlButton stManualButton;
|
||||||
|
|
||||||
|
public HMIControlButton stOpenButton;
|
||||||
|
|
||||||
|
public HMIControlButton stCloseButton;
|
||||||
|
|
||||||
|
// 1 = Opened, 2 = Opening/Closing, 3 = Closed, 4 = Error
|
||||||
|
public short iStatus;
|
||||||
|
|
||||||
|
// 1 = Automatic mode, 2 = Manual mode
|
||||||
|
public short iCurrentMode;
|
||||||
|
|
||||||
|
public HMIInterlock stInterlock;
|
||||||
|
|
||||||
|
HMIAnalogValue stSetpoint;
|
||||||
|
|
||||||
|
HMIAnalogValue stProcessValue;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwinCAT2 Pack = 1, TwinCAT 3 Pack = 0
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIAnalogMotorData
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HMIConstants.StringLength)]
|
||||||
|
public string sName;
|
||||||
|
|
||||||
|
public HMIControlButton stAutomaticButton;
|
||||||
|
|
||||||
|
public HMIControlButton stManualButton;
|
||||||
|
|
||||||
|
public HMIControlButton stStartButton;
|
||||||
|
|
||||||
|
public HMIControlButton stStopButton;
|
||||||
|
|
||||||
|
// 1 = Opened, 2 = Opening/Closing, 3 = Closed, 4 = Error
|
||||||
|
public short iStatus;
|
||||||
|
|
||||||
|
// 1 = Automatic mode, 2 = Manual mode
|
||||||
|
public short iCurrentMode;
|
||||||
|
|
||||||
|
public HMIAnalogValue stSetpoint;
|
||||||
|
|
||||||
|
public HMIAnalogValue stProcessValue;
|
||||||
|
|
||||||
|
public HMIInterlock stInterlock;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwinCAT2 Pack = 1, TwinCAT 3 Pack = 0
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||||
|
public struct HMIOrpSensorData
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HMIConstants.StringLength)]
|
||||||
|
public string sName;
|
||||||
|
|
||||||
|
// 1 = Ok, 2 = Error
|
||||||
|
public short iStatus;
|
||||||
|
|
||||||
|
public float rValuePH;
|
||||||
|
|
||||||
|
public float rValueTemp;
|
||||||
|
|
||||||
|
public float rValueORP;
|
||||||
|
|
||||||
|
public float rValueDLI;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool xUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class HMIUtilities
|
||||||
|
{
|
||||||
|
// Converts the interlock byte array into a string array
|
||||||
|
public static string[] GetInterlockStringArray(byte[] byteArray)
|
||||||
|
{
|
||||||
|
string[] temp = new string[HMIConstants.NumInterlocks];
|
||||||
|
int size;
|
||||||
|
|
||||||
|
// Check if byteArray is of correct size
|
||||||
|
if (byteArray.Length != (HMIConstants.StringLength * HMIConstants.NumInterlocks))
|
||||||
|
return temp;
|
||||||
|
|
||||||
|
for (int i = 0; i < HMIConstants.NumInterlocks; i++)
|
||||||
|
{
|
||||||
|
// Calculate length of string by finding the 0 terminator so the unused bytes get truncated
|
||||||
|
size = Array.IndexOf(byteArray, (byte)0, i * HMIConstants.StringLength) - (i * HMIConstants.StringLength);
|
||||||
|
|
||||||
|
// Check if we found a valid 0 terminator
|
||||||
|
if (size >= 0)
|
||||||
|
// Build string from byteArray with calculated size
|
||||||
|
temp[i] = Encoding.ASCII.GetString(byteArray, i * HMIConstants.StringLength, size);
|
||||||
|
else
|
||||||
|
// No valid 0 string terminator was found so return an empty string
|
||||||
|
temp[i] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
85
uniper_hmi/UniperHMI/MainWindow.xaml
Normal file
85
uniper_hmi/UniperHMI/MainWindow.xaml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<Window x:Class="UniperHMI.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||||
|
xmlns:local="clr-namespace:UniperHMI" xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:Name="MainControlWindow"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:MainWindowVM, IsDesignTimeCreatable=False}"
|
||||||
|
WindowStartupLocation="CenterScreen"
|
||||||
|
Title="Uniper HMI" Height="800" Width="1024" ResizeMode="NoResize">
|
||||||
|
|
||||||
|
<Grid HorizontalAlignment="Stretch">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"></RowDefinition>
|
||||||
|
<RowDefinition Height="Auto"></RowDefinition>
|
||||||
|
<RowDefinition Height="*"></RowDefinition>
|
||||||
|
<RowDefinition Height="Auto"></RowDefinition>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Latest event line -->
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<Border BorderThickness="0px 0px 0px 2px" BorderBrush="White" Background="Black">
|
||||||
|
<Label Content="{Binding EventsPageVM.CurrentEvent.Message}" FontSize="20" Height="45" VerticalAlignment="Center" HorizontalAlignment="Left" Visibility="{Binding StatusBarVisible}"/>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Breadcrumb line -->
|
||||||
|
<Label Grid.Row="1" Content="{Binding Breadcrumb}"/>
|
||||||
|
|
||||||
|
<!-- Page frame -->
|
||||||
|
<Frame x:Name="MainFrame" NavigationUIVisibility="Hidden" Content="{Binding CurrentPage}" Grid.Row="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
|
||||||
|
|
||||||
|
<!-- Softkey grid -->
|
||||||
|
<Grid Grid.Row="3" Margin="5,5,3,5" Width="Auto">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Softkey 1 -->
|
||||||
|
<Button Grid.Column="0" MinWidth="80" MinHeight="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth}" Margin="0,0,2,0" Content="Automatic" Command="{Binding AutomaticModeClickedCommand}"/>
|
||||||
|
<!-- Command="{Binding AutomaticModeCommand}" -->
|
||||||
|
|
||||||
|
<!-- Softkey 2 -->
|
||||||
|
<Button Grid.Column="1" MinWidth="80" MinHeight="80" Margin="0,0,2,0" Content="Manual" Command="{Binding ManualModeClickedCommand}" />
|
||||||
|
<!-- Command="{Binding ManualModeCommand}" -->
|
||||||
|
|
||||||
|
<!-- Softkey 3 -->
|
||||||
|
<Button Grid.Column="2" MinWidth="80" MinHeight="80" Margin="0,0,2,0" Content="Settings" Command="{Binding SettingsWindowCommand}" />
|
||||||
|
<!-- Command="{Binding SettingsWindowCommand}" -->
|
||||||
|
|
||||||
|
<!-- Softkey 4 -->
|
||||||
|
<Button Grid.Column="3" MinWidth="80" MinHeight="80" Margin="0,0,2,0" Content="Events" Command="{Binding EventsListClickedCommand}"/>
|
||||||
|
|
||||||
|
<!-- Softkey 5 -->
|
||||||
|
<Button Grid.Column="4" MinWidth="80" MinHeight="80" Margin="0,0,2,0" />
|
||||||
|
|
||||||
|
<!-- Softkey 6 -->
|
||||||
|
<Button Grid.Column="5" MinWidth="80" MinHeight="80" Margin="0,0,2,0" />
|
||||||
|
|
||||||
|
<!-- Softkey 7 -->
|
||||||
|
<Button Grid.Column="6" MinWidth="80" MinHeight="80" Margin="0,0,2,0" />
|
||||||
|
|
||||||
|
<!-- Softkey 8 -->
|
||||||
|
<Button Grid.Column="7" Content="Ack Alarms" Command="{Binding AckAlarmsCommand}" MinWidth="80" MinHeight="80" Margin="0,0,2,0" />
|
||||||
|
|
||||||
|
<!-- Softkey 9 -->
|
||||||
|
<Button Grid.Column="8" MinWidth="80" MinHeight="80" Margin="0,0,2,0" />
|
||||||
|
|
||||||
|
<!-- Softkey 10 -->
|
||||||
|
<Button Grid.Column="9" Content="Back" Command="{Binding NavigateBackCommand}" IsEnabled="{Binding CanNavigateBack}" MinWidth="80" MinHeight="80" Margin="0,0,2,0" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
26
uniper_hmi/UniperHMI/MainWindow.xaml.cs
Normal file
26
uniper_hmi/UniperHMI/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using HMIToolkit;
|
||||||
|
using MahApps.Metro.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public MainWindow(MainWindowVM mainWindowVM)
|
||||||
|
{
|
||||||
|
this.DataContext = mainWindowVM;
|
||||||
|
InitializeComponent();
|
||||||
|
Closed += OnClosedEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClosedEvent(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is IDisposable dataContext)
|
||||||
|
dataContext.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
273
uniper_hmi/UniperHMI/MainWindowVM.cs
Normal file
273
uniper_hmi/UniperHMI/MainWindowVM.cs
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using TcEventLoggerAdsProxyLib;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public sealed partial class MainWindowVM : ObservableObject, IRecipient<NavigateMessage>, IDisposable
|
||||||
|
{
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private StringControlButtonVM dummyStringVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Page currentPage;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canNavigateBack;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Visibility statusBarVisible;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string breadcrumb;
|
||||||
|
|
||||||
|
|
||||||
|
private readonly IAdsManager _adsManager;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly TcEventLogger _eventlogger;
|
||||||
|
|
||||||
|
// Last active event
|
||||||
|
[ObservableProperty]
|
||||||
|
private string currentActiveEvent = "";
|
||||||
|
|
||||||
|
private readonly object _lock = new();
|
||||||
|
|
||||||
|
// Empty page
|
||||||
|
private readonly Page _emptyPage;
|
||||||
|
|
||||||
|
// Last navigate message
|
||||||
|
private readonly Stack<NavigateMessage> _messageStack = new();
|
||||||
|
NavigateMessage? _currentMessage;
|
||||||
|
|
||||||
|
// Events page view model
|
||||||
|
[ObservableProperty]
|
||||||
|
EventsPageVM _eventsPageVM;
|
||||||
|
|
||||||
|
// Settings page viem model
|
||||||
|
SettingsPageVM? _settingsPageVM;
|
||||||
|
|
||||||
|
public MainWindowVM(IAdsManager adsManager, IConfiguration config, TcEventLogger eventLogger)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_config = config;
|
||||||
|
|
||||||
|
// Create dummy string
|
||||||
|
DummyStringVM = new StringControlButtonVM();
|
||||||
|
|
||||||
|
// Create empty page
|
||||||
|
_emptyPage = new();
|
||||||
|
|
||||||
|
// Create events page viewmodel
|
||||||
|
_eventlogger = eventLogger;
|
||||||
|
_eventsPageVM = new(_eventlogger);
|
||||||
|
|
||||||
|
CurrentPage = _emptyPage;
|
||||||
|
_currentMessage = new NavigateMessage("", typeof(Page));
|
||||||
|
_messageStack.Push(_currentMessage);
|
||||||
|
|
||||||
|
WeakReferenceMessenger.Default.Register<NavigateMessage>(this);
|
||||||
|
|
||||||
|
breadcrumb = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void SettingsWindow()
|
||||||
|
{
|
||||||
|
StatusBarVisible = Visibility.Visible;
|
||||||
|
_messageStack.Clear();
|
||||||
|
NavigateMessage message = new("", typeof(SettingsPage));
|
||||||
|
Receive(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void AutomaticModeClicked()
|
||||||
|
{
|
||||||
|
StatusBarVisible = Visibility.Visible;
|
||||||
|
_messageStack.Clear();
|
||||||
|
_currentMessage = new NavigateMessage("", typeof(Page));
|
||||||
|
NavigateMessage message = new(_config["AutomaticModeVarName"]!, typeof(AutomaticModePage));
|
||||||
|
Receive(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void ManualModeClicked()
|
||||||
|
{
|
||||||
|
StatusBarVisible = Visibility.Visible;
|
||||||
|
_messageStack.Clear();
|
||||||
|
_currentMessage = new NavigateMessage("", typeof(Page));
|
||||||
|
NavigateMessage message = new("", typeof(BatteryOverviewPage));
|
||||||
|
Receive(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void EventsListClicked()
|
||||||
|
{
|
||||||
|
StatusBarVisible = Visibility.Collapsed;
|
||||||
|
_messageStack.Clear();
|
||||||
|
_currentMessage = new NavigateMessage("", typeof(Page));
|
||||||
|
NavigateMessage message = new("", typeof(EventsPage));
|
||||||
|
Receive(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void NavigateBack()
|
||||||
|
{
|
||||||
|
if (_messageStack.Count == 0)
|
||||||
|
{
|
||||||
|
CanNavigateBack = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentMessage = _messageStack.Pop();
|
||||||
|
|
||||||
|
// Update if we can use the navigate back button
|
||||||
|
if (_messageStack.Count > 0)
|
||||||
|
CanNavigateBack = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusBarVisible = Visibility.Visible;
|
||||||
|
CanNavigateBack = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove last two entrys from Breadcrumbs
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
index = Breadcrumb.LastIndexOf('>');
|
||||||
|
if (index != -1)
|
||||||
|
Breadcrumb = Breadcrumb[..index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to page
|
||||||
|
Navigate(_currentMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use for forward traversal!
|
||||||
|
public void Receive(NavigateMessage message)
|
||||||
|
{
|
||||||
|
// Only change page if its a new page type
|
||||||
|
if (CurrentPage.GetType() == message.type)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Push current message
|
||||||
|
if (_currentMessage != null)
|
||||||
|
_messageStack.Push(_currentMessage);
|
||||||
|
|
||||||
|
// Save current message for later push
|
||||||
|
_currentMessage = message;
|
||||||
|
|
||||||
|
// Set can navigate back
|
||||||
|
CanNavigateBack = true;
|
||||||
|
|
||||||
|
Navigate(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Navigate(NavigateMessage message)
|
||||||
|
{
|
||||||
|
// Dispose current pages viewmodel
|
||||||
|
if (CurrentPage.DataContext is IDisposable viewModel)
|
||||||
|
{
|
||||||
|
CurrentPage.DataContext = null;
|
||||||
|
viewModel.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new page
|
||||||
|
switch (message.type.Name)
|
||||||
|
{
|
||||||
|
case nameof(AutomaticModePage):
|
||||||
|
var automaticModeViewModel = (AutomaticModePageVM)ActivatorUtilities.CreateInstance(App.AppHost!.Services, typeof(AutomaticModePageVM), message.VariableName); //App.AppHost!.Services.GetRequiredService<AutomaticModePageVM>();
|
||||||
|
AutomaticModePage automaticModePage = new() { DataContext = automaticModeViewModel };
|
||||||
|
CurrentPage = automaticModePage;
|
||||||
|
Breadcrumb = "> Automatic";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(BatteryOverviewPage):
|
||||||
|
var batteryOverviewPageVM = App.AppHost!.Services.GetRequiredService<BatteryOverviewPageVM>();
|
||||||
|
BatteryOverviewPage batteryOverviewPage = new() { DataContext = batteryOverviewPageVM };
|
||||||
|
CurrentPage = batteryOverviewPage;
|
||||||
|
Breadcrumb = "> Manual";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(StringOverviewPage):
|
||||||
|
var stringOverviewVM = (StringOverviewPageVM)ActivatorUtilities.CreateInstance(App.AppHost!.Services, typeof(StringOverviewPageVM), message.VariableName);
|
||||||
|
StringOverviewPage stringPage = new() { DataContext = stringOverviewVM };
|
||||||
|
CurrentPage = stringPage;
|
||||||
|
if (message.Header.Length > 0)
|
||||||
|
AppendBreadcrumb(message.Header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ModuleOverviewPage):
|
||||||
|
var moduleOverviewVM = (ModuleOverviewPageVM)ActivatorUtilities.CreateInstance(App.AppHost!.Services, typeof(ModuleOverviewPageVM), message.VariableName);
|
||||||
|
ModuleOverviewPage modulePage = new() { DataContext = moduleOverviewVM };
|
||||||
|
CurrentPage = modulePage;
|
||||||
|
if (message.Header.Length > 0)
|
||||||
|
AppendBreadcrumb(message.Header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(UnitOverviewPage):
|
||||||
|
var unitOverviewVM = (UnitOverviewPageVM)ActivatorUtilities.CreateInstance(App.AppHost!.Services, typeof(UnitOverviewPageVM), message.VariableName);
|
||||||
|
unitOverviewVM.UnitName = message.Header;
|
||||||
|
UnitOverviewPage unitPage = new() { DataContext = unitOverviewVM };
|
||||||
|
CurrentPage = unitPage;
|
||||||
|
if (message.Header.Length > 0)
|
||||||
|
AppendBreadcrumb(message.Header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(EventsPage):
|
||||||
|
#pragma warning disable MVVMTK0034 // Direct field reference to [ObservableProperty] backing field
|
||||||
|
EventsPage eventsPage = new() { DataContext = _eventsPageVM };
|
||||||
|
#pragma warning restore MVVMTK0034 // Direct field reference to [ObservableProperty] backing field
|
||||||
|
CurrentPage = eventsPage;
|
||||||
|
Breadcrumb = " > Events";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(SettingsPage):
|
||||||
|
// Create seetings page view model only once
|
||||||
|
if (_settingsPageVM == null)
|
||||||
|
_settingsPageVM = new(_adsManager, "GVL_CONFIG.stUnitConfig");
|
||||||
|
|
||||||
|
SettingsPage settingsPage = new() { DataContext = _settingsPageVM };
|
||||||
|
CurrentPage = settingsPage;
|
||||||
|
Breadcrumb = " > Settings";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CurrentPage = new Page();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendBreadcrumb(string path)
|
||||||
|
{
|
||||||
|
if (Breadcrumb[^1] != ' ')
|
||||||
|
Breadcrumb += " > " + path;
|
||||||
|
else
|
||||||
|
Breadcrumb += "> " + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void AckAlarms()
|
||||||
|
{
|
||||||
|
_adsManager.WriteValue("GVL_SCADA.stAckAlarmsButton.xRequest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Dispose current pages viewmodel
|
||||||
|
if (CurrentPage.DataContext is IDisposable viewModel)
|
||||||
|
{
|
||||||
|
CurrentPage.DataContext = null;
|
||||||
|
viewModel.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
DummyStringVM.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
3
uniper_hmi/UniperHMI/NavigateMessage.cs
Normal file
3
uniper_hmi/UniperHMI/NavigateMessage.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public record class NavigateMessage(string VariableName, Type type, string Header = "");
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public sealed partial class ModuleControlButtonVM : SMUBaseVM, IDisposable
|
||||||
|
{
|
||||||
|
public ModuleControlButtonVM() : base() { }
|
||||||
|
|
||||||
|
public ModuleControlButtonVM(IAdsManager adsManager, string variableName) : base(adsManager, variableName) { }
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName, typeof(ModuleOverviewPage)));
|
||||||
|
}
|
||||||
|
}
|
||||||
60
uniper_hmi/UniperHMI/OwnControls/ViewModels/SMUBaseVM.cs
Normal file
60
uniper_hmi/UniperHMI/OwnControls/ViewModels/SMUBaseVM.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public enum E_COMPONENT_STATUS : short
|
||||||
|
{
|
||||||
|
OFF = 0,
|
||||||
|
ON = 1,
|
||||||
|
CHARGING = 2,
|
||||||
|
DISCHARGING = 3,
|
||||||
|
ERROR = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class SMUBaseVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
protected float voltage;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
protected E_COMPONENT_STATUS status;
|
||||||
|
|
||||||
|
protected readonly string _variableName;
|
||||||
|
|
||||||
|
protected readonly IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public SMUBaseVM()
|
||||||
|
{
|
||||||
|
_variableName = string.Empty;
|
||||||
|
_adsManager = null;
|
||||||
|
voltage = 0.0f;
|
||||||
|
status = E_COMPONENT_STATUS.OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SMUBaseVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
Status = E_COMPONENT_STATUS.OFF;
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
_adsManager!.Register(_variableName + ".rVoltage", VoltageChanged);
|
||||||
|
_adsManager.Register(_variableName + ".eStatus", StatusChanged);
|
||||||
|
}
|
||||||
|
protected void VoltageChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Voltage = (float)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void StatusChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Status = (E_COMPONENT_STATUS)((short)e.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName + ".rVoltage", VoltageChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".eStatus", StatusChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public sealed partial class StringControlButtonVM : SMUBaseVM, IDisposable
|
||||||
|
{
|
||||||
|
public StringControlButtonVM() : base() { }
|
||||||
|
|
||||||
|
public StringControlButtonVM(IAdsManager adsManager, string variableName) : base(adsManager, variableName) { }
|
||||||
|
|
||||||
|
//[RelayCommand]
|
||||||
|
//private void Clicked()
|
||||||
|
//{
|
||||||
|
// WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName, typeof(StringOverviewPage)));
|
||||||
|
//}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI.OwnControls
|
||||||
|
{
|
||||||
|
public sealed partial class UnitControlButtonVM : SMUBaseVM
|
||||||
|
{
|
||||||
|
public UnitControlButtonVM() : base() { }
|
||||||
|
|
||||||
|
public UnitControlButtonVM(IAdsManager adsManager, string variableName) : base(adsManager, variableName) { }
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName, typeof(UnitDetailsControl)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,494 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using HMIToolkit;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
public sealed partial class UnitDetailsControlVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private float rVoltage;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private E_COMPONENT_STATUS status;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AnalogValueVM pressureNegolytSegmentInVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AnalogValueVM pressureNegolytTankInVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AnalogValueVM temperatureNegolytTankInVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AnalogValueVM pressurePosolytSegmentInVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AnalogValueVM pressurePosolytTankInVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AnalogValueVM temperaturePosolytTankInVM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canOpenBothValves;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canCloseBothValves;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private short feedbackOpenValves;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private short feedbackCloseValves;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canStartBothPumps;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canStopBothPumps;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private short feedbackStartPumps;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private short feedbackStopPumps;
|
||||||
|
|
||||||
|
private float _posolytPumpOnSpeed;
|
||||||
|
private float _negolytPumpOnSpeed;
|
||||||
|
|
||||||
|
private float valveWindowHorizontalPosition;
|
||||||
|
|
||||||
|
private readonly BinaryValveControlVM _valveNegolytVM;
|
||||||
|
private readonly BinaryValveControlVM _valvePosolytVM;
|
||||||
|
private readonly AnalogMotorControlVM _pumpNegolytVM;
|
||||||
|
private readonly AnalogMotorControlVM _pumpPosolytVM;
|
||||||
|
|
||||||
|
private BinaryValveWindow? _windowValveNegolyt;
|
||||||
|
private BinaryValveWindow? _windowValvePosolyt;
|
||||||
|
|
||||||
|
private AnalogMotorWindow? _windowPumpNegolyt;
|
||||||
|
private AnalogMotorWindow? _windowPumpPosolyt;
|
||||||
|
|
||||||
|
private readonly IAdsManager? _adsManager;
|
||||||
|
private readonly string _variableName;
|
||||||
|
|
||||||
|
public UnitDetailsControlVM()
|
||||||
|
{
|
||||||
|
Status = E_COMPONENT_STATUS.OFF;
|
||||||
|
rVoltage = 0.0f;
|
||||||
|
_variableName = "";
|
||||||
|
|
||||||
|
// Negolyt
|
||||||
|
PressureNegolytSegmentInVM = new AnalogValueVM();
|
||||||
|
PressureNegolytTankInVM = new AnalogValueVM();
|
||||||
|
TemperatureNegolytTankInVM = new AnalogValueVM();
|
||||||
|
_valveNegolytVM = new BinaryValveControlVM();
|
||||||
|
_pumpNegolytVM = new AnalogMotorControlVM();
|
||||||
|
|
||||||
|
_windowValveNegolyt = null;
|
||||||
|
|
||||||
|
// Posolyt
|
||||||
|
PressurePosolytSegmentInVM = new AnalogValueVM();
|
||||||
|
PressurePosolytTankInVM = new AnalogValueVM();
|
||||||
|
TemperaturePosolytTankInVM = new AnalogValueVM();
|
||||||
|
_valvePosolytVM = new BinaryValveControlVM();
|
||||||
|
_pumpPosolytVM = new AnalogMotorControlVM();
|
||||||
|
|
||||||
|
_windowValvePosolyt = null;
|
||||||
|
|
||||||
|
valveWindowHorizontalPosition = 10;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitDetailsControlVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
|
||||||
|
Status = E_COMPONENT_STATUS.OFF;
|
||||||
|
rVoltage = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
|
// Negolyt
|
||||||
|
PressureNegolytSegmentInVM = new AnalogValueVM(_adsManager, _variableName + ".stP21", true);
|
||||||
|
PressureNegolytTankInVM = new AnalogValueVM(_adsManager, _variableName + ".stP22", true);
|
||||||
|
TemperatureNegolytTankInVM = new AnalogValueVM(_adsManager, _variableName + ".stT21", true);
|
||||||
|
_valveNegolytVM = new BinaryValveControlVM(_adsManager, _variableName + ".stNS22");
|
||||||
|
_valveNegolytVM.OpenButton.FeedbackChanged += OnValveNegolytOpenFeedbackChanged;
|
||||||
|
_valveNegolytVM.CloseButton.FeedbackChanged += OnValveNegolytCloseFeedbackChanged;
|
||||||
|
_valveNegolytVM.OpenButton.ReleaseChanged += OnValveNegolytOpenReleaseChanged;
|
||||||
|
_valveNegolytVM.CloseButton.ReleaseChanged += OnValveNegolytCloseReleaseChanged;
|
||||||
|
_pumpNegolytVM = new AnalogMotorControlVM(_adsManager, _variableName + ".stNS21");
|
||||||
|
_pumpNegolytVM.StartButton.FeedbackChanged += OnPumpNegolytStartFeedbackChanged;
|
||||||
|
_pumpNegolytVM.StopButton.FeedbackChanged += OnPumpNegolytStopFeedbackChanged;
|
||||||
|
_pumpNegolytVM.StartButton.ReleaseChanged += OnPumpNegolytStartReleaseChanged;
|
||||||
|
_pumpNegolytVM.StopButton.ReleaseChanged += OnPumpNegolytStopReleaseChanged;
|
||||||
|
|
||||||
|
|
||||||
|
// Posolyt
|
||||||
|
PressurePosolytSegmentInVM = new AnalogValueVM(_adsManager, _variableName + ".stP11", true);
|
||||||
|
PressurePosolytTankInVM = new AnalogValueVM(_adsManager, _variableName + ".stP12", true);
|
||||||
|
TemperaturePosolytTankInVM = new AnalogValueVM(_adsManager, _variableName + ".stT11", true);
|
||||||
|
_valvePosolytVM = new BinaryValveControlVM(_adsManager, _variableName + ".stNS12");
|
||||||
|
_valvePosolytVM.OpenButton.FeedbackChanged += OnValvePosolytOpenFeedbackChanged;
|
||||||
|
_valvePosolytVM.CloseButton.FeedbackChanged += OnValvePosolytCloseFeedbackChanged;
|
||||||
|
_valvePosolytVM.OpenButton.ReleaseChanged += OnValvePosolytOpenReleaseChanged;
|
||||||
|
_valvePosolytVM.CloseButton.ReleaseChanged += OnValvePosolytCloseReleaseChanged;
|
||||||
|
_pumpPosolytVM = new AnalogMotorControlVM(_adsManager, _variableName + ".stNS11");
|
||||||
|
_pumpPosolytVM.StartButton.FeedbackChanged += OnPumpPosolytStartFeedbackChanged;
|
||||||
|
_pumpPosolytVM.StopButton.FeedbackChanged += OnPumpPosolytStopFeedbackChanged;
|
||||||
|
_pumpPosolytVM.StartButton.ReleaseChanged += OnPumpPosolytStartReleaseChanged;
|
||||||
|
_pumpPosolytVM.StopButton.ReleaseChanged += OnPumpPosolytStopReleaseChanged;
|
||||||
|
|
||||||
|
|
||||||
|
// Current status
|
||||||
|
_adsManager.Register(_variableName + ".eStatus", StatusChanged);
|
||||||
|
_adsManager.Register(_variableName + ".rVoltage", VoltageChanged);
|
||||||
|
|
||||||
|
|
||||||
|
// Configured pump speed for on
|
||||||
|
_adsManager.Register("GVL_CONFIG.rPumpNegolytOnPower", NegolytPumpOnSpeedChanged);
|
||||||
|
_adsManager.Register("GVL_CONFIG.rPumpPosolytOnPower", PosolytPumpOnSpeedChanged);
|
||||||
|
|
||||||
|
valveWindowHorizontalPosition = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NegolytPumpOnSpeedChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_negolytPumpOnSpeed = (float)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PosolytPumpOnSpeedChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_posolytPumpOnSpeed = (float)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VoltageChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
RVoltage = (float)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Dispose all necessary view models
|
||||||
|
// Negolyt
|
||||||
|
PressureNegolytSegmentInVM.Dispose();
|
||||||
|
PressureNegolytTankInVM.Dispose();
|
||||||
|
TemperatureNegolytTankInVM.Dispose();
|
||||||
|
_valveNegolytVM.OpenButton.FeedbackChanged -= OnValveNegolytOpenFeedbackChanged;
|
||||||
|
_valveNegolytVM.CloseButton.FeedbackChanged -= OnValveNegolytCloseFeedbackChanged;
|
||||||
|
_valveNegolytVM.OpenButton.ReleaseChanged -= OnValveNegolytOpenReleaseChanged;
|
||||||
|
_valveNegolytVM.CloseButton.ReleaseChanged -= OnValveNegolytCloseReleaseChanged;
|
||||||
|
_valveNegolytVM.Dispose();
|
||||||
|
_pumpNegolytVM.Dispose();
|
||||||
|
|
||||||
|
// Posolyt
|
||||||
|
PressurePosolytSegmentInVM.Dispose();
|
||||||
|
PressurePosolytTankInVM.Dispose();
|
||||||
|
TemperaturePosolytTankInVM.Dispose();
|
||||||
|
_valvePosolytVM.OpenButton.FeedbackChanged -= OnValvePosolytOpenFeedbackChanged;
|
||||||
|
_valvePosolytVM.CloseButton.FeedbackChanged -= OnValvePosolytCloseFeedbackChanged;
|
||||||
|
_valvePosolytVM.OpenButton.ReleaseChanged -= OnValvePosolytOpenReleaseChanged;
|
||||||
|
_valvePosolytVM.CloseButton.ReleaseChanged -= OnValvePosolytCloseReleaseChanged;
|
||||||
|
_valvePosolytVM.Dispose();
|
||||||
|
_pumpPosolytVM.Dispose();
|
||||||
|
|
||||||
|
// Deregister variables
|
||||||
|
_adsManager?.Deregister(_variableName + ".eStatus", StatusChanged);
|
||||||
|
_adsManager?.Deregister(_variableName + ".rVoltage", VoltageChanged);
|
||||||
|
_adsManager?.Deregister("GVL_CONFIG.rPumpNegolytOnPower", NegolytPumpOnSpeedChanged);
|
||||||
|
_adsManager?.Deregister("GVL_CONFIG.rPumpPosolytOnPower", PosolytPumpOnSpeedChanged);
|
||||||
|
|
||||||
|
// Destroy windows
|
||||||
|
_windowValveNegolyt?.Close();
|
||||||
|
_windowValvePosolyt?.Close();
|
||||||
|
_windowPumpNegolyt?.Close();
|
||||||
|
_windowPumpPosolyt?.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StatusChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Status = (E_COMPONENT_STATUS)((short)e.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ShowValveNegolyt()
|
||||||
|
{
|
||||||
|
if (_adsManager != null && _windowValveNegolyt == null)
|
||||||
|
{
|
||||||
|
_windowValveNegolyt = new() { DataContext = _valveNegolytVM };
|
||||||
|
_windowValveNegolyt.Closed += WindowValveNegolyt_Closed;
|
||||||
|
_windowValveNegolyt.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WindowValveNegolyt_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_windowValveNegolyt!.Close();
|
||||||
|
_windowValveNegolyt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ShowValvePosolyt()
|
||||||
|
{
|
||||||
|
if (_adsManager != null && _windowValvePosolyt == null)
|
||||||
|
{
|
||||||
|
_windowValvePosolyt = new() { DataContext = _valvePosolytVM };
|
||||||
|
_windowValvePosolyt.Closed += WindowValvePosolyt_Closed;
|
||||||
|
_windowValvePosolyt.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WindowValvePosolyt_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_windowValvePosolyt!.Close();
|
||||||
|
_windowValvePosolyt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void ShowPumpNegolyt()
|
||||||
|
{
|
||||||
|
if (_adsManager != null && _windowPumpNegolyt == null)
|
||||||
|
{
|
||||||
|
_windowPumpNegolyt = new() { DataContext = _pumpNegolytVM };
|
||||||
|
_windowPumpNegolyt.Closed += WindowPumpNegolyt_Closed;
|
||||||
|
_windowPumpNegolyt.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WindowPumpNegolyt_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_windowPumpNegolyt!.Close();
|
||||||
|
_windowPumpNegolyt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void ShowPumpPosolyt()
|
||||||
|
{
|
||||||
|
if (_adsManager != null && _windowPumpPosolyt == null)
|
||||||
|
{
|
||||||
|
_windowPumpPosolyt = new() { DataContext = _pumpPosolytVM };
|
||||||
|
_windowPumpPosolyt.Closed += WindowPumpPosolyt_Closed;
|
||||||
|
_windowPumpPosolyt.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void OpenBothValves()
|
||||||
|
{
|
||||||
|
_valveNegolytVM.OpenButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
_valvePosolytVM.OpenButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void CloseBothValves()
|
||||||
|
{
|
||||||
|
_valveNegolytVM.CloseButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
_valvePosolytVM.CloseButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValveNegolytOpenFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateOpenFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValvePosolytOpenFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateOpenFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateOpenFeedback()
|
||||||
|
{
|
||||||
|
if (_valveNegolytVM?.OpenButton.IFeedback == 1 && _valvePosolytVM?.OpenButton.IFeedback == 1)
|
||||||
|
FeedbackOpenValves = 1;
|
||||||
|
else if (_valveNegolytVM?.OpenButton.IFeedback == 0 && _valvePosolytVM?.OpenButton.IFeedback == 0)
|
||||||
|
FeedbackOpenValves = 0;
|
||||||
|
else
|
||||||
|
FeedbackOpenValves = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValveNegolytCloseFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateCloseFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValvePosolytCloseFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateCloseFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateCloseFeedback()
|
||||||
|
{
|
||||||
|
if (_valveNegolytVM?.CloseButton.IFeedback == 1 && _valvePosolytVM?.CloseButton.IFeedback == 1)
|
||||||
|
FeedbackCloseValves = 1;
|
||||||
|
else if (_valveNegolytVM?.CloseButton.IFeedback == 0 && _valvePosolytVM?.CloseButton.IFeedback == 0)
|
||||||
|
FeedbackCloseValves = 0;
|
||||||
|
else
|
||||||
|
FeedbackCloseValves = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValveNegolytOpenReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateOpenRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValvePosolytOpenReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateOpenRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateOpenRelease()
|
||||||
|
{
|
||||||
|
if (_valvePosolytVM == null || _valveNegolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_valveNegolytVM.OpenButton.XRelease && _valvePosolytVM.OpenButton.XRelease)
|
||||||
|
CanOpenBothValves = true;
|
||||||
|
else
|
||||||
|
CanOpenBothValves = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValveNegolytCloseReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateCloseRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValvePosolytCloseReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateCloseRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateCloseRelease()
|
||||||
|
{
|
||||||
|
if (_valvePosolytVM == null || _valveNegolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_valveNegolytVM.CloseButton.XRelease && _valvePosolytVM.CloseButton.XRelease)
|
||||||
|
CanCloseBothValves = true;
|
||||||
|
else
|
||||||
|
CanCloseBothValves = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void StartBothPumps()
|
||||||
|
{
|
||||||
|
if (_adsManager == null || _pumpNegolytVM == null || _pumpPosolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_pumpNegolytVM.Setpoint.RValue = _negolytPumpOnSpeed;
|
||||||
|
_pumpPosolytVM.Setpoint.RValue = _posolytPumpOnSpeed;
|
||||||
|
|
||||||
|
_pumpNegolytVM.StartButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
_pumpPosolytVM.StartButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void StopBothPumps()
|
||||||
|
{
|
||||||
|
_pumpNegolytVM.StopButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
_pumpPosolytVM.StopButton?.ButtonClickedCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateStartRelease()
|
||||||
|
{
|
||||||
|
if (_pumpNegolytVM == null || _pumpPosolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_pumpNegolytVM.StartButton.XRelease && _pumpPosolytVM.StartButton.XRelease)
|
||||||
|
CanStartBothPumps = true;
|
||||||
|
else
|
||||||
|
CanStartBothPumps = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculatStopRelease()
|
||||||
|
{
|
||||||
|
if (_pumpNegolytVM == null || _pumpPosolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_pumpNegolytVM.StopButton.XRelease && _pumpPosolytVM.StopButton.XRelease)
|
||||||
|
CanStopBothPumps = true;
|
||||||
|
else
|
||||||
|
CanStopBothPumps = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateStartFeedback()
|
||||||
|
{
|
||||||
|
if (_pumpNegolytVM == null || _pumpPosolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_pumpNegolytVM.StartButton.IFeedback == 1 && _pumpPosolytVM.StartButton.IFeedback == 1)
|
||||||
|
FeedbackStartPumps = 1;
|
||||||
|
else if (_pumpNegolytVM.StartButton.IFeedback == 0 && _pumpPosolytVM.StartButton.IFeedback == 0)
|
||||||
|
FeedbackStartPumps = 0;
|
||||||
|
else
|
||||||
|
FeedbackStartPumps = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateStopFeedback()
|
||||||
|
{
|
||||||
|
if (_pumpNegolytVM == null || _pumpPosolytVM == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_pumpNegolytVM.StopButton.IFeedback == 1 && _pumpPosolytVM.StopButton.IFeedback == 1)
|
||||||
|
FeedbackStopPumps = 1;
|
||||||
|
else if (_pumpNegolytVM.StopButton.IFeedback == 0 && _pumpPosolytVM.StopButton.IFeedback == 0)
|
||||||
|
FeedbackStopPumps = 0;
|
||||||
|
else
|
||||||
|
FeedbackStopPumps = 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpPosolytStopReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculatStopRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpPosolytStartReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateStartRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpPosolytStopFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateStopFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpPosolytStartFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateStartFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpNegolytStopReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculatStopRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpNegolytStartReleaseChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateStartRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpNegolytStopFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateStopFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPumpNegolytStartFeedbackChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CalculateStartFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WindowPumpPosolyt_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_windowPumpPosolyt!.Close();
|
||||||
|
_windowPumpPosolyt = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
uniper_hmi/UniperHMI/OwnControls/Views/SMUControlButton.xaml
Normal file
42
uniper_hmi/UniperHMI/OwnControls/Views/SMUControlButton.xaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<Button x:Class="UniperHMI.SMUControlButton"
|
||||||
|
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:UniperHMI"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:StringControlButtonVM, IsDesignTimeCreatable=True}"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Style="{StaticResource MahApps.Styles.Button}"
|
||||||
|
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
|
||||||
|
Width="Auto" Height="Auto"
|
||||||
|
x:Name="root">
|
||||||
|
|
||||||
|
<Grid x:Name="mainGrid" Width="Auto" Height="Auto">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Label Content="{Binding SMUName, ElementName=root}" Grid.Row="0" Grid.ColumnSpan="3" FontSize="24" HorizontalAlignment="Center"/>
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Line Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" X1="0" X2="{Binding ElementName=mainGrid, Path=ActualWidth}" Stroke="White" Margin="0,5,0,10"/>
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Label Grid.Row="2" Grid.Column="0" Content="Spannung:" />
|
||||||
|
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Voltage, StringFormat=N2}" MaxLines="1" Width="70" TextAlignment="Right" IsReadOnly="True" />
|
||||||
|
<Label Grid.Row="2" Grid.Column="2" Content="V" />
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Label Content="Status:" Grid.Row="3" Grid.Column="0" />
|
||||||
|
<Label Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Content="{Binding Status}" HorizontalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für StringControlButton.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class SMUControlButton : Button
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty SMUNameProperty = DependencyProperty.Register("SMUName", typeof(string), typeof(SMUControlButton));
|
||||||
|
public String SMUName
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(SMUNameProperty); }
|
||||||
|
set { SetValue(SMUNameProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public SMUControlButton()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
138
uniper_hmi/UniperHMI/OwnControls/Views/UnitDetailsControl.xaml
Normal file
138
uniper_hmi/UniperHMI/OwnControls/Views/UnitDetailsControl.xaml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<UserControl xmlns:HMIToolkit="clr-namespace:HMIToolkit" x:Class="UniperHMI.UnitDetailsControl"
|
||||||
|
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:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:UnitDetailsControlVM, IsDesignTimeCreatable=True}"
|
||||||
|
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Width="Auto" Height="Auto"
|
||||||
|
x:Name="root">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<HMIToolkit:FeedbackToColorConverter x:Key="feedbackConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Grid x:Name="mainGrid">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Row 0 -->
|
||||||
|
<Label Content="{Binding UnitName, ElementName=root}" Grid.Row="0" Grid.ColumnSpan="4" FontSize="24" HorizontalAlignment="Center"/>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<Line Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" X1="0" X2="{Binding ElementName=mainGrid, Path=ActualWidth}" Stroke="White" Margin="0,5,0,10"/>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Grid Grid.Row="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Width="Auto" HorizontalAlignment="Left">
|
||||||
|
<Label Content="Spannung:" />
|
||||||
|
<TextBox Text="{Binding RVoltage, StringFormat=N2}" MaxLines="1" Width="70" TextAlignment="Right" IsReadOnly="True" />
|
||||||
|
<Label Content="V" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||||
|
<Label Content="Status:" Margin="20,0,0,0"/>
|
||||||
|
<Label Grid.ColumnSpan="2" Content="{Binding Status}" HorizontalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<Line Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="4" X1="0" X2="{Binding ElementName=mainGrid, Path=ActualWidth}" Stroke="White" Margin="0,5,0,10"/>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<Grid Grid.Row="4">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Content="Negolyt:" FontWeight="Bold" HorizontalAlignment="Center"/>
|
||||||
|
<Label Grid.Row="0" Grid.Column="2" Content="Posolyt:" FontWeight="Bold" HorizontalAlignment="Center"/>
|
||||||
|
|
||||||
|
<Button Grid.Row="1" Grid.Column="0" Content="Tankventil" Command="{Binding ShowValveNegolytCommand}" HorizontalAlignment="Center" Width="100" />
|
||||||
|
<Button Grid.Row="1" Grid.Column="2" Content="Tankventil" Command="{Binding ShowValvePosolytCommand}" HorizontalAlignment="Center" Width="100" />
|
||||||
|
|
||||||
|
<!-- Open Close both valves -->
|
||||||
|
<Label Grid.Row="0" Grid.Column="1" Content="Both:" FontWeight="Bold" HorizontalAlignment="Center"/>
|
||||||
|
<Grid Grid.Row="1" Grid.Column="1">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button Grid.Column="0" Content="Open" Width="50" Command="{Binding OpenBothValvesCommand}" IsEnabled="{Binding CanOpenBothValves}" Background="{Binding FeedbackOpenValves, Converter={StaticResource feedbackConverter}}"/>
|
||||||
|
<Button Grid.Column="1" Content="Close" Width="50" Command="{Binding CloseBothValvesCommand}" IsEnabled="{Binding CanCloseBothValves}" Background="{Binding FeedbackCloseValves, Converter={StaticResource feedbackConverter}}" Margin="5,0,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Start stop both pumps -->
|
||||||
|
<Grid Grid.Row="2" Grid.Column="1">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button Grid.Column="0" Content="Start" Command="{Binding StartBothPumpsCommand}" IsEnabled="{Binding CanStartBothPumps}" Background="{Binding FeedbackStartPumps, Converter={StaticResource feedbackConverter}}" Width="50" Margin="0,5,0,0"/>
|
||||||
|
<Button Grid.Column="1" Content="Stop" Command="{Binding StopBothPumpsCommand}" IsEnabled="{Binding CanStopBothPumps}" Background="{Binding FeedbackStopPumps, Converter={StaticResource feedbackConverter}}" Width="50" Margin="5,5,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Button Grid.Row="2" Grid.Column="0" Content="Pumpe" Command="{Binding ShowPumpNegolytCommand}" HorizontalAlignment="Center" Width="100" Margin="0,5,0,0"/>
|
||||||
|
<Button Grid.Row="2" Grid.Column="2" Content="Pumpe" Command="{Binding ShowPumpPosolytCommand}" HorizontalAlignment="Center" Width="100" Margin="0,5,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<Line Grid.Row="5" X1="0" X2="{Binding ElementName=mainGrid, Path=ActualWidth}" Stroke="White" Margin="0,5,0,10"/>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<Grid Grid.Row="6">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Label Grid.Row="0" Grid.Column="1" Content="Negolyt:" FontWeight="Bold" />
|
||||||
|
<Label Grid.Row="0" Grid.Column="2" Content="Posolyt:" FontWeight="Bold" />
|
||||||
|
|
||||||
|
<Label Grid.Row="1" Grid.Column="0" Content="Druck Segment Inlet:" />
|
||||||
|
<HMIToolkit:AnalogValue Grid.Row="1" Grid.Column="1" DataContext="{Binding PressureNegolytSegmentInVM}" HorizontalAlignment="Left" />
|
||||||
|
<HMIToolkit:AnalogValue Grid.Row="1" Grid.Column="2" DataContext="{Binding PressurePosolytSegmentInVM}" HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<Label Grid.Row="2" Grid.Column="0" Content="Druck Tank Inlet:" Margin="0,5,0,0"/>
|
||||||
|
<HMIToolkit:AnalogValue Grid.Row="2" Grid.Column="1" DataContext="{Binding PressureNegolytTankInVM}" HorizontalAlignment="Left" Margin="0,5,0,0"/>
|
||||||
|
<HMIToolkit:AnalogValue Grid.Row="2" Grid.Column="2" DataContext="{Binding PressurePosolytTankInVM}" HorizontalAlignment="Left" Margin="0,5,0,0"/>
|
||||||
|
|
||||||
|
<Label Grid.Row="3" Grid.Column="0" Content="Temperatur Tank Inlet:" Margin="0,5,0,5"/>
|
||||||
|
<HMIToolkit:AnalogValue Grid.Row="3" Grid.Column="1" DataContext="{Binding TemperatureNegolytTankInVM}" HorizontalAlignment="Left" Margin="0,5,0,5"/>
|
||||||
|
<HMIToolkit:AnalogValue Grid.Row="3" Grid.Column="2" DataContext="{Binding TemperaturePosolytTankInVM}" HorizontalAlignment="Left" Margin="0,5,0,5"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für UnitControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class UnitDetailsControl : UserControl
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty UnitNameProperty = DependencyProperty.Register("UnitName", typeof(string), typeof(UnitDetailsControl));
|
||||||
|
public String UnitName
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(UnitNameProperty); }
|
||||||
|
set { SetValue(UnitNameProperty, value); }
|
||||||
|
}
|
||||||
|
public UnitDetailsControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
151
uniper_hmi/UniperHMI/Pages/ViewModels/AutomaticModePageVM.cs
Normal file
151
uniper_hmi/UniperHMI/Pages/ViewModels/AutomaticModePageVM.cs
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using HMIToolkit;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum E_BMS_CONTROL_MODE : short
|
||||||
|
{
|
||||||
|
AUTO_REMOTE = 1,
|
||||||
|
AUTO_LOCAL = 2,
|
||||||
|
SAFETY_CHECK = 3,
|
||||||
|
CAPACITY_TEST = 4,
|
||||||
|
MANUAL = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BMSControlModeEntry(E_BMS_CONTROL_MODE mode, string name)
|
||||||
|
{
|
||||||
|
public E_BMS_CONTROL_MODE eMode = mode;
|
||||||
|
public string Name = name;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed partial class AutomaticModePageVM : ObservableValidator, IDisposable
|
||||||
|
{
|
||||||
|
private int _setpoint;
|
||||||
|
|
||||||
|
[Range(-40000, 40000)]
|
||||||
|
public int Setpoint
|
||||||
|
{
|
||||||
|
get => this._setpoint;
|
||||||
|
set => SetProperty(ref this._setpoint, value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int processValue;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public HMIControlButtonVM? startButton;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public HMIControlButtonVM? stopButton;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private E_BMS_CONTROL_MODE bmsControlMode;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public ObservableCollection<BMSControlModeEntry> reqBMSControlModes =
|
||||||
|
[
|
||||||
|
new BMSControlModeEntry(E_BMS_CONTROL_MODE.AUTO_REMOTE, "Auto Remote"),
|
||||||
|
new BMSControlModeEntry(E_BMS_CONTROL_MODE.AUTO_LOCAL, "Auto Local"),
|
||||||
|
new BMSControlModeEntry(E_BMS_CONTROL_MODE.SAFETY_CHECK, "Safety Check"),
|
||||||
|
new BMSControlModeEntry(E_BMS_CONTROL_MODE.CAPACITY_TEST, "Capacity Test"),
|
||||||
|
new BMSControlModeEntry(E_BMS_CONTROL_MODE.MANUAL, "Manual")
|
||||||
|
];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private BMSControlModeEntry selectedControlMode;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool canChangeControlMode;
|
||||||
|
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
private readonly IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public AutomaticModePageVM()
|
||||||
|
{
|
||||||
|
StartButton = new HMIControlButtonVM();
|
||||||
|
StopButton = new HMIControlButtonVM();
|
||||||
|
SelectedControlMode = ReqBMSControlModes[1];
|
||||||
|
canChangeControlMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutomaticModePageVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
//StartButton = new HMIControlButtonVM(_adsManager, _variableName + ".stStartAutoButton");
|
||||||
|
//StopButton = new HMIControlButtonVM(_adsManager, _variableName + ".stStopAutoButton");
|
||||||
|
|
||||||
|
SelectedControlMode = ReqBMSControlModes[1];
|
||||||
|
|
||||||
|
_adsManager.Register("GVL_SCADA.eCurrentControlMode", CurrentControlModeChanged);
|
||||||
|
_adsManager.Register("GVL_SCADA.xCanChangeControlMode", CCCMChanged);
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName + ".diSetpointAutomatic", SetpointChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetpointChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Setpoint = (int)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CCCMChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
CanChangeControlMode = (bool)e.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CurrentControlModeChanged(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
BmsControlMode = (E_BMS_CONTROL_MODE)e.Value;
|
||||||
|
SelectedControlMode.eMode = BmsControlMode;
|
||||||
|
SelectedControlMode.Name = "Test";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
StartButton?.Dispose();
|
||||||
|
StartButton = null;
|
||||||
|
StopButton?.Dispose();
|
||||||
|
StopButton = null;
|
||||||
|
|
||||||
|
_adsManager?.Deregister("GVL_SCADA.eCurrentControlMode", CurrentControlModeChanged);
|
||||||
|
_adsManager?.Deregister("GVL_SCADA.xCanChangeControlMode", CCCMChanged);
|
||||||
|
|
||||||
|
_adsManager?.Deregister(_variableName + ".diSetpointAutomatic", SetpointChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void StartAutomatic()
|
||||||
|
{
|
||||||
|
_adsManager?.WriteValue(_variableName + ".diSetpointAutomatic", Setpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void StopAutomatic()
|
||||||
|
{
|
||||||
|
_adsManager?.WriteValue(_variableName + ".diSetpointAutomatic", 0);
|
||||||
|
Setpoint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidationResult ValidatePower(int power, ValidationContext context)
|
||||||
|
{
|
||||||
|
if (power < -40000 || power > 40000)
|
||||||
|
return new("Must be between -40.000 and +40.000");
|
||||||
|
else
|
||||||
|
return ValidationResult.Success!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
public sealed partial class BatteryOverviewPageVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private StringControlButtonVM? string1VM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private StringControlButtonVM? string2VM;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private StringControlButtonVM? dummyStringVM;
|
||||||
|
|
||||||
|
private readonly IAdsManager? _adsManager;
|
||||||
|
|
||||||
|
public BatteryOverviewPageVM()
|
||||||
|
{
|
||||||
|
string1VM = new StringControlButtonVM();
|
||||||
|
string2VM = new StringControlButtonVM();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatteryOverviewPageVM(IAdsManager adsManager)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
string1VM = new StringControlButtonVM(adsManager, "GVL_SCADA.stHMIInterface[0]");
|
||||||
|
string2VM = new StringControlButtonVM(adsManager, "GVL_SCADA.stHMIInterface[1]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
String1VM?.Dispose();
|
||||||
|
String1VM = null;
|
||||||
|
|
||||||
|
String2VM?.Dispose();
|
||||||
|
String2VM = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void String1Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage("GVL_SCADA.stHMIInterface[0]", typeof(StringOverviewPage), "String 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void String2Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage("GVL_SCADA.stHMIInterface[1]", typeof(StringOverviewPage), "String 2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
109
uniper_hmi/UniperHMI/Pages/ViewModels/EventsPageVM.cs
Normal file
109
uniper_hmi/UniperHMI/Pages/ViewModels/EventsPageVM.cs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
using TcEventLoggerAdsProxyLib;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
public partial class EventData : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
public uint id;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public string? message;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public DateTime raised;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public DateTime cleared;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public DateTime confirmed;
|
||||||
|
};
|
||||||
|
|
||||||
|
public sealed partial class EventsPageVM : ObservableObject
|
||||||
|
{
|
||||||
|
public ObservableCollection<EventData> CurrentEvents { get; private set; } = [];
|
||||||
|
private readonly object _lock = new();
|
||||||
|
|
||||||
|
private readonly TcEventLogger _logger;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private EventData? currentEvent;
|
||||||
|
|
||||||
|
// 599264352000000000 ticks is a date used by beckhoff for events that didnt happen up to this point
|
||||||
|
private const long NoTime = 599264352000000000;
|
||||||
|
|
||||||
|
|
||||||
|
public EventsPageVM(TcEventLogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
_logger.AlarmRaised += SimpleAlarmRaisedEvent;
|
||||||
|
_logger.AlarmCleared += SimpleAlarmClearedEvent;
|
||||||
|
_logger.AlarmConfirmed += SimpleConfirmedAlarmEvent;
|
||||||
|
|
||||||
|
_logger.Connect("10.103.32.50.1.1");
|
||||||
|
|
||||||
|
GetAllActiveEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RebuildCurrentEventsList()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
CurrentEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetAllActiveEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SimpleConfirmedAlarmEvent(TcAlarm alarm, bool remove)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(RebuildCurrentEventsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SimpleAlarmClearedEvent(TcAlarm alarm, bool remove)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(RebuildCurrentEventsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SimpleAlarmRaisedEvent(TcAlarm alarm)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(RebuildCurrentEventsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetAllActiveEvents()
|
||||||
|
{
|
||||||
|
EventData eventData;
|
||||||
|
List<EventData> tempEventList = [];
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var alarm in _logger.ActiveAlarms)
|
||||||
|
{
|
||||||
|
eventData = new()
|
||||||
|
{
|
||||||
|
Id = alarm.EventId,
|
||||||
|
Message = alarm.GetText(1033),
|
||||||
|
Raised = alarm.TimeRaised,
|
||||||
|
Cleared = alarm.TimeCleared,
|
||||||
|
Confirmed = alarm.TimeConfirmed
|
||||||
|
};
|
||||||
|
|
||||||
|
tempEventList.Add(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<EventData> _eventQuery =
|
||||||
|
from data in tempEventList
|
||||||
|
orderby data.Raised descending
|
||||||
|
select data;
|
||||||
|
|
||||||
|
CurrentEvent = _eventQuery.FirstOrDefault();
|
||||||
|
CurrentEvents = new ObservableCollection<EventData>(_eventQuery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
using UniperHMI.OwnControls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
public sealed partial class ModuleOverviewPageVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private UnitControlButtonVM unit1;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private UnitControlButtonVM unit2;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private UnitControlButtonVM unit3;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private UnitControlButtonVM unit4;
|
||||||
|
|
||||||
|
private readonly IAdsManager? _adsManager;
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
public ModuleOverviewPageVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
unit1 = new(_adsManager, _variableName + ".stHMIInterfaceUnit1");
|
||||||
|
unit2 = new(_adsManager, _variableName + ".stHMIInterfaceUnit2");
|
||||||
|
unit3 = new(_adsManager, _variableName + ".stHMIInterfaceUnit3");
|
||||||
|
unit4 = new(_adsManager, _variableName + ".stHMIInterfaceUnit4");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Unit1?.Dispose();
|
||||||
|
Unit2?.Dispose();
|
||||||
|
Unit3?.Dispose();
|
||||||
|
Unit4?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void Unit1Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceUnit1", typeof(UnitOverviewPage), "Unit 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void Unit2Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceUnit2", typeof(UnitOverviewPage), "Unit 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void Unit3Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceUnit3", typeof(UnitOverviewPage), "Unit 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void Unit4Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceUnit4", typeof(UnitOverviewPage), "Unit 4"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public sealed partial class StringOverviewPageVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private ModuleControlButtonVM module1;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ModuleControlButtonVM module2;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ModuleControlButtonVM module3;
|
||||||
|
|
||||||
|
private readonly IAdsManager? _adsManager;
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
public StringOverviewPageVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
module1 = new(_adsManager, _variableName + ".stHMIInterfaceModule1");
|
||||||
|
module2 = new(_adsManager, _variableName + ".stHMIInterfaceModule2");
|
||||||
|
module3 = new(_adsManager, _variableName + ".stHMIInterfaceModule3");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Module1?.Dispose();
|
||||||
|
Module2?.Dispose();
|
||||||
|
Module3?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Module1Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceModule1", typeof(ModuleOverviewPage), "Module 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Module2Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceModule2", typeof(ModuleOverviewPage), "Module 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Module3Clicked()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateMessage(_variableName + ".stHMIInterfaceModule3", typeof(ModuleOverviewPage), "Module 3"));
|
||||||
|
}
|
||||||
|
}
|
||||||
31
uniper_hmi/UniperHMI/Pages/ViewModels/UnitOverviewPageVM.cs
Normal file
31
uniper_hmi/UniperHMI/Pages/ViewModels/UnitOverviewPageVM.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
public sealed partial class UnitOverviewPageVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string unitName;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private UnitDetailsControlVM unitControlVM;
|
||||||
|
|
||||||
|
private readonly IAdsManager? _adsManager;
|
||||||
|
private readonly string? _variableName;
|
||||||
|
|
||||||
|
public UnitOverviewPageVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
unitControlVM = new(_adsManager, _variableName);
|
||||||
|
|
||||||
|
unitName = "Unit X";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
UnitControlVM?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
uniper_hmi/UniperHMI/Pages/Views/AutomaticModePage.xaml
Normal file
49
uniper_hmi/UniperHMI/Pages/Views/AutomaticModePage.xaml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<Page x:Class="UniperHMI.AutomaticModePage"
|
||||||
|
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:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:AutomaticModePageVM, IsDesignTimeCreatable=True}"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
Title="AutomaticModePage">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Grid.Row="1" Grid.Column="1" Content="Requested Control Mode:" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
|
<ComboBox Grid.Row="1" Grid.Column="2" IsEnabled="{Binding CanChangeControlMode}" ItemsSource="{Binding ReqBMSControlModes}" SelectedItem="{Binding SelectedControlMode}"/>
|
||||||
|
|
||||||
|
<Label Grid.Row="2" Grid.Column="1" Content="Current Control Mode:" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
|
<TextBox Grid.Row="2" Grid.Column="2" Text="{Binding BmsControlMode}" MaxLines="1" IsReadOnly="True" TextAlignment="Right"/>
|
||||||
|
|
||||||
|
<Label Grid.Row="3" Grid.Column="1" Content="Status:" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
|
<TextBox Grid.Row="3" Width="125" Grid.Column="2" Text="Charging" MaxLines="1" IsReadOnly="True" TextAlignment="Right"/>
|
||||||
|
|
||||||
|
<Label Grid.Row="4" Grid.Column="1" Content="Target Power (W):" Margin="0,5,0,0" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||||
|
<TextBox Grid.Row="4" Width="125" Grid.Column="2" Text="{Binding Setpoint}" MaxLines="1" Margin="0,5,0,0" TextAlignment="Right" />
|
||||||
|
|
||||||
|
<Label Grid.Row="5" Grid.Column="1" Content="Actual Power (W):" Margin="0,5,0,0" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
|
<TextBox Grid.Row="5" Width="125" Grid.Column="2" Text="{Binding ProcessValue}" MaxLines="1" Margin="0,5,0,0" IsReadOnly="True" TextAlignment="Right" />
|
||||||
|
|
||||||
|
<Button Grid.Row="6" Grid.Column="1" Command="{Binding StartAutomaticCommand}" Content="Start" Margin="0,5,5,0" />
|
||||||
|
<Button Grid.Row="6" Grid.Column="2" Command="{Binding StopAutomaticCommand}" Content="Stop" Margin="5,5,0,0" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
22
uniper_hmi/UniperHMI/Pages/Views/AutomaticModePage.xaml.cs
Normal file
22
uniper_hmi/UniperHMI/Pages/Views/AutomaticModePage.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für AutomaticModePage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class AutomaticModePage : Page
|
||||||
|
{
|
||||||
|
public AutomaticModePage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
uniper_hmi/UniperHMI/Pages/Views/BatteryOverviewPage.xaml
Normal file
39
uniper_hmi/UniperHMI/Pages/Views/BatteryOverviewPage.xaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<Page x:Class="UniperHMI.BatteryOverviewPage"
|
||||||
|
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:UniperHMI"
|
||||||
|
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:Name="root"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:BatteryOverviewPageVM, IsDesignTimeCreatable=False}"
|
||||||
|
Title="ManualModePage" Height="Auto" Width="Auto" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||||
|
|
||||||
|
<Grid Margin="10" Width="Auto" Height="Auto">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<local:SMUControlButton Grid.Row="0" Grid.Column="0" DataContext="{Binding String1VM}" Command="{Binding ElementName=root, Path=DataContext.String1ClickedCommand}" SMUName="String 1" Margin="0,0,5,0" />
|
||||||
|
<local:SMUControlButton Grid.Row="0" Grid.Column="1" DataContext="{Binding String2VM}" Command="{Binding ElementName=root, Path=DataContext.String2ClickedCommand}" SMUName="String 2" Margin="0,0,5,0" />
|
||||||
|
<local:SMUControlButton Grid.Row="0" Grid.Column="2" DataContext="{Binding DummyStringVM}" SMUName="String 3" Margin="0,0,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="0" Grid.Column="3" DataContext="{Binding DummyStringVM}" SMUName="String 4" Margin="0,0,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="0" Grid.Column="4" DataContext="{Binding DummyStringVM}" SMUName="String 5" Margin="0,0,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="0" Grid.Column="5" DataContext="{Binding DummyStringVM}" SMUName="String 6" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="1" Grid.Column="0" DataContext="{Binding DummyStringVM}" SMUName="String 7" Margin="0,5,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="1" Grid.Column="1" DataContext="{Binding DummyStringVM}" SMUName="String 8" Margin="0,5,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="1" Grid.Column="2" DataContext="{Binding DummyStringVM}" SMUName="String 9" Margin="0,5,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="1" Grid.Column="3" DataContext="{Binding DummyStringVM}" SMUName="String 10" Margin="0,5,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="1" Grid.Column="4" DataContext="{Binding DummyStringVM}" SMUName="String 11" Margin="0,5,5,0" IsEnabled="False"/>
|
||||||
|
<local:SMUControlButton Grid.Row="1" Grid.Column="5" DataContext="{Binding DummyStringVM}" SMUName="String 12" Margin="0,5,0,0" IsEnabled="False"/>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
22
uniper_hmi/UniperHMI/Pages/Views/BatteryOverviewPage.xaml.cs
Normal file
22
uniper_hmi/UniperHMI/Pages/Views/BatteryOverviewPage.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für ManualModePage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class BatteryOverviewPage : Page
|
||||||
|
{
|
||||||
|
public BatteryOverviewPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
//Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
uniper_hmi/UniperHMI/Pages/Views/EventsPage.xaml
Normal file
25
uniper_hmi/UniperHMI/Pages/Views/EventsPage.xaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<Page x:Class="UniperHMI.EventsPage"
|
||||||
|
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:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:EventsPageVM, IsDesignTimeCreatable=False}"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
Title="EventsPage">
|
||||||
|
<Page.Resources>
|
||||||
|
<local:DateTimeToEventTimeConverter x:Key="dtConverter" />
|
||||||
|
</Page.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<DataGrid ItemsSource="{Binding CurrentEvents}" AutoGenerateColumns="False" IsReadOnly="True">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Message" Binding="{Binding Message}" Width="400"/>
|
||||||
|
<DataGridTextColumn Header="Raised" Binding="{Binding Raised, Converter={StaticResource dtConverter}}" Width="*" SortDirection="Descending"/>
|
||||||
|
<DataGridTextColumn Header="Cleared" Binding="{Binding Cleared, Converter={StaticResource dtConverter}}" Width="*"/>
|
||||||
|
<DataGridTextColumn Header="Confirmed" Binding="{Binding Confirmed, Converter={StaticResource dtConverter}}" Width="*"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
14
uniper_hmi/UniperHMI/Pages/Views/EventsPage.xaml.cs
Normal file
14
uniper_hmi/UniperHMI/Pages/Views/EventsPage.xaml.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für EventsPage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class EventsPage : Page
|
||||||
|
{
|
||||||
|
public EventsPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
25
uniper_hmi/UniperHMI/Pages/Views/ModuleOverviewPage.xaml
Normal file
25
uniper_hmi/UniperHMI/Pages/Views/ModuleOverviewPage.xaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<Page x:Class="UniperHMI.ModuleOverviewPage"
|
||||||
|
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:UniperHMI"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:ModuleOverviewPageVM, IsDesignTimeCreatable=False}"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Width="Auto" Height="Auto" x:Name="root" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
|
||||||
|
<Grid Margin="10" ShowGridLines="False" Width="Auto" Height="Auto">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<local:SMUControlButton SMUName="Unit 1" DataContext="{Binding Unit1}" Command="{Binding ElementName=root, Path=DataContext.Unit1ClickedCommand}" Grid.Row="0" Grid.Column="0" Margin="0,0,5,0" />
|
||||||
|
<local:SMUControlButton SMUName="Unit 2" DataContext="{Binding Unit2}" Command="{Binding ElementName=root, Path=DataContext.Unit2ClickedCommand}" Grid.Row="0" Grid.Column="1" />
|
||||||
|
<local:SMUControlButton SMUName="Unit 3" DataContext="{Binding Unit3}" Command="{Binding ElementName=root, Path=DataContext.Unit3ClickedCommand}" Grid.Row="1" Grid.Column="0" Margin="0,5,5,0" />
|
||||||
|
<local:SMUControlButton SMUName="Unit 4" DataContext="{Binding Unit4}" Command="{Binding ElementName=root, Path=DataContext.Unit4ClickedCommand}" Grid.Row="1" Grid.Column="1" Margin="0,5,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
28
uniper_hmi/UniperHMI/Pages/Views/ModuleOverviewPage.xaml.cs
Normal file
28
uniper_hmi/UniperHMI/Pages/Views/ModuleOverviewPage.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 UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für ModuleOverviewPage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ModuleOverviewPage : Page
|
||||||
|
{
|
||||||
|
public ModuleOverviewPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
uniper_hmi/UniperHMI/Pages/Views/StringOverviewPage.xaml
Normal file
23
uniper_hmi/UniperHMI/Pages/Views/StringOverviewPage.xaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<Page x:Class="UniperHMI.StringOverviewPage"
|
||||||
|
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:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:StringOverviewPageVM, IsDesignTimeCreatable=False}"
|
||||||
|
Title="StringOverviewPage"
|
||||||
|
Width="Auto" Height="Auto" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||||
|
x:Name="root">
|
||||||
|
|
||||||
|
<Grid Margin="10" Width="Auto" Height="Auto">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<local:SMUControlButton SMUName="Modul 1" DataContext="{Binding Module1}" Command="{Binding ElementName=root, Path=DataContext.Module1ClickedCommand}" Grid.Column="0" Margin="0,0,5,0"/>
|
||||||
|
<local:SMUControlButton SMUName="Modul 2" DataContext="{Binding Module2}" Command="{Binding ElementName=root, Path=DataContext.Module2ClickedCommand}" Grid.Column="1" Margin="0,0,5,0"/>
|
||||||
|
<local:SMUControlButton SMUName="Modul 3" DataContext="{Binding Module3}" Command="{Binding ElementName=root, Path=DataContext.Module3ClickedCommand}" Grid.Column="2"/>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
15
uniper_hmi/UniperHMI/Pages/Views/StringOverviewPage.xaml.cs
Normal file
15
uniper_hmi/UniperHMI/Pages/Views/StringOverviewPage.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für StringOverviewPage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class StringOverviewPage : Page
|
||||||
|
{
|
||||||
|
public StringOverviewPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
uniper_hmi/UniperHMI/Pages/Views/UnitOverviewPage.xaml
Normal file
16
uniper_hmi/UniperHMI/Pages/Views/UnitOverviewPage.xaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<Page x:Class="UniperHMI.UnitOverviewPage"
|
||||||
|
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:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:UnitOverviewPageVM, IsDesignTimeCreatable=False}"
|
||||||
|
Width="Auto" Height="Auto"
|
||||||
|
Title="UnitOverviewPage"
|
||||||
|
x:Name="root">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<local:UnitDetailsControl UnitName="{Binding ElementName=root, Path=DataContext.UnitName}" DataContext="{Binding UnitControlVM}" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
14
uniper_hmi/UniperHMI/Pages/Views/UnitOverviewPage.xaml.cs
Normal file
14
uniper_hmi/UniperHMI/Pages/Views/UnitOverviewPage.xaml.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für UnitOverviewPage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class UnitOverviewPage : Page
|
||||||
|
{
|
||||||
|
public UnitOverviewPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
36
uniper_hmi/UniperHMI/SettingsPage/SettingsPage.xaml
Normal file
36
uniper_hmi/UniperHMI/SettingsPage/SettingsPage.xaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<Page x:Class="UniperHMI.SettingsPage"
|
||||||
|
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:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||||
|
xmlns:local="clr-namespace:UniperHMI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance Type=local:SettingsPageVM}"
|
||||||
|
Title="SettingsPageView">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<!-- {d:SampleData ItemCount=5} -->
|
||||||
|
<!--<DataGrid d:ItemsSource="{Binding CollectionView.View}"/>-->
|
||||||
|
<TreeView x:Name="treeview" ItemsSource="{Binding RootItem}" SelectedValuePath="Value" MinWidth="200" >
|
||||||
|
<TreeView.ItemTemplate>
|
||||||
|
<HierarchicalDataTemplate ItemsSource="{Binding SubEntries}">
|
||||||
|
<TreeViewItem>
|
||||||
|
<TreeViewItem.Header>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Content="{Binding Path=Name}"/>
|
||||||
|
<TextBox Text="{Binding Value}" Visibility="{Binding Visibility}" Margin="10,0,0,0" Width="150" TextAlignment="Right"/>
|
||||||
|
</Grid>
|
||||||
|
</TreeViewItem.Header>
|
||||||
|
<!-- <TextBox Text="{Binding Value}" Visibility="{Binding Visibility}"/> -->
|
||||||
|
</TreeViewItem>
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
</TreeView.ItemTemplate>
|
||||||
|
</TreeView>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
22
uniper_hmi/UniperHMI/SettingsPage/SettingsPage.xaml.cs
Normal file
22
uniper_hmi/UniperHMI/SettingsPage/SettingsPage.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für SettingsPageView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class SettingsPage : Page
|
||||||
|
{
|
||||||
|
public SettingsPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var disposable = DataContext as IDisposable;
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
125
uniper_hmi/UniperHMI/SettingsPage/SettingsPageVM.cs
Normal file
125
uniper_hmi/UniperHMI/SettingsPage/SettingsPageVM.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using MahApps.Metro.Controls;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows;
|
||||||
|
using TwinCAT.Ads.TypeSystem;
|
||||||
|
using TwinCAT.TypeSystem;
|
||||||
|
using Heisig.HMI.AdsManager;
|
||||||
|
|
||||||
|
namespace UniperHMI
|
||||||
|
{
|
||||||
|
public partial class SettingsEntry : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string name = "";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string instancePath = "";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? dataType;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Object? value;
|
||||||
|
|
||||||
|
public ObservableCollection<SettingsEntry> SubEntries { get; set; } = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Visibility visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
private readonly IAdsManager _adsManager;
|
||||||
|
|
||||||
|
public SettingsEntry(IAdsManager adsManager)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnValueChanging(object? oldValue, object? newValue)
|
||||||
|
{
|
||||||
|
if (newValue == null)
|
||||||
|
{
|
||||||
|
newValue = oldValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_adsManager.WriteValue(InstancePath, newValue);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
newValue = oldValue;
|
||||||
|
Debug.WriteLine("Value {0} could not be written to {1}", newValue, InstancePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class SettingsPageVM : ObservableObject, IDisposable
|
||||||
|
{
|
||||||
|
public ObservableCollection<SettingsEntry> RootItem { get; private set; } = [];
|
||||||
|
|
||||||
|
private readonly IAdsManager _adsManager;
|
||||||
|
|
||||||
|
private readonly string _variableName;
|
||||||
|
|
||||||
|
public SettingsPageVM(IAdsManager adsManager, string variableName)
|
||||||
|
{
|
||||||
|
_adsManager = adsManager;
|
||||||
|
_variableName = variableName;
|
||||||
|
|
||||||
|
_adsManager.Register(_variableName, ConfigChangedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigChangedEvent(object? sender, ValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
App.Current.Invoke(CreateSettingsTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSettingsTree()
|
||||||
|
{
|
||||||
|
ISymbolLoader? symbolLoader = _adsManager.GetSymbolLoader();
|
||||||
|
|
||||||
|
if (symbolLoader == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Symbol configSymbol = (Symbol)symbolLoader.Symbols[_variableName];
|
||||||
|
SettingsEntry entry = GetSymbol(configSymbol);
|
||||||
|
RootItem.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SettingsEntry GetSymbol(Symbol symbol)
|
||||||
|
{
|
||||||
|
// Create Symbol
|
||||||
|
SettingsEntry entry = new(_adsManager)
|
||||||
|
{
|
||||||
|
Name = symbol.InstanceName,
|
||||||
|
InstancePath = symbol.InstancePath,
|
||||||
|
DataType = symbol.DataType?.Name
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if symbol has sub symbols
|
||||||
|
if (!symbol.IsPrimitiveType)
|
||||||
|
{
|
||||||
|
foreach (Symbol subSymbol in symbol.SubSymbols.Cast<Symbol>())
|
||||||
|
{
|
||||||
|
entry.SubEntries.Add(GetSymbol(subSymbol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
entry.Value = symbol.ReadValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_adsManager?.Deregister(_variableName, ConfigChangedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
uniper_hmi/UniperHMI/UniperHMI.csproj
Normal file
53
uniper_hmi/UniperHMI/UniperHMI.csproj
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
<AssemblyVersion>0.1.0</AssemblyVersion>
|
||||||
|
<FileVersion>0.1</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AdsManager" Version="1.0.0.6" />
|
||||||
|
<PackageReference Include="Beckhoff.TwinCAT.Ads" Version="6.1.197" />
|
||||||
|
<PackageReference Include="Beckhoff.TwinCAT.TcEventLoggerAdsProxy.Net" Version="2.7.11" />
|
||||||
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||||
|
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\AnalogMotorControl\AnalogMotorControl.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\AnalogValue\AnalogValue.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\AnalogValveControl\AnalogValveControl.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\BinaryValveControl\BinaryValveControl.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\InterlockControl\IntlkControl.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\InterlockDetailsControl\IntlkDetails.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="HMIToolkit\HMIObjects\InterlockDetailsControl\IntlkDetailsWindow.xaml.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
8
uniper_hmi/UniperHMI/appsettings.json
Normal file
8
uniper_hmi/UniperHMI/appsettings.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"AutomaticModeVarName": "GVL_SCADA.stAutomaticModeHMI",
|
||||||
|
"String1VarName": "GVL_SCADA.stHMIInterface",
|
||||||
|
|
||||||
|
"Module1VarName": ".stHMIInterfaceModule1",
|
||||||
|
"Module2VarName": ".stHMIInterfaceModule2",
|
||||||
|
"Module3VarName": ".stHMIInterfaceModule3"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user