From 627050501d34ef65f107a85a9cca15f2815d40a6 Mon Sep 17 00:00:00 2001 From: bliestlech-tc Date: Wed, 11 Feb 2026 08:38:36 +0100 Subject: [PATCH] Initial Push --- ads-wrapper/.gitattributes | 63 +++ ads-wrapper/.gitignore | 363 +++++++++++++ ads-wrapper/AdsManager.cs | 331 ++++++++++++ ads-wrapper/AdsManager.csproj | 29 + ads-wrapper/AdsManager.sln | 25 + ads-wrapper/AdsSettings.cs | 27 + ads-wrapper/README.md | 2 + uniper_hmi/.gitattributes | 63 +++ uniper_hmi/.gitignore | 367 +++++++++++++ uniper_hmi/AdsSettings.json | 1 + uniper_hmi/README.md | 98 ++++ uniper_hmi/Uniper.sln | 25 + uniper_hmi/UniperHMI/App.xaml | 17 + uniper_hmi/UniperHMI/App.xaml.cs | 46 ++ uniper_hmi/UniperHMI/AssemblyInfo.cs | 10 + .../UniperHMI/DateTimeToEventTimeConverter.cs | 33 ++ .../HMIToolkit/AnalogMotorWindow.xaml | 12 + .../HMIToolkit/AnalogMotorWindow.xaml.cs | 14 + .../HMIToolkit/BinaryValveWindow.xaml | 12 + .../HMIToolkit/BinaryValveWindow.xaml.cs | 15 + .../HMIToolkit/FeedbackToColorConverter.cs | 46 ++ .../AnalogMotorControl.xaml | 91 ++++ .../AnalogMotorControl.xaml.cs | 23 + .../AnalogMotorcontrolVM.cs | 83 +++ .../AnalogValue/AnalogRangeValidator.cs | 33 ++ .../HMIObjects/AnalogValue/AnalogValue.xaml | 33 ++ .../AnalogValue/AnalogValue.xaml.cs | 32 ++ .../HMIObjects/AnalogValue/AnalogValueVM.cs | 144 +++++ .../AnalogValveControl.xaml | 87 +++ .../AnalogValveControl.xaml.cs | 35 ++ .../AnalogValveControlVM.cs | 83 +++ .../BinaryValveControl.xaml | 74 +++ .../BinaryValveControl.xaml.cs | 35 ++ .../BinaryValveControlVM.cs | 70 +++ .../HMIObjects/BoolToBrushConverter.cs | 25 + .../HMIObjects/HMIControlButtonVM.cs | 74 +++ .../InterlockControl/IntlkControl.xaml | 33 ++ .../InterlockControl/IntlkControl.xaml.cs | 35 ++ .../InterlockControl/IntlkControlVM.cs | 109 ++++ .../InterlockDetailsControl/IntlkDetails.xaml | 132 +++++ .../IntlkDetails.xaml.cs | 35 ++ .../InterlockDetailsControl/IntlkDetailsVM.cs | 151 ++++++ .../IntlkDetailsWindow.xaml | 13 + .../IntlkDetailsWindow.xaml.cs | 27 + .../HMIObjects/structures/HMIDataTypes.cs | 218 ++++++++ uniper_hmi/UniperHMI/MainWindow.xaml | 85 +++ uniper_hmi/UniperHMI/MainWindow.xaml.cs | 26 + uniper_hmi/UniperHMI/MainWindowVM.cs | 273 ++++++++++ uniper_hmi/UniperHMI/NavigateMessage.cs | 3 + .../ViewModels/ModuleControlButtonVM.cs | 18 + .../OwnControls/ViewModels/SMUBaseVM.cs | 60 +++ .../ViewModels/StringControlButtonVM.cs | 16 + .../ViewModels/UnitControlButtonVM.cs | 19 + .../ViewModels/UnitDetailsControlVM.cs | 494 ++++++++++++++++++ .../OwnControls/Views/SMUControlButton.xaml | 42 ++ .../Views/SMUControlButton.xaml.cs | 23 + .../OwnControls/Views/UnitDetailsControl.xaml | 138 +++++ .../Views/UnitDetailsControl.xaml.cs | 22 + .../Pages/ViewModels/AutomaticModePageVM.cs | 151 ++++++ .../Pages/ViewModels/BatteryOverviewPageVM.cs | 55 ++ .../Pages/ViewModels/EventsPageVM.cs | 109 ++++ .../Pages/ViewModels/ModuleOverviewPageVM.cs | 69 +++ .../Pages/ViewModels/StringOverviewPageVM.cs | 56 ++ .../Pages/ViewModels/UnitOverviewPageVM.cs | 31 ++ .../Pages/Views/AutomaticModePage.xaml | 49 ++ .../Pages/Views/AutomaticModePage.xaml.cs | 22 + .../Pages/Views/BatteryOverviewPage.xaml | 39 ++ .../Pages/Views/BatteryOverviewPage.xaml.cs | 22 + .../UniperHMI/Pages/Views/EventsPage.xaml | 25 + .../UniperHMI/Pages/Views/EventsPage.xaml.cs | 14 + .../Pages/Views/ModuleOverviewPage.xaml | 25 + .../Pages/Views/ModuleOverviewPage.xaml.cs | 28 + .../Pages/Views/StringOverviewPage.xaml | 23 + .../Pages/Views/StringOverviewPage.xaml.cs | 15 + .../Pages/Views/UnitOverviewPage.xaml | 16 + .../Pages/Views/UnitOverviewPage.xaml.cs | 14 + .../UniperHMI/SettingsPage/SettingsPage.xaml | 36 ++ .../SettingsPage/SettingsPage.xaml.cs | 22 + .../UniperHMI/SettingsPage/SettingsPageVM.cs | 125 +++++ uniper_hmi/UniperHMI/UniperHMI.csproj | 53 ++ uniper_hmi/UniperHMI/appsettings.json | 8 + 81 files changed, 5500 insertions(+) create mode 100644 ads-wrapper/.gitattributes create mode 100644 ads-wrapper/.gitignore create mode 100644 ads-wrapper/AdsManager.cs create mode 100644 ads-wrapper/AdsManager.csproj create mode 100644 ads-wrapper/AdsManager.sln create mode 100644 ads-wrapper/AdsSettings.cs create mode 100644 ads-wrapper/README.md create mode 100644 uniper_hmi/.gitattributes create mode 100644 uniper_hmi/.gitignore create mode 100644 uniper_hmi/AdsSettings.json create mode 100644 uniper_hmi/README.md create mode 100644 uniper_hmi/Uniper.sln create mode 100644 uniper_hmi/UniperHMI/App.xaml create mode 100644 uniper_hmi/UniperHMI/App.xaml.cs create mode 100644 uniper_hmi/UniperHMI/AssemblyInfo.cs create mode 100644 uniper_hmi/UniperHMI/DateTimeToEventTimeConverter.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/FeedbackToColorConverter.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogMotorControl/AnalogMotorControl.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogMotorControl/AnalogMotorControl.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogMotorControl/AnalogMotorcontrolVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValue/AnalogRangeValidator.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValue/AnalogValue.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValue/AnalogValue.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValue/AnalogValueVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValveControl/AnalogValveControl.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValveControl/AnalogValveControl.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogValveControl/AnalogValveControlVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/BinaryValveControl/BinaryValveControl.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/BinaryValveControl/BinaryValveControl.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/BinaryValveControl/BinaryValveControlVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/BoolToBrushConverter.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/HMIControlButtonVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControl.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControl.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControlVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsVM.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml.cs create mode 100644 uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/structures/HMIDataTypes.cs create mode 100644 uniper_hmi/UniperHMI/MainWindow.xaml create mode 100644 uniper_hmi/UniperHMI/MainWindow.xaml.cs create mode 100644 uniper_hmi/UniperHMI/MainWindowVM.cs create mode 100644 uniper_hmi/UniperHMI/NavigateMessage.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/ViewModels/ModuleControlButtonVM.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/ViewModels/SMUBaseVM.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/ViewModels/StringControlButtonVM.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/ViewModels/UnitControlButtonVM.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/ViewModels/UnitDetailsControlVM.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/Views/SMUControlButton.xaml create mode 100644 uniper_hmi/UniperHMI/OwnControls/Views/SMUControlButton.xaml.cs create mode 100644 uniper_hmi/UniperHMI/OwnControls/Views/UnitDetailsControl.xaml create mode 100644 uniper_hmi/UniperHMI/OwnControls/Views/UnitDetailsControl.xaml.cs create mode 100644 uniper_hmi/UniperHMI/Pages/ViewModels/AutomaticModePageVM.cs create mode 100644 uniper_hmi/UniperHMI/Pages/ViewModels/BatteryOverviewPageVM.cs create mode 100644 uniper_hmi/UniperHMI/Pages/ViewModels/EventsPageVM.cs create mode 100644 uniper_hmi/UniperHMI/Pages/ViewModels/ModuleOverviewPageVM.cs create mode 100644 uniper_hmi/UniperHMI/Pages/ViewModels/StringOverviewPageVM.cs create mode 100644 uniper_hmi/UniperHMI/Pages/ViewModels/UnitOverviewPageVM.cs create mode 100644 uniper_hmi/UniperHMI/Pages/Views/AutomaticModePage.xaml create mode 100644 uniper_hmi/UniperHMI/Pages/Views/AutomaticModePage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/Pages/Views/BatteryOverviewPage.xaml create mode 100644 uniper_hmi/UniperHMI/Pages/Views/BatteryOverviewPage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/Pages/Views/EventsPage.xaml create mode 100644 uniper_hmi/UniperHMI/Pages/Views/EventsPage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/Pages/Views/ModuleOverviewPage.xaml create mode 100644 uniper_hmi/UniperHMI/Pages/Views/ModuleOverviewPage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/Pages/Views/StringOverviewPage.xaml create mode 100644 uniper_hmi/UniperHMI/Pages/Views/StringOverviewPage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/Pages/Views/UnitOverviewPage.xaml create mode 100644 uniper_hmi/UniperHMI/Pages/Views/UnitOverviewPage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/SettingsPage/SettingsPage.xaml create mode 100644 uniper_hmi/UniperHMI/SettingsPage/SettingsPage.xaml.cs create mode 100644 uniper_hmi/UniperHMI/SettingsPage/SettingsPageVM.cs create mode 100644 uniper_hmi/UniperHMI/UniperHMI.csproj create mode 100644 uniper_hmi/UniperHMI/appsettings.json diff --git a/ads-wrapper/.gitattributes b/ads-wrapper/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/ads-wrapper/.gitattributes @@ -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 diff --git a/ads-wrapper/.gitignore b/ads-wrapper/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/ads-wrapper/.gitignore @@ -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 \ No newline at end of file diff --git a/ads-wrapper/AdsManager.cs b/ads-wrapper/AdsManager.cs new file mode 100644 index 0000000..cdf2f0e --- /dev/null +++ b/ads-wrapper/AdsManager.cs @@ -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 eventHandler); + + public void Deregister(string variableName, EventHandler 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>> _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(text) ?? new AdsSettings(); + } + + return settings; + } + + // Register a callback on variable change + public void Register(string variableName, EventHandler eventHandler) + { + List> 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 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 eventHandler) + { + List>? tempList; + bool eventRemoved = false; + + if (_test.TryGetValue(variableName, out tempList)) + { + foreach (EventHandler 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>> entry in _test) + { + symbol = (Symbol)_symbolLoader.Symbols[entry.Key]; + foreach (EventHandler 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; + } +} diff --git a/ads-wrapper/AdsManager.csproj b/ads-wrapper/AdsManager.csproj new file mode 100644 index 0000000..b03c255 --- /dev/null +++ b/ads-wrapper/AdsManager.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + True + Ads Manager + M.Heisig + Heisig GmbH + Wrapper für den Ads Client von Beckhoff um automatische reconnects und onlinechanges zu behandeln. + README.md + C:\Users\matthias.heisig\Documents\nuget_packages + https://gitlab.cmblu.de/matthias.heisig/ads-wrapper + 1.0.0.7 + + + + + + + + + True + \ + + + + diff --git a/ads-wrapper/AdsManager.sln b/ads-wrapper/AdsManager.sln new file mode 100644 index 0000000..de2b583 --- /dev/null +++ b/ads-wrapper/AdsManager.sln @@ -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 diff --git a/ads-wrapper/AdsSettings.cs b/ads-wrapper/AdsSettings.cs new file mode 100644 index 0000000..120a92c --- /dev/null +++ b/ads-wrapper/AdsSettings.cs @@ -0,0 +1,27 @@ +namespace Heisig.HMI.AdsManager; + +/// +/// Struct with the settings for connecting to the ads server +/// +public class AdsSettings +{ + /// + /// Ads server address + /// + public string AdsAdress { get; set; } = "127.0.0.1.1.1"; + + /// + /// Ads server port + /// + public int AdsPort { get; set; } = 851; + + /// + /// Intervall for reconnect tries + /// + public int ReconnectIntervalMS { get; set; } = 2000; + + /// + /// Variable name for which contains the online change counter + /// + public string OnlineChangeCntVar { get; set; } = "TWinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"; +} diff --git a/ads-wrapper/README.md b/ads-wrapper/README.md new file mode 100644 index 0000000..827b01c --- /dev/null +++ b/ads-wrapper/README.md @@ -0,0 +1,2 @@ +# Ads Manager +Ads Wrapper klasse um automatische reconnects und online changes mit einem ADS Server der Beckhoff steuerung zu behandeln. \ No newline at end of file diff --git a/uniper_hmi/.gitattributes b/uniper_hmi/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/uniper_hmi/.gitattributes @@ -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 diff --git a/uniper_hmi/.gitignore b/uniper_hmi/.gitignore new file mode 100644 index 0000000..da7cb42 --- /dev/null +++ b/uniper_hmi/.gitignore @@ -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 \ No newline at end of file diff --git a/uniper_hmi/AdsSettings.json b/uniper_hmi/AdsSettings.json new file mode 100644 index 0000000..98599c4 --- /dev/null +++ b/uniper_hmi/AdsSettings.json @@ -0,0 +1 @@ +{"AdsAdress":"10.103.32.50.1.1","AdsPort":851,"ReconnectIntervalMS":1000,"OnlineChangeCntVar":"TWinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"} \ No newline at end of file diff --git a/uniper_hmi/README.md b/uniper_hmi/README.md new file mode 100644 index 0000000..cf2e00b --- /dev/null +++ b/uniper_hmi/README.md @@ -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 +``` \ No newline at end of file diff --git a/uniper_hmi/Uniper.sln b/uniper_hmi/Uniper.sln new file mode 100644 index 0000000..90d9631 --- /dev/null +++ b/uniper_hmi/Uniper.sln @@ -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 diff --git a/uniper_hmi/UniperHMI/App.xaml b/uniper_hmi/UniperHMI/App.xaml new file mode 100644 index 0000000..4b8b9c0 --- /dev/null +++ b/uniper_hmi/UniperHMI/App.xaml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/uniper_hmi/UniperHMI/App.xaml.cs b/uniper_hmi/UniperHMI/App.xaml.cs new file mode 100644 index 0000000..5ea07d7 --- /dev/null +++ b/uniper_hmi/UniperHMI/App.xaml.cs @@ -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(); + services.AddSingleton(); + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddSingleton(); + }) + .Build(); + } + + protected override async void OnStartup(StartupEventArgs e) + { + await AppHost!.StartAsync(); + + var startupForm = AppHost.Services.GetRequiredService(); + startupForm.Show(); + + base.OnStartup(e); + } + + protected override async void OnExit(ExitEventArgs e) + { + await AppHost!.StopAsync(); + + base.OnExit(e); + } +} diff --git a/uniper_hmi/UniperHMI/AssemblyInfo.cs b/uniper_hmi/UniperHMI/AssemblyInfo.cs new file mode 100644 index 0000000..b0ec827 --- /dev/null +++ b/uniper_hmi/UniperHMI/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/uniper_hmi/UniperHMI/DateTimeToEventTimeConverter.cs b/uniper_hmi/UniperHMI/DateTimeToEventTimeConverter.cs new file mode 100644 index 0000000..c692701 --- /dev/null +++ b/uniper_hmi/UniperHMI/DateTimeToEventTimeConverter.cs @@ -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; + } + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml b/uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml new file mode 100644 index 0000000..9702640 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml.cs b/uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml.cs new file mode 100644 index 0000000..9d6b34b --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/AnalogMotorWindow.xaml.cs @@ -0,0 +1,14 @@ +using System.Windows; + +namespace HMIToolkit; + +/// +/// Interaktionslogik für AnalogMotorWindow.xaml +/// +public partial class AnalogMotorWindow : Window +{ + public AnalogMotorWindow() + { + InitializeComponent(); + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml b/uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml new file mode 100644 index 0000000..15b9970 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml.cs b/uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml.cs new file mode 100644 index 0000000..5a42eed --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/BinaryValveWindow.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows; + +namespace UniperHMI +{ + /// + /// Interaktionslogik für BinaryValveWindow.xaml + /// + public partial class BinaryValveWindow : Window + { + public BinaryValveWindow() + { + InitializeComponent(); + } + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/FeedbackToColorConverter.cs b/uniper_hmi/UniperHMI/HMIToolkit/FeedbackToColorConverter.cs new file mode 100644 index 0000000..3411a73 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/FeedbackToColorConverter.cs @@ -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; + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogMotorControl/AnalogMotorControl.xaml b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogMotorControl/AnalogMotorControl.xaml new file mode 100644 index 0000000..626d329 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/AnalogMotorControl/AnalogMotorControl.xaml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControl.xaml.cs b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControl.xaml.cs new file mode 100644 index 0000000..6f4ae19 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControl.xaml.cs @@ -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 +{ + /// + /// Interaktionslogik für ProcessIntlkButtonControl.xaml + /// + public partial class IntlkButtonControl : UserControl + { + public IntlkButtonControl() + { + InitializeComponent(); + // Unloaded += OnUnloaded; + } + + private void OnUnloaded(object? sender, EventArgs e) + { + var disposable = DataContext as IDisposable; + disposable?.Dispose(); + } + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControlVM.cs b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControlVM.cs new file mode 100644 index 0000000..8b66b64 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockControl/IntlkControlVM.cs @@ -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; + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml new file mode 100644 index 0000000..c45ae3d --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml.cs b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml.cs new file mode 100644 index 0000000..b331460 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetails.xaml.cs @@ -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 +{ + /// + /// Interaktionslogik für IntlkDetails.xaml + /// + public partial class IntlkDetails : UserControl + { + public IntlkDetails() + { + InitializeComponent(); + // Unloaded += OnUnloaded; + } + + private void OnUnloaded(object? sender, EventArgs e) + { + var disposable = DataContext as IDisposable; + disposable?.Dispose(); + } + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsVM.cs b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsVM.cs new file mode 100644 index 0000000..7f6b3aa --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsVM.cs @@ -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 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; + } + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml new file mode 100644 index 0000000..695641c --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml @@ -0,0 +1,13 @@ + + + + + diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml.cs b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml.cs new file mode 100644 index 0000000..f1bb72d --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/InterlockDetailsControl/IntlkDetailsWindow.xaml.cs @@ -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 +{ + /// + /// Interaktionslogik für IntlkDetailsWindow.xaml + /// + public partial class IntlkDetailsWindow : Window + { + public IntlkDetailsWindow() + { + InitializeComponent(); + } + } +} diff --git a/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/structures/HMIDataTypes.cs b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/structures/HMIDataTypes.cs new file mode 100644 index 0000000..332eb81 --- /dev/null +++ b/uniper_hmi/UniperHMI/HMIToolkit/HMIObjects/structures/HMIDataTypes.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/uniper_hmi/UniperHMI/MainWindow.xaml b/uniper_hmi/UniperHMI/MainWindow.xaml new file mode 100644 index 0000000..e8d2872 --- /dev/null +++ b/uniper_hmi/UniperHMI/MainWindow.xaml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + +