omni plus new ui

This commit is contained in:
Stoyan Zlatev
2024-01-24 17:14:10 +01:00
parent 1ed57bae10
commit 5eb69b6794
70 changed files with 2458 additions and 1278 deletions
@@ -0,0 +1,10 @@
namespace ExchangeHub.Contracts
{
public delegate void VoidEventHandler(string groupName);
public delegate void IntEventHandler(int value, string groupName);
public delegate void DoubleEventHandler(double value, string groupName);
public delegate void StringEventHandler(string value, string groupName);
}
@@ -0,0 +1,43 @@
namespace ExchangeHub.Contracts
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Only for COM usage.
/// Exposes event handlers for the (VB6) master.
/// </summary>
[Guid("9FAA6100-E33F-46F7-9151-C85903472388")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IExchangeEvents
{
/// <summary>
/// On received: VB6 should stop all running tasks.
/// </summary>
void Disposed(string groupName);
/// <summary>
/// On received: VB6 should start given flow.
/// On sent: VB6 notifies that the flow is reached.
/// </summary>
void StartFlow(double valueM3H, string groupName);
/// <summary>
/// On received: VB6 should stop any flow.
/// On sent: VB6 notifies that the flow is stopped.
/// </summary>
void StopFlow(string groupName);
/// <summary>
/// On received: VB6 should start reference volume messuring.
/// On sent: VB6 notifies that the reference messuring has started.
/// </summary>
void StartReferenceMessurement(int durationSeconds, string groupName);
/// <summary>
/// On received: VB6 should stop reference volume messuring.
/// On sent: VB6 sends the volume messured.
/// </summary>
void StopReferenceMessurement(double valueM3, string groupName);
}
}
@@ -0,0 +1,10 @@
namespace ExchangeHub.Contracts
{
/// <summary>
/// <para>Only for the SignalR host.</para>
/// <para>Exposes used events as methods.</para>
/// </summary>
public interface IExchangeHub : IExchangeEvents
{
}
}
@@ -0,0 +1,22 @@
namespace ExchangeHub.Contracts
{
using System;
using System.Runtime.InteropServices;
[Guid("21EA6C57-A004-456E-8D99-7DCAD3481205")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IExchangeHubMaster : IExchangeHubSlave
{
void Connect(string url);
void SendDisposed(string _ = "");
void SendStartFlow(double volumeM3H, string _ = "");
void SendStopFlow(string _ = "");
void SendStartReferenceMessurement(int durationSeconds, string _ = "");
void SendStopReferenceMessurement(double volumeM3 = 0D, string _ = "");
}
}
@@ -0,0 +1,15 @@
namespace ExchangeHub.Contracts
{
public interface IExchangeHubSlave
{
event VoidEventHandler Disposed;
event DoubleEventHandler StartFlow;
event VoidEventHandler StopFlow;
event IntEventHandler StartReferenceMessurement;
event DoubleEventHandler StopReferenceMessurement;
}
}
@@ -0,0 +1,235 @@
namespace ExchangeHub
{
using ExchangeHub.Contracts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IExchangeEvents))]
[Guid("2ABFAC6C-9F3C-4702-9E08-4979A26577EF")]
[ProgId("ExchangeHub.ExchangeConnection")]
public class ExchangeConnection : IExchangeHubMaster
{
public const string GROUP_KEY = "GroupNameKey";
public const string HUB_DIR = ".\\ExchangeHub";
public const string HUB_NAME = "ExchangeHub";
public const string STR_EMPTY = "";
private static readonly string GroupName = Environment.MachineName;
private static readonly string LoggingDir = Directory.CreateDirectory(HUB_DIR).FullName;
private readonly ICollection<IDisposable> disposables;
private HubConnection connection;
private IHubProxy proxy;
public ExchangeConnection()
=> this.disposables = new List<IDisposable>();
public event VoidEventHandler Disposed;
public event DoubleEventHandler StartFlow;
public event VoidEventHandler StopFlow;
public event IntEventHandler StartReferenceMessurement;
public event DoubleEventHandler StopReferenceMessurement;
public event StringEventHandler StateChanged;
public void Connect(string url)
{
this.connection = new HubConnection(url, queryString: $"{GROUP_KEY}={Environment.MachineName}");
this.connection.Closed += this.Connection_Closed;
this.connection.ConnectionSlow += this.Connection_ConnectionSlow;
this.connection.Error += this.Connection_Error;
this.connection.Received += this.Connection_Received;
this.connection.Reconnected += this.Connection_Reconnected;
this.connection.Reconnecting += this.Connection_Reconnecting;
this.connection.StateChanged += this.Connection_StateChanged;
this.proxy = this.connection.CreateHubProxy(HUB_NAME);
this.disposables.Add(this.proxy.On<string>( nameof(this.Disposed), this.ReceiveDisposed));
this.disposables.Add(this.proxy.On<double, string>( nameof(this.StartFlow), this.FlowStarted));
this.disposables.Add(this.proxy.On<string>( nameof(this.StopFlow), this.FlowStopped));
this.disposables.Add(this.proxy.On<int, string>( nameof(this.StartReferenceMessurement), this.MessurementStarted));
this.disposables.Add(this.proxy.On<double, string>( nameof(this.StopReferenceMessurement), this.MessurementStopped));
try
{
this.connection
.Start()
.Wait();
}
catch (Exception e)
{
this.FileAppendLine(e.ToString());
}
}
public void Disconnect()
{
try
{
this.SendDisposed();
this.connection.Closed -= this.Connection_Closed;
this.connection.ConnectionSlow -= this.Connection_ConnectionSlow;
this.connection.Error -= this.Connection_Error;
this.connection.Received -= this.Connection_Received;
this.connection.Reconnected -= this.Connection_Reconnected;
this.connection.Reconnecting -= this.Connection_Reconnecting;
this.connection.StateChanged -= this.Connection_StateChanged;
foreach (var disposable in this.disposables)
{
disposable.Dispose();
}
Task.Factory.StartNew(this.connection.Dispose);
this.FileAppendLine($"Connection disconnected.");
}
catch (Exception e)
{
this.FileAppendLine(e.ToString());
}
}
public void SendDisposed(string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke<string>(nameof(this.Disposed), GroupName);
}
}
public void SendStartFlow(double volumeM3H, string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StartFlow), volumeM3H, GroupName);
}
}
public void SendStopFlow(string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StopFlow), GroupName);
}
}
public void SendStartReferenceMessurement(int durationSeconds, string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StartReferenceMessurement), durationSeconds, GroupName);
}
}
public void SendStopReferenceMessurement(double volumeM3H = 0D, string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StopReferenceMessurement), volumeM3H, GroupName);
}
}
private void ReceiveDisposed(string groupName)
{
if (GroupName == groupName)
{
this.Disposed?.Invoke(groupName);
}
}
private void FlowStarted(double volumeM3H, string groupName)
{
if (GroupName == groupName)
{
this.StartFlow?.Invoke(volumeM3H, groupName);
}
}
private void FlowStopped(string groupName)
{
if (GroupName == groupName)
{
this.StopFlow?.Invoke(groupName);
}
}
private void MessurementStarted(int seconds, string groupName)
{
if (GroupName == groupName)
{
this.StartReferenceMessurement?.Invoke(seconds, groupName);
}
}
private void MessurementStopped(double volumeMessured, string groupName)
{
if (GroupName == groupName)
{
this.StopReferenceMessurement?.Invoke(volumeMessured, groupName);
}
}
private void Connection_Closed()
{
this.FileAppendLine("HubConnection closed!");
}
private void Connection_ConnectionSlow()
{
this.FileAppendLine("HubConnection is about to timeout!");
}
private void Connection_Error(Exception e)
{
this.FileAppendLine(e.ToString());
}
private void Connection_Received(string data)
{
this.FileAppendLine(data);
}
private void Connection_Reconnected()
{
this.FileAppendLine("HubConnection reconnected!");
}
private void Connection_Reconnecting()
{
this.FileAppendLine("HubConnection reconnecting!");
}
private void Connection_StateChanged(StateChange state)
{
this.FileAppendLine($"{state.OldState} -> {state.NewState}");
}
private void FileAppendLine(string text)
{
try
{
var fileName = $"{LoggingDir}\\{DateTime.Now:yyyy_MM_dd}.txt";
File.AppendAllText(
path: $"{LoggingDir}\\{DateTime.Now:yyyy_MM_dd}.txt",
contents: $"[{DateTime.Now:HH:mm:ss}] {text}{Environment.NewLine}");
this.StateChanged?.Invoke(text, GroupName);
}
catch (Exception e)
{
this.StateChanged?.Invoke(e.ToString(), GroupName);
}
}
}
}
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ExchangeHub</RootNamespace>
<AssemblyName>ExchangeHub</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNet.SignalR.Client, Version=2.4.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.SignalR.Client.2.4.3\lib\net40\Microsoft.AspNet.SignalR.Client.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Contracts\EventHandlers.cs" />
<Compile Include="Contracts\IExchangeEvents.cs" />
<Compile Include="Contracts\IExchangeHub.cs" />
<Compile Include="Contracts\IExchangeHubMaster.cs" />
<Compile Include="Contracts\IExchangeHubSlave.cs" />
<Compile Include="ExchangeConnection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ExchangeHub")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ExchangeHub")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6033ff0c-cf32-4bc5-8efe-4774ccdc663d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.SignalR.Client" version="2.4.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net40" />
</packages>
+2 -1
View File
@@ -6,6 +6,7 @@
<add key="COMPorts" value="COM4" />
<add key="ExchangeHubURL" value="http://sla12iis01.emea.sensus.net/LaaProductionWeb" />
<!--<add key="ExchangeHubURL" value="http://localhost:52822/LaaProductionWeb"/>-->
<add key="OmniDB" value="Server=SLASQL01.emea.sensus.net; Database=AuftragKopie; User ID=sa; Password=sqlserver;" />
<!--<add key="OmniDB" value="Server=SLASQL01.emea.sensus.net; Database=AuftragKopie; User ID=sa; Password=sqlserver;" />-->
<add key="OmniDB" value="Server=SLASQL01.emea.sensus.net; Database=Auftrag; User ID=sa; Password=sqlserver;" />
</appSettings>
</configuration>
+1 -1
View File
@@ -8,7 +8,7 @@
public partial class App : Application
{
public static readonly string ExePath = typeof(App).Assembly.Location;
public static readonly string Path = new FileInfo(ExePath).DirectoryName;
public static readonly string ExeDirectory = new FileInfo(ExePath).DirectoryName;
public static event Action Disposed;
@@ -0,0 +1,21 @@
namespace OMNIPruefung.Models
{
using OmniPlus;
public class OmniInspectionModel
{
private OmniDatabase database;
public OmniInspectionModel()
{
this.database = new OmniDatabase(Appsettings.Current.OmniDB);
}
public OmniAuftrag Auftrag { get; private set; }
public void LoadAuftrag(string suchNr)
{
this.Auftrag = this.database.LoadAuftrag(suchNr);
}
}
}
@@ -37,6 +37,10 @@
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SqlExtensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\SqlExtensions\SqlExtensions.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Data" />
@@ -65,6 +69,11 @@
<Compile Include="Models\Appsettings.cs" />
<Compile Include="Models\COMPorts.cs" />
<Compile Include="Models\EOLContentM.cs" />
<Compile Include="Models\OmniInspectionModel.cs" />
<Compile Include="OmniInspection.xaml.cs">
<DependentUpon>OmniInspection.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\BaseVM.cs" />
<Compile Include="ViewModels\Content\SettingsContentVM.cs" />
<Compile Include="ViewModels\Features\OMNIPlusVM.cs" />
<Compile Include="ViewModels\Base\Command.cs" />
@@ -77,6 +86,8 @@
<Compile Include="ViewModels\Content\MainContentVM.cs" />
<Compile Include="ViewModels\Features\OMNISysParameters.cs" />
<Compile Include="ViewModels\NodeVM.cs" />
<Compile Include="ViewModels\OmniAuftragVM.cs" />
<Compile Include="ViewModels\OmniInspectionVM.cs" />
<Compile Include="ViewModels\Options\COMOptionVM.cs" />
<Compile Include="ViewModels\Options\EOLOptionVM.cs" />
<Compile Include="ViewModels\Options\ExchangeHubOptionVM.cs" />
@@ -114,6 +125,10 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="OmniInspection.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Content\COMContent.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -161,7 +176,7 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ExchangeHub\ExchangeHub.csproj">
<ProjectReference Include="..\ExchangeHub\ExchangeHub.csproj">
<Project>{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}</Project>
<Name>ExchangeHub</Name>
</ProjectReference>
@@ -0,0 +1,26 @@
<Window x:Class="OMNIPruefung.OmniInspection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:OMNIPruefung.ViewModels"
Height="600"
Width="977">
<Window.DataContext>
<VM:OmniInspectionVM />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding SuchNr}" Width="150" Margin="5" FontFamily="Consolas" />
<Button Grid.Column="1" Command="{Binding Load}" Content="Load" Margin="5" Padding="5" FontFamily="Consolas" />
<Label Grid.Column="2" Content="{Binding AuftragVM}" />
</Grid>
</Grid>
</Window>
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 OMNIPruefung
{
/// <summary>
/// Interaction logic for OmniInspection.xaml
/// </summary>
public partial class OmniInspection : Window
{
public OmniInspection()
{
InitializeComponent();
}
}
}
@@ -8,5 +8,12 @@
protected void NotifyPropertyChanged(string property)
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
protected void Set<T>(ref T oldValue, T newValue, string property)
{
oldValue = newValue;
this.NotifyPropertyChanged(property);
}
}
}
@@ -0,0 +1,49 @@
namespace OMNIPruefung.ViewModels
{
using System;
using System.ComponentModel;
using System.Windows.Input;
public abstract class BaseVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string property)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
protected void Set<T>(ref T oldValue, T newValue, string property)
{
oldValue = newValue;
this.NotifyPropertyChanged(property);
}
protected class Command : ICommand
{
private readonly Action executable;
public Command(Action executable)
{
this.executable = executable;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object _)
{
return this.executable != null;
}
public void Execute(object _)
{
this.executable?.Invoke();
}
}
}
}
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -10,7 +11,7 @@
using OmniPlus.Features;
using OmniPlus.Features.Enums;
using OmniPlus.Inspection;
using OMNIPruefung.Models;
using OMNIPruefung.ViewModels.Base;
using OMNIPruefung.ViewModels.Features;
using OMNIPruefung.ViewModels.Options;
@@ -21,12 +22,14 @@
= new SortedDictionary<OmniPlusTestPoint, OmniPlusTest>();
private OmniConnection connection;
private OmniDatabase database;
public COMContentVM() : base()
{
this.Meter = new OMNIPlusVM();
this.Option = new COMOptionVM(this);
this.Option.OptionSelected += this.NotifyOptionSelected;
this.database = new OmniDatabase(Appsettings.Current.OmniDB);
}
private int nr;
@@ -102,6 +105,18 @@
}
}
private bool isvalid = true;
public bool IsValid
{
get => this.isvalid;
set
{
this.isvalid = value;
this.NotifyPropertyChanged(nameof(this.IsValid));
}
}
private string state;
public string State
{
@@ -176,11 +191,16 @@
if (this.IsRunning())
{
var response = this.connection.ViewSystemParameters();
this.Running = response.IsValid;
this.Header = response.BuildInfo.Value;
this.Progress += 10;
this.Meter.Add(response);
App.Invoke(() =>
{
this.Running = response.Status == Status.Completed;
this.IsValid = response.IsValid;
this.Header = response.BuildInfo.Value;
this.Progress += 10;
this.Meter.Add(response);
});
}
}
@@ -196,10 +216,11 @@
if (this.IsRunning())
{
var response = this.connection.Set(defaults.InputVolume);
this.Running = response.Succeeded;
this.Running = response.Status == Status.Completed;
this.IsValid = this.Running;
this.Progress += 10;
if (this.Running)
if (this.IsValid)
{
this.Meter.Add(defaults.InputVolume);
@@ -228,13 +249,14 @@
var rotations = pp.Rotations;
var duration = pp.Duration;
var response = connection.StartChamberCalibration(pp.Rotations, pp.Duration);
this.Running = response.Succeeded && response.Control == ChamberCalibrationResponse.TEST_ACTIVATED;
this.Running = response.Status == Status.Completed;
this.IsValid = response.Completed && response.Control == ChamberCalibrationResponse.TEST_ACTIVATED;
this.Progress += 10;
this.Meter.Add(pp);
if (this.Running)
if (this.IsValid)
{
this.State = $"{this.Header} PP {rotations}/{duration}";
}
@@ -256,24 +278,25 @@
{
if (this.IsRunning())
{
var resonse = connection.ViewChamberCalibration();
var response = connection.ViewChamberCalibration();
this.results[pp].Rotations = resonse.Rotations;
this.results[pp].Duration = resonse.Duration;
this.results[pp].Rotations = response.Rotations;
this.results[pp].Duration = response.Duration;
this.results[pp].MeterFlowM3S = pp.MeterFlowM3S(this.results[pp]);
this.results[pp].ReferenceFlowM3S = referenceFlowM3S;
this.Running = resonse.Succeeded && resonse.Control == ChamberCalibrationResponse.TEST_COMPLETED;
this.Running = response.Status == Status.Completed;
this.IsValid = response.Completed && response.Control == ChamberCalibrationResponse.TEST_COMPLETED;
this.Meter.Add(this.results[pp]);
if (this.Running)
if (this.IsValid)
{
this.State = $"{this.Header} PP {pp.Rotations}/{pp.Duration} - completed.";
}
else
{
this.State = $"{this.Header} PP {pp.Rotations}/{pp.Duration} failed: Status:{resonse.Status}, Control:{resonse.Control}";
this.State = $"{this.Header} PP {pp.Rotations}/{pp.Duration} failed: Status:{response.Status}, Control:{response.Control}";
}
}
@@ -298,16 +321,25 @@
registerSettings.Size = this.Meter.Size;
registerSettings.Range = this.Meter.Range;
registerSettings.VolumePerPulseUnit = 0x00;
registerSettings.MeterUnits = (byte)MessurementUnits.USGallons;
registerSettings.FlowUnits = (byte)MessurementUnits.USGallons;
registerSettings.FlowRate = (byte)TimeUnits.Minutes;
registerSettings.FactoryCorrection = this.Meter.FactoryCorrection;
registerSettings.MeterUnits = (byte)MessurementUnits.CubicMeters;
registerSettings.FlowUnits = (byte)MessurementUnits.CubicMeters;
registerSettings.FlowRate = (byte)TimeUnits.Hours;
registerSettings.FactoryCorrection = 33;
registerSettings.FieldCorrection = 0x00;
registerSettings.PulseWeight = 0x01;
registerSettings.PulseWidth = 0x02;
registerSettings.PulseUpdate = 0x00;
registerSettings.PulseWeight = 0;
registerSettings.PulseWidth = 7;
registerSettings.PulseUpdate = 0;
var response = this.connection.Set(registerSettings);
if (response.Status == Status.Completed)
{
this.Meter.AddResult($">>> Correction Factor", $"{registerSettings.FactoryCorrection / 10D:0.00} %");
}
else
{
this.Meter.AddResult($">>> !!! Correction Factor", $"{registerSettings.FactoryCorrection / 10D:0.00} %");
}
}
}
@@ -508,9 +540,13 @@
{
var response = this.connection.ViewRegisterSettings();
if (response.Succeeded)
if (response.Completed)
{
this.Meter.AddResult("<<< Correction factor", $"{response.FactoryCorrection / 10D:0.00} %");
this.Meter.AddResult("<<< Correction factor", $"{(response.FactoryCorrection / 10D):0.00} %");
}
else
{
this.Meter.AddResult("<<< !!! Correction factor", $"{(response.FactoryCorrection / 10D):0.00} %");
}
}
}
@@ -520,20 +556,41 @@
internal double GetCorrectionFactor()
{
var deviations = this.results
.OrderBy(x => x.Key.GPM)
var orderedResults = this.results
.OrderBy(x => x.Key.GPM);
var accuracies = orderedResults
.Select(x => x.Value.DifferencePercentage())
.ToArray();
var correction = deviations.GetCorrectionFactor();
var correctionUnit = 1 + correction / 100;
var correction = accuracies.GetCorrectionFactor();
this.State = $"{this.Header}, correction: {correction:0.00} %";
this.Meter.AddFactoryCorrection(correction);
this.Meter.AddResult(string.Empty, string.Empty);
foreach (var deviation in deviations)
var correctionUnit = 1 + correction / 100;
var testPoints = orderedResults
.Select(x => x.Key)
.ToArray();
var length = testPoints.Length;
for (int i = 0; i < length; i++)
{
this.Meter.AddResult($"{deviation:0.00} %", $"{deviation * correctionUnit:0.00} %");
var testPoint = testPoints[i];
var accuracy = accuracies[i];
var _accuracy = accuracy * correctionUnit;
var state = "Out Of Range";
if (testPoint.MinDiff <= _accuracy && _accuracy <= testPoint.MaxDiff)
{
state = "OK";
}
else if (this.IsValid)
{
this.IsValid = false;
}
this.Meter.AddResult($"{accuracy:0.00} %", $"{_accuracy:0.00} % - ({state})");
}
return correction;
@@ -560,5 +617,106 @@
return this.Connected;
}
internal Task ReadDisplayAsync(CancellationToken cancellationToken)
{
void ReadDisplay()
{
var response = this.connection.ViewReadings();
this.Meter.AddResult($"<<< Display value", response.Value);
}
return Task.Factory.StartNew(ReadDisplay, cancellationToken);
}
public Task GetStateIfNewAsync(CancellationToken cancellationToken)
{
void GetState()
{
var buildInfo = this.connection.ViewBuildInformation();
if (buildInfo.Status != Status.Completed)
{
return;
}
var omniID = buildInfo.Value;
if (string.IsNullOrWhiteSpace(omniID))
{
return;
}
//else if (this.database.OMNIPlus_Exists(omniID))
//{
// return;
//}
var commands = new List<byte[]>();
commands.Add(new byte[] { 0x01 });
commands.Add(new byte[] { 0x03 });
commands.Add(new byte[] { 0x05 });
commands.Add(new byte[] { 0x07 });
commands.Add(new byte[] { 0x09 });
commands.Add(new byte[] { 0x0B });
commands.Add(new byte[] { 0x0D });
commands.Add(new byte[] { 0x0F });
commands.Add(new byte[] { 0x11 });
commands.Add(new byte[] { 0x13 });
commands.Add(new byte[] { 0x15 });
commands.Add(new byte[] { 0x17 });
commands.Add(new byte[] { 0x1F });
commands.Add(new byte[] { 0x21 });
commands.Add(new byte[] { 0x25 });
commands.Add(new byte[] { 0x27 });
commands.Add(new byte[] { 0x29 });
commands.Add(new byte[] { 0x2B });
commands.Add(new byte[] { 0xFD, 0x02 });
commands.Add(new byte[] { 0xFD, 0x05 });
commands.Add(new byte[] { 0xFD, 0x06 });
commands.Add(new byte[] { 0xFD, 0x08 });
commands.Add(new byte[] { 0xFD, 0x0A });
commands.Add(new byte[] { 0xFD, 0x0E });
commands.Add(new byte[] { 0xFD, 0x10 });
commands.Add(new byte[] { 0xFD, 0x12 });
commands.Add(new byte[] { 0xFD, 0x14 });
commands.Add(new byte[] { 0xFD, 0x22 });
commands.Add(new byte[] { 0xFD, 0x24 });
commands.Add(new byte[] { 0xFD, 0x26 });
commands.Add(new byte[] { 0xFD, 0x28 });
commands.Add(new byte[] { 0xFD, 0x39 });
commands.Add(new byte[] { 0xFD, 0x3D });
commands.Add(new byte[] { 0xFD, 0x55 });
commands.Add(new byte[] { 0xFD, 0x63 });
commands.Add(new byte[] { 0xFD, 0x7B });
commands.Add(new byte[] { 0xFD, 0x7E, 0x00 });
commands.Add(new byte[] { 0xFD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
commands.Add(new byte[] { 0xFD, 0x8B });
commands.Add(new byte[] { 0xFD, 0xA9 });
commands.Add(new byte[] { 0xFD, 0xAA });
commands.Add(new byte[] { 0xFD, 0xAC });
commands.Add(new byte[] { 0xFD, 0xB7 });
commands.Add(new byte[] { 0xFD, 0xBC });
commands.Add(new byte[] { 0xFD, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
commands.Add(new byte[] { 0xFD, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
commands.Add(new byte[] { 0xFD, 0xC4, 0x00 });
commands.Add(new byte[] { 0xFD, 0xC6 });
commands.Add(new byte[] { 0xFD, 0xC7 });
var state = new StringBuilder();
foreach (var cmd in commands)
{
var response = this.connection.Send(cmd);
var entry = $"{BitConverter.ToString(cmd)}:{BitConverter.ToString(response)}";
state.AppendLine(entry);
}
//this.database.OMNIPlus_Insert(omniID, state.ToString());
};
return Task.Factory.StartNew(GetState, cancellationToken);
}
}
}
@@ -49,10 +49,11 @@
this.CancelInspection = new Command(this.CancelInspectionHandler);
this.StartInspection = new Command(this.StartInspectionHandler);
this.CheckInspection = new Command(this.CheckInspectionHandler);
this.ReadDisplay = new Command(this.ReadDisplayCommand);
}
private int size;
public int Size
private byte size;
public byte Size
{
get => this.size;
set
@@ -159,6 +160,13 @@
}
}
private string suchnr;
public string SuchNr
{
get => this.suchnr;
set => this.Set(ref this.suchnr, value, nameof(SuchNr));
}
private OmniPlusType omniDefaults;
public OmniPlusType OmniDefaults
{
@@ -181,13 +189,14 @@
public ICommand CheckInspection { get; }
public ICommand ReadDisplay { get; }
private string errorLog;
private void PrepareConnections()
{
try
{
var directory = Directory.CreateDirectory(".\\Results");
this.errorLog = Path.Combine(directory.FullName, $"errors.txt");
this.errorLog = Path.Combine(App.ExeDirectory, $"ui_logs.txt");
File.AppendAllText(this.errorLog, string.Empty);
}
@@ -198,53 +207,67 @@
this.exchangeConnection.Connect(Appsettings.Current.ExchangeHubURL);
if (this.Size == 0 || this.Type is null)
if (string.IsNullOrWhiteSpace(this.SuchNr) && this.Size == 0 && this.Type is null)
{
this.Error = "Size und Type auswählen!";
this.Error = "FertigungsauftragNr eingeben oder Size und Type auswählen!";
return;
return;
}
this.Error = default(string);
if (this.Nodes.Any())
App.Invoke(() =>
{
foreach (var disposable in this.Nodes.Cast<IDisposable>())
if (this.Nodes.Any())
{
disposable.Dispose();
foreach (var disposable in this.Nodes.Cast<IDisposable>())
{
disposable.Dispose();
}
this.Nodes.Clear();
this.Option.Clear();
}
this.Nodes.Clear();
this.Option.Clear();
}
if (!string.IsNullOrWhiteSpace(this.SuchNr))
{
this.dbcontext.LoadAuftrag(this.SuchNr);
}
else if (this.Size > 0 && !string.IsNullOrWhiteSpace(this.Type))
{
this.dbcontext.LoadAuftrag(this.Size, this.Type);
this.dbcontext.LoadOmniDefaults((byte)this.Size, this.Type, this.OmniDefaults);
this.NotifyPropertyChanged(nameof(this.OmniDefaults));
this.Text = $"ME OMNI 1.5-2\" {this.Type}";
this.Text = $"ME OMNI 1.5-2\" {this.Type}";
}
});
try
{
var placeNr = 1;
foreach (var com in Appsettings.Current.COMPorts)
App.Invoke(() =>
{
var comVM = new COMContentVM();
comVM.ContentSelected += this.NotifyCotnentSelected;
comVM.PortName = com;
comVM.Nr = placeNr++;
comVM.Header = $"{com}";
comVM.State = $"{com}";
var placeNr = 1;
this.Nodes.Add(comVM);
this.Option.Add(comVM.Option);
}
foreach (var com in Appsettings.Current.COMPorts)
{
var comVM = new COMContentVM();
comVM.ContentSelected += this.NotifyCotnentSelected;
comVM.PortName = com;
comVM.Nr = placeNr++;
comVM.Header = $"{com}";
comVM.State = $"{com}";
this.Option.SetIndentation(this.Option.Indent);
this.Nodes.Add(comVM);
this.Option.Add(comVM.Option);
}
this.Option.SetIndentation(this.Option.Indent);
});
var metersVM = this.Nodes.Cast<COMContentVM>();
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in this.Nodes.Cast<COMContentVM>())
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.InitializeAsync(cancellationToken));
}
@@ -252,11 +275,19 @@
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in this.Nodes.Cast<COMContentVM>())
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.GetStateIfNewAsync(cancellationToken));
}
});
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.ReadSystemParametersAsync(cancellationToken));
}
}, wait: false);
}, false);
}
catch (Exception e)
{
@@ -264,10 +295,13 @@
this.LogError(e.ToString());
}
this.CanStop = false;
this.CanStart = true;
this.Error = default(string);
this.State = default(string);
App.Invoke(() =>
{
this.CanStop = false;
this.CanStart = true;
this.Error = default(string);
this.State = default(string);
});
}
private void CancelInspectionHandler()
@@ -360,14 +394,10 @@
break;
}
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
// this.canceled = this.canceled || meterVM.IsRunning();
tasks.Add(meterVM.StartPPCalibrationAsync(pp, cancellationToken));
}
});
@@ -397,8 +427,6 @@
{
foreach (var meterVM in metersVM)
{
// this.canceled = this.canceled || meterVM.IsRunning();
tasks.Add(meterVM.StopPPCalibrationAsync(pp, referenceFlowM3S, cancellationToken));
}
});
@@ -411,20 +439,9 @@
this.exchangeConnection.SendStopFlow();
if (!this.canceled)
foreach (var meterVM in metersVM)
{
foreach (var meterVM in metersVM)
{
meterVM.GetCorrectionFactor();
}
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.SetRegisterSettingsAsync(cancellationToken));
}
});
meterVM.GetCorrectionFactor();
}
foreach (var meterVM in metersVM)
@@ -564,8 +581,6 @@
};
this.timer.Elapsed += (_1, _2) =>
{
this.AvailableIn -= 1;
if (show)
{
if (error)
@@ -584,7 +599,12 @@
{
this.AvailableIn = 0;
this.awaiter?.Set();
return;
}
this.AvailableIn -= 1;
};
this.timer.Start();
@@ -741,8 +761,6 @@
{
foreach (var t in _tasks)
{
this.LogError($"[{t.Id}]:{nameof(t.Status)} = {t.Status}{Environment.NewLine}");
if (t.Exception != null)
{
this.LogError($"[{t.Id}]:{t.Exception}{Environment.NewLine}");
@@ -766,8 +784,6 @@
.StartNew(action, cancellationToken)
.ContinueWith(t =>
{
this.LogError($"[{t.Id}]:{nameof(t.Status)} = {t.Status}{Environment.NewLine}");
if (t.Exception != null)
{
this.LogError($"[{t.Id}]:{t.Exception}{Environment.NewLine}");
@@ -786,5 +802,24 @@
Console.WriteLine(e);
}
}
private void ReadDisplayCommand()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
var metersVM = this.Nodes.Cast<COMContentVM>();
this.InvokeAsync(() =>
{
this.InvokeAsync((tasks, _cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.ReadDisplayAsync(_cancellationToken));
}
});
}, this.cancellationToken);
}
}
}
@@ -47,7 +47,7 @@
internal void Add(OmniPlus.Features.SystemParameters response)
{
if (response.Succeeded)
if (response.Completed)
{
this.AddResult(nameof(response.VersionAndType), response.VersionAndType.Value);
this.AddResult(nameof(response.BuildInfo), response.BuildInfo.Value);
@@ -66,6 +66,8 @@
this.IntPart = response.IntPartFull;
this.Fraction = response.Fraction;
this.AddResult(string.Empty, string.Empty);
this.AddResult(nameof(InputVolume), string.Empty);
this.AddResult(nameof(response.Size), $"{response.Size}");
this.AddResult(nameof(response.Range), $"{response.Range}");
this.AddResult(nameof(response.Direction), $"{response.Direction}");
@@ -75,18 +77,18 @@
internal void Add(OmniPlusTestPoint pp)
{
this.AddResult("", $"");
this.AddResult("Test point:", $"{pp.Rotations}/{pp.Duration:0}");
this.AddResult("Volume", $"{pp.RequiredFlowM3H:0.00000000 m³/h}");
this.AddResult("Validation frame", $"{pp.MinDiff:0.00}% - {pp.MaxDiff:0.00}%");
this.AddResult(string.Empty, string.Empty);
this.AddResult("Test point", $"{pp.Rotations}/{pp.Duration:0}");
this.AddResult("Test flow", $"{pp.RequiredFlowM3H:0.00000000 m³/h}");
this.AddResult("Test frame", $"{pp.MinDiff:0.00}% - {pp.MaxDiff:0.00}%");
}
internal void Add(OmniPlusTest test)
{
this.AddResult("Test result:", $"{test.Rotations:0}/{test.Duration:0.0000}");
this.AddResult("Meter volume", $"{test.MeterFlowM3S:0.00000000 m³}");
this.AddResult("Reference volume", $"{test.ReferenceFlowM3S:0.00000000 m³}");
this.AddResult("Deviation", $"{test.DifferencePercentage():0.00}%");
this.AddResult("Meter flow", $"{test.MeterFlowM3S:0.00000000} m³/h");
this.AddResult("Reference flow", $"{test.ReferenceFlowM3S:0.00000000} m³/h");
this.AddResult("Accuracy", $"{test.DifferencePercentage():0.00}%");
}
internal void Add(ConfigurationParameters response)
@@ -105,7 +107,7 @@
{
this.FactoryCorrection = (sbyte)(value * 10);
this.AddResult("Correction", $"{value:0.00} %");
this.AddResult("Correction factor", $"{value:0.00} %");
}
}
@@ -0,0 +1,14 @@
namespace OMNIPruefung.ViewModels
{
using OmniPlus;
public class OmniAuftragVM : BaseVM
{
private OmniAuftrag auftrag;
public OmniAuftragVM(OmniAuftrag auftrag)
{
this.auftrag = auftrag;
}
}
}
@@ -0,0 +1,31 @@
namespace OMNIPruefung.ViewModels
{
using OMNIPruefung.Models;
using System.Windows.Input;
public class OmniInspectionVM : BaseVM
{
private OmniInspectionModel model;
public OmniInspectionVM()
{
this.model = new OmniInspectionModel();
this.Load = new Command(this.LoadComamnd);
}
private string suchNr;
public string SuchNr
{
get => this.suchNr;
set => this.Set(ref this.suchNr, value, nameof(SuchNr));
}
public ICommand Load { get; }
private void LoadComamnd()
{
this.model.LoadAuftrag(this.suchNr);
}
}
}
@@ -31,6 +31,12 @@
set => this.NotifyPropertyChanged(nameof(this.Running));
}
public bool IsValid
{
get => this.parent.IsValid;
set => this.NotifyPropertyChanged(nameof(this.IsValid));
}
public bool Connected
{
get => this.parent.Connected;
@@ -58,6 +64,7 @@
this.NotifyPropertyChanged(nameof(this.Progress));
this.NotifyPropertyChanged(nameof(this.State));
this.NotifyPropertyChanged(nameof(this.Visible));
this.NotifyPropertyChanged(nameof(this.IsValid));
}
}
}
@@ -77,12 +77,15 @@
<Grid Grid.Row="9" Grid.ColumnSpan="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="150" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Grid.Column="0" Text="{Binding Size}" HorizontalAlignment="Stretch" Margin="0, 2, 2, 2">
<TextBox Grid.Column="0" Text="{Binding SuchNr}" Margin="0, 2, 2, 2" />
<ComboBox Grid.Column="1" Text="{Binding Size}" HorizontalAlignment="Stretch" Margin="0, 2, 2, 2">
<ComboBoxItem IsSelected="True">5</ComboBoxItem>
<ComboBoxItem >6</ComboBoxItem>
<ComboBoxItem >7</ComboBoxItem>
@@ -91,7 +94,7 @@
<ComboBoxItem >10</ComboBoxItem>
<ComboBoxItem >11</ComboBoxItem>
</ComboBox>
<ComboBox Grid.Column="1" Text="{Binding Type}" HorizontalAlignment="Stretch" Margin="2, 2, 0, 2">
<ComboBox Grid.Column="2" Text="{Binding Type}" HorizontalAlignment="Stretch" Margin="2, 2, 0, 2">
<ComboBoxItem IsSelected="True">C2</ComboBoxItem>
<ComboBoxItem >F2</ComboBoxItem>
<ComboBoxItem >R2</ComboBoxItem>
@@ -102,6 +105,10 @@
Style="{DynamicResource SystemBtn}"
Visibility="{Binding CanCheck, Converter={StaticResource BooleanVisibility}}"
Command="{Binding CheckInspection}"/>
<Button Grid.Column="4"
Content="Displays auslesen"
Style="{DynamicResource SystemBtn}"
Command="{Binding ReadDisplay}"/>
</Grid>
<!--<Label Grid.Column="0" Grid.Row="9" Content="Type eingeben: " VerticalContentAlignment="Center" VerticalAlignment="Stretch"/>
@@ -152,7 +159,7 @@
Grid.ColumnSpan="3"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Foreground="{Binding Running, Converter={StaticResource BooleanProgress}}"
Foreground="{Binding IsValid, Converter={StaticResource BooleanProgress}}"
Value="{Binding Progress}"
Background="WhiteSmoke"
BorderBrush="WhiteSmoke"
@@ -32,7 +32,7 @@
{
break;
}
this.WritePlain(1, 1, 1, 1);
this.waitHandle.Wait(1);
@@ -42,6 +42,11 @@
this.waitHandle.Wait(3000);
this.waitHandle.Reset();
if (response != null && response.Length > 0)
{
break;
}
}
this.StopListening();
@@ -362,5 +362,44 @@
return BitConverter.GetBytes(checksum);
}
public static byte[] CalculateCRC16(this byte[] data, ushort start, ushort length)
{
var ui_index = start;
var test = default(byte);
var zeichen = default(byte);
var crc_result = ushort.MaxValue;
if (data.Length >= length + start)
{
while (ui_index < length + start)
{
zeichen = data[ui_index];
ui_index++;
for (byte h = 0; h < 8; h++)
{
test = 0;
if ((crc_result & 0x8000) != 0)
{
test = 0x80;
}
crc_result <<= 1;
if (((zeichen & 0x80) ^ test) != 0)
{
crc_result ^= 0x1021;
}
zeichen <<= 1;
}
}
}
return BitConverter.GetBytes(crc_result);
}
}
}
@@ -59,7 +59,6 @@
{
try
{
this.buffer.Clear();
this.waitHandle.Set();
}
@@ -85,7 +84,7 @@
protected void WriteEncoded(params byte[] bytes)
{
try
{
{
if (this.encoder.TryEncode(bytes, out byte[] message))
{
this.Write(message, 0, message.Length);
@@ -145,7 +144,6 @@
private void StartReading()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
this.readingTask = Task.Factory.StartNew(this.ReadingTaskHandler, this.cancellationToken);
@@ -67,7 +67,7 @@
public class ConfigurationParametersSet : FeatureRequest
{
const int LENGTH = 90;
const int LENGTH = 80;
public ConfigurationParametersSet() : base(LENGTH)
{
@@ -88,9 +88,9 @@
get => this.programmableID;
set
{
this.SetASCIIBytes(value, 1, 20);
this.SetASCIIBytes(value, 0, 20);
this.programmableID = this.bytes.ToASCIIString(1, 20);
this.programmableID = this.bytes.ToASCIIString(0, 20);
}
}
@@ -105,9 +105,9 @@
get => this.factoryID;
set
{
this.SetASCIIBytes(value, 22, 33);
this.SetASCIIBytes(value, 21, 33);
this.factoryID = this.bytes.ToASCIIString(22, 33);
this.factoryID = this.bytes.ToASCIIString(21, 33);
}
}
@@ -139,9 +139,9 @@
get => this.readingPreset;
set
{
this.SetASCIIBytes(value, 39, 47);
this.SetASCIIBytes(value, 38, 47);
this.readingPreset = this.bytes.ToASCIIString(36, 47);
this.readingPreset = this.bytes.ToASCIIString(38, 47);
}
}
@@ -240,9 +240,9 @@
get => this.buildInfo;
set
{
this.SetASCIIBytes(value, 65, 79);
this.SetASCIIBytes(value, 64, 79);
this.buildInfo = this.bytes.ToASCIIString(65, 79);
this.buildInfo = this.bytes.ToASCIIString(64, 79);
}
}
@@ -257,9 +257,9 @@
get => this.deviceID;
set
{
this.SetASCIIBytes(value, 81, 89);
this.SetASCIIBytes(value, 80, 89);
this.deviceID = this.bytes.ToASCIIString(81, 89);
this.deviceID = this.bytes.ToASCIIString(80, 89);
}
}
@@ -28,6 +28,6 @@
set => this.SecondsSince = (uint)(value - epoch).TotalSeconds;
}
public static uint UTCNow => new Epoch20000101 { DateTime = DateTime.UtcNow }.SecondsSince + 3;
public static uint UTCNow => new Epoch20000101 { DateTime = DateTime.UtcNow }.SecondsSince + 10;
}
}
@@ -28,14 +28,17 @@
if (responseLength > 1)
{
Array.Copy(response, 1, this.bytes, 0, this.length);
for (int src = 1, dst = 0; src < responseLength && dst < this.length; src++, dst++)
{
this.bytes[dst] = response[src];
}
}
}
}
public Status Status { get; set; }
public bool Succeeded => this.Status == Status.Completed;
public bool Completed => this.Status == Status.Completed;
public override bool Equals(object obj)
=> obj is FeatureResponse outer && outer.bytes == this.bytes;
@@ -2,7 +2,7 @@
{
using System;
internal static class FeaturesExtensions
public static class FeaturesExtensions
{
public const int BYTE_BITS = 8;
@@ -49,14 +49,20 @@
public static byte[] Reverse(this byte[] bytes)
{
var length = bytes.Length / 2;
for (int i = 0; i < length; i++)
if (bytes is null || bytes.Length <= 1)
{
var last = length - i - 1;
var first = bytes[i];
bytes[i] = bytes[last];
bytes[last] = first;
return bytes;
}
var length = bytes.Length;
var _length = length / 2;
var last = length - 1;
for (int i = 0; i < _length; i++)
{
var current = bytes[i];
bytes[i] = bytes[last - i];
bytes[last - i] = current;
}
return bytes;
+87 -6
View File
@@ -1,7 +1,12 @@
namespace OmniPlus
{
using OmniPlus.Connections;
using OmniPlus.Features;
using System;
using System.Linq;
using System.Text;
using static OmniPlus.Features.Features;
public delegate byte[] MessageHandler(params byte[] bytes);
@@ -9,12 +14,19 @@
public abstract class OmniConnection
{
public abstract bool IsOpen { get; }
protected MessageHandler MessageHandler { get; set; }
public abstract void Close();
public abstract void Open();
public byte[] Send(params byte[] bytes)
{
return this.MessageHandler?.Invoke(bytes);
}
public FactoryID ViewFactoryID()
{
var response = this.MessageHandler.Invoke(VIEW_FACTORY_ID);
@@ -363,11 +375,12 @@
public FeatureResponse Unseal()
{
var request = new byte[18];
request[0] = DEVICE_SPECIFIC;
request[1] = SET_FACTORY_SEAL;
// TODO: Implement factory unseal.
// 1. ((View Seconds Active) >> 8) &0xFFFF
// 2. CRC16_iPERL(View Factory ID),
// 3. ViewCustomerText.Substring(0, 4).Sum(x => x.Count(x => x == 1))
// 4. ViewReadingPreset.Substring(3, 4)
// - The ASCII values in hex for those characters are 0x33 34 35 36 which when reinterpreted as a uint32BE represents
// - the value 859059510 in decimal. That, mod 11 is 1, so VVVV is 0x0001.
// - When the input data is a string, and does not contain the number of characters required for this algorithm,
@@ -377,10 +390,78 @@
// - to send the unseal command.Because of this, if the register responds with Unable to execute,
// - you should recalculate the hash which should last for a longer period if SSSS is large / close to rolling over.
// - Also, if the 7th digit rolls over during unsealing, the hash will not be valid.
// - Current system time is written into manufacturing date/ time if the manufacturing date/ time has not been set
// - Current system time is written into manufacturing date/ time if the manufacturing date / time has not been set
// - when factory seal is set.
var muster = new byte[] { (byte)'F', (byte)'a', (byte)'c', (byte)'t', (byte)'o', (byte)'r', (byte)'y' };
var key = new byte[16];
return new FeatureResponse();
// 1. ((View Seconds Active) >> 8) &0xFFFF
var secondsActive = new Epoch20000101(this.Send(0xFD, 0x3D)).SecondsSince;
var SSSS = BitConverter.GetBytes((secondsActive >> 8) & 0xFFFF);
Buffer.BlockCopy(SSSS, 0, key, 0, 4);
// 2. CRC16_iPERL(View Factory ID),
var factoryID = this.ViewFactoryID().Value;
var factoryIDBytes = Encoding.ASCII.GetBytes(factoryID);
var IIII = factoryIDBytes.CalculateCRC16(0, (ushort)factoryIDBytes.Length);
Buffer.BlockCopy(IIII, 0, key, 4, 2);
// 3. ViewCustomerText.Substring(0, 4).Sum(x => x.Count(x => x == 1))
var customerText = this.ViewCustomerText().Value;
var ctLength = customerText?.Length ?? 0;
var CCCC = new byte[4];
for (int ct = 0; ct < 4; ct++)
{
if (ctLength > ct + 3)
{
CCCC[ct] = (byte)customerText[ct + 3];
}
else
{
CCCC[ct] = muster[ct];
}
}
Buffer.BlockCopy(CCCC, 0, key, 8, 4);
// 4. ViewReadingPreset.Substring(3, 4)
var readings = this
.ViewReadings()
.Value
.Substring(3, 4)
.ToCharArray()
.Reverse()
.Select(x => (byte)x)
.ToArray();
for (int x = readings.Length - 1; x < 4; x++)
{
readings[x] = muster[x];
}
var value = BitConverter.ToUInt32(readings, 0) % 11;
var VVVV = BitConverter.GetBytes(value);
Buffer.BlockCopy(VVVV, 0, key, 12, 4);
Console.WriteLine(BitConverter.ToString(key));
if (key is null || key.Length != 16)
{
return new FactorySeal();
}
//var _key = key.Reverse();
Buffer.BlockCopy(key, 0, request, 2, 16);
var response = this.MessageHandler.Invoke(request);
return new FactorySeal(response);
}
}
}
+58
View File
@@ -0,0 +1,58 @@
namespace OmniPlus
{
using System;
using System.Collections.Concurrent;
public class OmniContext
{
private readonly ConcurrentDictionary<int, OmniMeter> meters;
private readonly OmniDatabase database;
private OmniContext(string connectionString)
{
this.database = new OmniDatabase(connectionString);
this.meters = new ConcurrentDictionary<int, OmniMeter>();
}
public OmniAuftrag Auftrag { get; set; }
public static OmniContext Current { get; private set; }
public static OmniContext GetOrCreateInstance(string connectionString)
{
if (Current is null)
{
Current = new OmniContext(connectionString);
}
return Current;
}
public void LoadAuftrag(string suchnr)
{
this.Auftrag = this.database.LoadAuftrag(suchnr);
}
public void LoadAuftrag(byte size, string type)
{
this.Auftrag = this.database.LoadAuftrag(size, type);
}
public OmniMeter LoadMeter(int nr, string portName)
{
var meter = new OmniMeter(nr, portName);
return this.meters.AddOrUpdate(nr, meter, (_, _1) => meter);
}
internal bool Exists(string meterNr)
{
return this.database.OmniPlus_Exists(meterNr);
}
internal void Add(string meterNr, string meterState)
{
this.database.OmniPlus_Insert(meterNr, meterState);
}
}
}
+265 -192
View File
@@ -1,221 +1,294 @@
namespace OmniPlus
{
using OmniPlus.Features;
using Common.SqlExtensions;
using Common.SqlExtensions.Interfaces;
using OmniPlus.Inspection;
using System;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Collections.Generic;
public class OmniDatabase
{
private readonly string connectionString;
private readonly ISQLConnection sqlConnection;
public OmniDatabase(string omniDatabase)
=> this.connectionString = omniDatabase;
public void AddOrUpdate(int position, SystemParameters parameters)
public OmniDatabase(string connectionString)
{
using (var sqlConnection = new SqlConnection(this.connectionString))
{
sqlConnection.OpenConnection();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $@"
INSERT
INTO [OmniTestStates] ([Position])
VALUES (@{nameof(position)})";
sqlCommand.Parameters.Add(new SqlParameter(nameof(position), position));
sqlCommand.ExecuteNonQuery();
sqlCommand.Parameters.Clear();
}
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $@"
UPDATE [OmniTestStates]
SET [BuildInfo] = @{nameof(parameters.BuildInfo)}
, [ManifacturingTime] = @{nameof(parameters.ManifacturingTime)}
, [RebootsCount] = @{nameof(parameters.RebootsCount)}
, [VersionAndType] = @{nameof(parameters.VersionAndType)}
WHERE [Position] = @{nameof(position)}";
sqlCommand.Parameters.Add(new SqlParameter(nameof(position), position));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.VersionAndType), parameters.VersionAndType.Value));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.RebootsCount), parameters.RebootsCount));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.ManifacturingTime), parameters.ManifacturingTime.DateTime));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.BuildInfo), parameters.BuildInfo.Value));
sqlCommand.ExecuteNonQuery();
sqlCommand.Parameters.Clear();
}
}
this.sqlConnection = SQLConnection.CreateSQLConnection(connectionString);
}
public void AddOrUpdate(int position, ConfigurationParameters parameters)
public OmniAuftrag LoadAuftrag(string suchNr)
{
using (var sqlConnection = new SqlConnection(this.connectionString))
var auftrag = default(OmniAuftrag);
this.sqlConnection
.CreateCommand($@"
SELECT [APP].[FertigungsauftragNr] -- 0
, [APP].[AuftragNr] -- 1
, [APP].[PositionNr] -- 2
, [APP].[Menge] -- 3
, [APP].[KundenNr] -- 4
, [APP].[IdentNr] -- 5
, [IDN].[KurzBez] -- 6
, [IDN].[Typ] -- 7
, [IDN].[Typzusatz] -- 8
, [IDN].[Nennweite] -- 9
, [OT].[TypeId] -- 10
, [OT].[Type] -- 11
, [OT].[Size] -- 12
, [OT].[Range] -- 13
, [OT].[Direction] -- 14
, [OT].[IntPart] -- 15
, [OT].[Fraction] -- 16
, [OT].[CorrectionFactor] -- 17
, [OT].[PulsePerRotation] -- 18
, [OTP].[TestPointId] -- 19
, [OTP].[OmniTypeId] -- 20
, [OTP].[OmniVariant] -- 21
, [OTP].[GalPerMin] -- 22
, [OTP].[Rotations] -- 23
, [OTP].[Duration] -- 24
, [OTP].[MinAccuracy] -- 25
, [OTP].[MaxAccuracy] -- 26
FROM [AlleAuftragPositionen] AS [APP]
JOIN [Identnr] AS [IDN] ON [IDN].[IdentNr] = [APP].[IdentNr]
JOIN [OmniTypes] AS [OT] ON [IDN].[Typzusatz] LIKE '%' + [OT].[Type] + '%'
JOIN [OmniTestPoints] AS [OTP] ON [OTP].[OmniTypeId] = [OT].[TypeId] AND [IDN].[Typzusatz] LIKE '%' + [OTP].[OmniVariant] + '%'
WHERE [APP].[FertigungsauftragNr] = @{nameof(suchNr)}
ORDER BY [OTP].[GalPerMin] DESC")
.SetParameter(nameof(suchNr), suchNr)
.ExecuteReader(reader =>
{
if (auftrag is null)
{
auftrag = new OmniAuftrag
{
FertigungsauftragNr = reader.GetInt(0),
AuftragNr = reader.GetInt(1),
PositionNr = reader.GetSmallint(2),
Menge = reader.GetInt(3),
KundenNr = reader.GetInt(4),
IdentNr = reader.GetInt(5),
KurzBez = reader.GetString(6),
Typ = reader.GetString(7),
Typzusatz = reader.GetString(8),
Nennweite = reader.GetInt(9),
Grosse = reader.GetString(11),
Variante = reader.GetString(21)
};
}
if (auftrag.TypParameter is null)
{
auftrag.TypParameter = new OmniParameter
{
TypeId = reader.GetTinyint(10),
Type = reader.GetString(11),
Size = reader.GetTinyint(12),
Range = reader.GetTinyint(13),
Direction = reader.GetTinyint(14),
IntPart = reader.GetTinyint(15),
Fraction = reader.GetInt(16),
Factor = reader.GetSmallint(17),
PulsePerRotation = reader.GetTinyint(18)
};
}
if (auftrag.Pruefpunkte is null)
{
auftrag.Pruefpunkte = new HashSet<OmniPruefpunkt>();
}
auftrag.Pruefpunkte.Add(new OmniPruefpunkt
{
TestPointId = reader.GetSmallint(19),
OmniTypeId = reader.GetTinyint(20),
OmniVariant = reader.GetString(21),
GalPerMin = reader.GetValue<double>(22),
Rotations = reader.GetSmallint(23),
Duration = reader.GetSmallint(24),
MinAccuracy = reader.GetValue<double>(25),
MaxAccuracy = reader.GetValue<double>(26),
});
});
return auftrag ?? new OmniAuftrag
{
sqlConnection.OpenConnection();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $@"
INSERT
INTO [OmniTestStates] ([Position])
VALUES (@{nameof(position)})";
sqlCommand.Parameters.Add(new SqlParameter(nameof(position), position));
sqlCommand.ExecuteNonQuery();
sqlCommand.Parameters.Clear();
}
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $@"
UPDATE [OmniTestStates]
SET [ProgrammableID] = @{nameof(parameters.ProgrammableID)}
, [FactoryID] = @{nameof(parameters.FactoryID)}
, [ReadingDigitsCount] = @{nameof(parameters.ReadingDigits.Count)}
, [ReadingDigitsOffsest] = @{nameof(parameters.ReadingDigits.Offset)}
, [Readings] = @{nameof(parameters.Readings)}
, [OptionalUniDirFields] = @{nameof(parameters.OptionalUniDirFields)}
, [AlarmPersitenceDays] = @{nameof(parameters.AlarmPersistenceDays)}
, [DataLogIntervalMins] = @{nameof(parameters.DataLogIntervalMins)}
WHERE [Position] = @{nameof(position)}";
sqlCommand.Parameters.Add(new SqlParameter(nameof(position), position));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.ProgrammableID), parameters.ProgrammableID.Value));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.FactoryID), parameters.FactoryID.Value));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.ReadingDigits.Count), parameters.ReadingDigits.Count));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.ReadingDigits.Offset), parameters.ReadingDigits.Offset));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.Readings), parameters.Readings.Value));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.OptionalUniDirFields), parameters.OptionalUniDirFields.Value));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.AlarmPersistenceDays), parameters.AlarmPersistenceDays));
sqlCommand.Parameters.Add(new SqlParameter(nameof(parameters.DataLogIntervalMins), BitConverter.GetBytes(parameters.DataLogIntervalMins)
.Reverse()
.ToArray()));
try
{
sqlCommand.ExecuteNonQuery();
sqlCommand.Parameters.Clear();
}
catch (Exception e)
{
}
}
}
TypParameter = new OmniParameter(),
Pruefpunkte = new List<OmniPruefpunkt>()
};
}
public void LoadOmniDefaults(byte size, string variant, OmniPlusType omniType)
public OmniAuftrag LoadAuftrag(byte size, string variant)
{
omniType?.TestPoints?.Clear();
var auftrag = default(OmniAuftrag);
using (var sqlConnection = new SqlConnection(this.connectionString))
this.sqlConnection
.CreateCommand($@"
SELECT [OT].[TypeId] -- 0
, [OT].[Type] -- 1
, [OT].[Size] -- 2
, [OT].[Range] -- 3
, [OT].[Direction] -- 4
, [OT].[IntPart] -- 5
, [OT].[Fraction] -- 6
, [OT].[CorrectionFactor] -- 7
, [OT].[PulsePerRotation] -- 8
, [OTP].[TestPointId] -- 9
, [OTP].[OmniTypeId] -- 10
, [OTP].[OmniVariant] -- 11
, [OTP].[GalPerMin] -- 12
, [OTP].[Rotations] -- 13
, [OTP].[Duration] -- 14
, [OTP].[MinAccuracy] -- 15
, [OTP].[MaxAccuracy] -- 16
FROM [OmniTypes] AS [OT]
JOIN [OmniTestPoints] AS [OTP]
ON [OTP].[OmniTypeId] = [OT].[TypeId]
WHERE [OT].[Size] = @{nameof(size)}
AND [OTP].[OmniVariant] = @{nameof(variant)}
ORDER BY [OTP].[GalPerMin] DESC")
.SetParameter(nameof(size), size)
.SetParameter(nameof(variant), variant)
.ExecuteReader(reader =>
{
if (auftrag is null)
{
auftrag = new OmniAuftrag
{
Grosse = reader.GetString(1),
Variante = reader.GetString(11)
};
}
if (auftrag.TypParameter is null)
{
auftrag.TypParameter = new OmniParameter
{
TypeId = reader.GetTinyint(0),
Type = reader.GetString(1),
Size = reader.GetTinyint(2),
Range = reader.GetTinyint(3),
Direction = reader.GetTinyint(4),
IntPart = reader.GetTinyint(5),
Fraction = reader.GetInt(6),
Factor = reader.GetSmallint(7),
PulsePerRotation = reader.GetTinyint(8)
};
}
if (auftrag.Pruefpunkte is null)
{
auftrag.Pruefpunkte = new HashSet<OmniPruefpunkt>();
}
auftrag.Pruefpunkte.Add(new OmniPruefpunkt
{
TestPointId = reader.GetSmallint(9),
OmniTypeId = reader.GetTinyint(10),
OmniVariant = reader.GetString(11),
GalPerMin = reader.GetValue<double>(12),
Rotations = reader.GetSmallint(13),
Duration = reader.GetSmallint(14),
MinAccuracy = reader.GetValue<double>(15),
MaxAccuracy = reader.GetValue<double>(16),
});
});
return auftrag ?? new OmniAuftrag
{
sqlConnection.OpenConnection();
TypParameter = new OmniParameter(),
Pruefpunkte = new List<OmniPruefpunkt>()
};
}
var field = 0;
public bool OmniPlus_Exists(string meterNr)
{
return this.sqlConnection
.CreateCommand($@"SELECT COUNT(1) FROM [OmniPlus] WHERE [MeterNr] = @{nameof(meterNr)}")
.SetParameter(nameof(meterNr), meterNr)
.ExecuteScalar(x => x.GetInt()) > 0;
}
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $@"
SELECT [Id]
, [Size]
, [Range]
, [Direction]
, [IntPart]
, [Fraction]
, [PulsePerRotation]
, [CorrectionFactor]
FROM [OmniTestTypes]
WHERE [Size] = @{nameof(size)}";
sqlCommand.Parameters.Add(new SqlParameter(nameof(size), size));
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
if (sqlDataReader.Read())
{
field = 0;
omniType.OmniId = sqlDataReader.GetValue<byte>(field++);
omniType.Size = sqlDataReader.GetValue<byte>(field++);
omniType.Range = sqlDataReader.GetValue<byte>(field++);
omniType.Direction = sqlDataReader.GetValue<byte>(field++);
omniType.IntPart = sqlDataReader.GetValue<byte>(field++);
omniType.Fraction = (ushort)sqlDataReader.GetValue<int>(field++);
omniType.PulsePerRotation = sqlDataReader.GetValue<byte>(field++);
omniType.CorrectionFactor = sqlDataReader.GetValue<short>(field++);
}
}
}
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $@"
SELECT [GalPerMin]
, [Rotations]
, [Duration]
, [MinDiff]
, [MaxDiff]
FROM [OmniTestPoints]
WHERE [OmniTypeId] = @{nameof(omniType.OmniId)}
AND [OmniVariant] = @{nameof(variant)}
AND [MinDiff] IS NOT NULL
ORDER BY [GalPerMin] ASC";
sqlCommand.Parameters.Add(new SqlParameter(nameof(omniType.OmniId), omniType.OmniId));
sqlCommand.Parameters.Add(new SqlParameter(nameof(variant), variant));
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
var milliliterPerRotation = omniType.MilliliterPerRotation();
while (sqlDataReader.Read())
{
field = 0;
omniType.TestPoints.Add(new OmniPlusTestPoint
{
MLR = milliliterPerRotation,
GPM = sqlDataReader.GetValue<double>(field++),
Rotations = (ushort)sqlDataReader.GetValue<short>(field++),
Duration = (ushort)sqlDataReader.GetValue<short>(field++),
MinDiff = sqlDataReader.GetValue<double>(field++),
MaxDiff = sqlDataReader.GetValue<double>(field++),
});
}
}
}
}
public int OmniPlus_Insert(string meterNr, string meterState)
{
return this.sqlConnection
.CreateCommand($@"INSERT INTO [OmniPlus] VALUES (@{nameof(meterNr)}, @{nameof(meterState)})")
.SetParameter(nameof(meterNr), meterNr)
.SetParameter(nameof(meterState), meterState)
.ExecuteNonQuery();
}
}
internal static class SqlConnectionExtensions
public class OmniAuftrag
{
public static void OpenConnection(this SqlConnection connection)
{
connection.FireInfoMessageEventOnUserErrors = true;
connection.InfoMessage += Connection_InfoMessage;
connection.Open();
}
public int FertigungsauftragNr { get; internal set; }
public static TValue GetValue<TValue>(this SqlDataReader reader, int index)
{
if (reader.FieldCount > index && !reader.IsDBNull(index) && reader.GetValue(index) is TValue value)
{
return value;
}
public int AuftragNr { get; internal set; }
return default(TValue);
}
public short PositionNr { get; internal set; }
private static void Connection_InfoMessage(object sender, SqlInfoMessageEventArgs args)
{
try
{
File.AppendAllText(".\\sql_connection.log", args.Message);
}
catch { }
}
public int Menge { get; internal set; }
public int KundenNr { get; internal set; }
public int IdentNr { get; internal set; }
public string KurzBez { get; internal set; }
public string Typ { get; internal set; }
public string Grosse { get; internal set; }
public string Variante { get; internal set; }
public string Typzusatz { get; internal set; }
public int Nennweite { get; internal set; }
public OmniParameter TypParameter { get; internal set; }
public ICollection<OmniPruefpunkt> Pruefpunkte { get; internal set; }
}
public class OmniParameter
{
public byte TypeId { get; internal set; }
public string Type { get; internal set; }
public byte Size { get; internal set; }
public byte Range { get; internal set; }
public byte Direction { get; internal set; }
public byte IntPart { get; internal set; }
public int Fraction { get; internal set; }
public short Factor { get; internal set; }
public byte PulsePerRotation { get; internal set; }
}
public class OmniPruefpunkt
{
public short TestPointId { get; internal set; }
public byte OmniTypeId { get; internal set; }
public double MaxAccuracy { get; internal set; }
public short Duration { get; internal set; }
public string OmniVariant { get; internal set; }
public double GalPerMin { get; internal set; }
public short Rotations { get; internal set; }
public double MinAccuracy { get; internal set; }
public double FlowM3H => this.GalPerMin.GPM2M3H();
}
}
-30
View File
@@ -1,30 +0,0 @@
namespace OmniPlus
{
using System;
using ExchangeHub;
public class OmniExchange
{
private readonly ExchangeConnection connection;
public OmniExchange()
{
this.connection = new ExchangeConnection();
}
public void Connect(string url)
{
this.connection.Connect(url);
}
public void Disconnect()
{
this.connection.Disconnect();
}
public void StopFlow()
{
throw new NotImplementedException();
}
}
}
@@ -28,6 +28,11 @@
this.MessageHandler = this.stream.Send;
}
public override bool IsOpen
{
get => this.stream.IsOpen;
}
public override void Close()
{
this.stream.Close();
-38
View File
@@ -1,38 +0,0 @@
namespace OmniPlus
{
using System.Collections.Generic;
public sealed class OmniIrdaEOL
{
private readonly IDictionary<int, OmniConnection> connections;
private readonly IDictionary<int, OmniMeter> meters;
private readonly OmniExchange exchangeHub;
private readonly OmniDatabase database;
public OmniIrdaEOL(string connectionString)
{
this.connections = new Dictionary<int, OmniConnection>();
this.meters = new Dictionary<int, OmniMeter>();
this.exchangeHub = new OmniExchange();
this.database = new OmniDatabase(connectionString);
}
public void AddConnection(string portName)
{
var nr = this.connections.Count + 1;
this.connections[nr] = new OmniIrdaConnection(portName);
this.meters[nr] = new OmniMeter();
}
public void Clear()
{
foreach (var connection in this.connections.Values)
{
connection.Close();
}
this.connections.Clear();
this.meters.Clear();
}
}
}
+120 -11
View File
@@ -2,32 +2,141 @@
{
using OmniPlus.Features.Enums;
using System;
using System.Collections.Generic;
using System.Text;
public class OmniMeter
{
const string NA = "n/a";
private readonly int slotnr;
private readonly string portName;
private OmniConnection connection;
public void ConnectIrda(string portName)
public OmniMeter(int nr, string portName)
{
if (this.connection != null)
{
this.connection.Close();
}
this.connection = new OmniIrdaConnection(portName);
this.connection.Open();
this.slotnr = nr;
this.portName = portName;
}
public void ConnectUniPro(string portName)
public string MeterNr { get; private set; }
public int? SerialNr { get; private set; }
public void ConnectIrda()
{
if (this.connection is null)
{
this.connection = new OmniIrdaConnection(this.portName);
}
if (!this.connection.IsOpen)
{
this.connection.Close();
this.connection.Open();
}
}
public void Dispose()
{
if (this.connection != null)
{
this.connection.Close();
}
this.connection = new OmniUniProConnection(portName);
this.connection.Open();
this.connection = null;
}
public void Initialize()
{
this.ConnectIrda();
this.MeterNr = NA;
this.SerialNr = default(int?);
var buildInfo = this.connection.ViewBuildInformation();
if (buildInfo.Status != Status.Completed)
{
return;
}
this.MeterNr = buildInfo.Value;
this.SerialNr = OmniContext.Current.Auftrag.IdentNr;
if (string.IsNullOrWhiteSpace(this.MeterNr))
{
return;
}
else if (OmniContext.Current.Exists(this.MeterNr))
{
return;
}
var commands = new List<byte[]>
{
new byte[] { 0x01 },
new byte[] { 0x03 },
new byte[] { 0x05 },
new byte[] { 0x07 },
new byte[] { 0x09 },
new byte[] { 0x0B },
new byte[] { 0x0D },
new byte[] { 0x0F },
new byte[] { 0x11 },
new byte[] { 0x13 },
new byte[] { 0x15 },
new byte[] { 0x17 },
new byte[] { 0x1F },
new byte[] { 0x21 },
new byte[] { 0x25 },
new byte[] { 0x27 },
new byte[] { 0x29 },
new byte[] { 0x2B },
new byte[] { 0xFD, 0x02 },
new byte[] { 0xFD, 0x05 },
new byte[] { 0xFD, 0x06 },
new byte[] { 0xFD, 0x08 },
new byte[] { 0xFD, 0x0A },
new byte[] { 0xFD, 0x0E },
new byte[] { 0xFD, 0x10 },
new byte[] { 0xFD, 0x12 },
new byte[] { 0xFD, 0x14 },
new byte[] { 0xFD, 0x22 },
new byte[] { 0xFD, 0x24 },
new byte[] { 0xFD, 0x26 },
new byte[] { 0xFD, 0x28 },
new byte[] { 0xFD, 0x39 },
new byte[] { 0xFD, 0x3D },
new byte[] { 0xFD, 0x55 },
new byte[] { 0xFD, 0x63 },
new byte[] { 0xFD, 0x7B },
new byte[] { 0xFD, 0x7E, 0x00 },
new byte[] { 0xFD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
new byte[] { 0xFD, 0x8B },
new byte[] { 0xFD, 0xA9 },
new byte[] { 0xFD, 0xAA },
new byte[] { 0xFD, 0xAC },
new byte[] { 0xFD, 0xB7 },
new byte[] { 0xFD, 0xBC },
new byte[] { 0xFD, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
new byte[] { 0xFD, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
new byte[] { 0xFD, 0xC4, 0x00 },
new byte[] { 0xFD, 0xC6 },
new byte[] { 0xFD, 0xC7 }
};
var meterState = new StringBuilder();
foreach (var cmd in commands)
{
var response = this.connection.Send(cmd);
var entry = $"{BitConverter.ToString(cmd)}:{BitConverter.ToString(response)};";
meterState.Append(entry);
}
OmniContext.Current.Add(this.MeterNr, meterState.ToString());
}
}
}
+6 -2
View File
@@ -37,8 +37,13 @@
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SqlExtensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\SqlExtensions\SqlExtensions.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -96,8 +101,7 @@
<Compile Include="Features\VersionAndType.cs" />
<Compile Include="Inspection\OmniPlusFormulas.cs" />
<Compile Include="OmniConnection.cs" />
<Compile Include="OmniExchange.cs" />
<Compile Include="OmniIrdaEOL.cs" />
<Compile Include="OmniContext.cs" />
<Compile Include="OmniIrdaConnection.cs" />
<Compile Include="OmniMeter.cs" />
<Compile Include="OmniDatabase.cs" />
+120 -68
View File
@@ -1,11 +1,11 @@
USE [AuftragKopie];
IF OBJECT_ID(N'OmniTestStates') IS NOT NULL DROP TABLE [OmniTestStates];
IF OBJECT_ID(N'OmniTestPoints') IS NOT NULL DROP TABLE [OmniTestPoints];
IF OBJECT_ID(N'OmniTestTypes') IS NOT NULL DROP TABLE [OmniTestTypes];
IF OBJECT_ID(N'OmniTypes') IS NOT NULL DROP TABLE [OmniTypes];
IF OBJECT_ID(N'OmniPlus') IS NOT NULL DROP TABLE [OmniPlus];
CREATE TABLE [OmniTestTypes] (
[Id] TINYINT NOT NULL IDENTITY(1, 1),
CREATE TABLE [OmniTypes] (
[TypeId] TINYINT NOT NULL IDENTITY(1, 1),
[Type] VARCHAR(5) NOT NULL,
[Size] TINYINT NOT NULL,
[Range] TINYINT NOT NULL,
@@ -14,84 +14,136 @@ CREATE TABLE [OmniTestTypes] (
[Fraction] INT NOT NULL,
[CorrectionFactor] SMALLINT NOT NULL,
[PulsePerRotation] TINYINT NOT NULL,
CONSTRAINT [PK_OmniTestTypes_Id] PRIMARY KEY ([Id])
CONSTRAINT [PK_OmniTestTypes_TypeId] PRIMARY KEY ([TypeId])
);
INSERT INTO [OmniTestTypes]
INSERT INTO [OmniTypes]
([Type], [Size], [Range], [Direction], [IntPart], [Fraction], [CorrectionFactor], [PulsePerRotation])
VALUES ( '1½"', 0x05, 0x00, 0x00, 0x00, 34017, 100, 8)
, ( '2"', 0x06, 0x00, 0x00, 0x00, 34017, 100, 8)
, ( '3"', 0x07, 0x01, 0x00, 0x01, 50827, 100, 8)
, ( '4"', 0x08, 0x01, 0x00, 0x01, 50827, 100, 8)
, ( '6"', 0x09, 0x02, 0x00, 0x06, 16754, 100, 8)
, ( '8"', 0x0A, 0x03, 0x80, 0x01, 36814, 1000, 8)
, ( '10"', 0x0B, 0x04, 0x80, 0x02, 21667, 1000, 8);
, ( '2"', 0x06, 0x00, 0x00, 0x00, 34017, 100, 8);
CREATE TABLE [OmniTestPoints] (
[Id] SMALLINT NOT NULL IDENTITY(1, 1),
[TestPointId] SMALLINT NOT NULL IDENTITY(1, 1),
[OmniTypeId] TINYINT NOT NULL,
[OmniVariant] CHAR(2) NULL,
[GalPerMin] FLOAT NOT NULL,
[Rotations] SMALLINT NOT NULL,
[Duration] SMALLINT NOT NULL,
[MinDiff] FLOAT NULL,
[MaxDiff] FLOAT NULL,
CONSTRAINT [PK_OmniTestPoints_Id] PRIMARY KEY ([Id]),
CONSTRAINT [FK_OmniTestPoints_OmniTypeId_OmniPlus_Id] FOREIGN KEY ([OmniTypeId]) REFERENCES [OmniTestTypes]([Id]),
[MinAccuracy] FLOAT NULL,
[MaxAccuracy] FLOAT NULL,
CONSTRAINT [PK_OmniTestPoints_TestPointId] PRIMARY KEY ([TestPointId]),
CONSTRAINT [FK_OmniTestPoints_OmniTypes_OmniTypeId] FOREIGN KEY ([OmniTypeId]) REFERENCES [OmniTypes]([TypeId]),
CONSTRAINT [CHK_OmniTestPoints_Rotations] CHECK ([Rotations] BETWEEN 1 AND 5000),
CONSTRAINT [CHK_OmniTestPoints_Duration] CHECK ([Duration] BETWEEN 1 AND 3600)
);
INSERT INTO [OmniTestPoints]
([OmniTypeId], [OmniVariant], [GalPerMin], [Rotations], [Duration], [MinDiff], [MaxDiff])
------------------------------------------------------------------------------------------
VALUES ( 1, 'C2', 160.00, 700, 35, 98.5, 101.5)
, ( 1, 'C2', 1.00, 4, 32, 98.5, 101.5)
, ( 1, 'C2', 0.25, 4, 127, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 1, 'F2', 160.00, 700, 35, 98.5, 101.5)
, ( 1, 'F2', 1.00, 4, 32, 98.5, 101.5)
, ( 1, 'F2', 0.25, 4, 127, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 1, 'R2', 150.00, 600, 32, 98.5, 101.5)
, ( 1, 'R2', 2.00, 8, 32, 98.5, 101.5)
, ( 1, 'R2', 0.75, 4, 43, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 1, 'T2', 160.00, 700, 35, 98.5, 101.5)
, ( 1, 'T2', 1.25, 6, 38, 98.5, 101.5)
, ( 1, 'T2', 0.75, 4, 43, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 2, 'C2', 160.00, 800, 40, 98.5, 101.5)
, ( 2, 'C2', 1.00, 4, 32, 98.5, 101.5)
, ( 2, 'C2', 0.25, 4, 127, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 2, 'F2', 160.00, 800, 40, 98.5, 101.5)
, ( 2, 'F2', 1.00, 4, 32, 98.5, 101.5)
, ( 2, 'F2', 0.25, 4, 127, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 2, 'R2', 200.00, 1000, 40, 98.5, 101.5)
, ( 2, 'R2', 2.50, 10, 32, 98.5, 101.5)
, ( 2, 'R2', 1.00, 4, 32, 95.0, 101.5)
------------------------------------------------------------------------------------------
, ( 2, 'T2', 200.00, 1000, 40, 98.5, 101.5)
, ( 2, 'T2', 1.50, 8, 43, 98.5, 101.5)
, ( 2, 'T2', 1.00, 4, 32, 95.0, 101.5);
([OmniTypeId], [OmniVariant], [GalPerMin], [Rotations], [Duration], [MinAccuracy], [MaxAccuracy])
VALUES ( 1, 'C2', 160.00, 700, 35, 98.5, 101.5)
, ( 1, 'C2', 1.00, 4, 32, 98.5, 101.5)
, ( 1, 'C2', 0.25, 4, 127, 95.0, 101.5)
--------------------------------------------------------------------------------------------------
, ( 1, 'R2', 150.00, 600, 32, 98.5, 101.5)
, ( 1, 'R2', 2.00, 8, 32, 98.5, 101.5)
, ( 1, 'R2', 0.75, 4, 43, 95.0, 101.5)
--------------------------------------------------------------------------------------------------
, ( 1, 'T2', 160.00, 700, 35, 98.5, 101.5)
, ( 1, 'T2', 1.25, 6, 38, 98.5, 101.5)
, ( 1, 'T2', 0.75, 4, 43, 95.0, 101.5)
--------------------------------------------------------------------------------------------------
, ( 2, 'C2', 160.00, 800, 40, 98.5, 101.5)
, ( 2, 'C2', 1.00, 4, 32, 98.5, 101.5)
, ( 2, 'C2', 0.25, 4, 127, 95.0, 101.5)
--------------------------------------------------------------------------------------------------
, ( 2, 'R2', 200.00, 1000, 40, 98.5, 101.5)
, ( 2, 'R2', 2.50, 10, 32, 98.5, 101.5)
, ( 2, 'R2', 1.00, 4, 32, 95.0, 101.5)
--------------------------------------------------------------------------------------------------
, ( 2, 'T2', 200.00, 1000, 40, 98.5, 101.5)
, ( 2, 'T2', 1.50, 8, 43, 98.5, 101.5)
, ( 2, 'T2', 1.00, 4, 32, 95.0, 101.5);
CREATE TABLE [OmniTestStates] (
[Position] INT NOT NULL,
[BuildInfo] VARCHAR(50) NULL,
[ManifacturingTime] DATETIME NULL,
[RebootsCount] TINYINT NULL,
[VersionAndType] VARCHAR(50) NULL,
[ProgrammableID] VARCHAR(50) NULL,
[FactoryID] VARCHAR(50) NULL,
[ReadingDigitsCount] BINARY(1) NULL,
[ReadingDigitsOffsest] BINARY(1) NULL,
[Readings] VARCHAR(50) NULL,
[OptionalUniDirFields] VARCHAR(50) NULL,
[AlarmPersitenceDays] BINARY(1) NULL,
[DataLogIntervalMins] BINARY(2) NULL,
[DeviceID] VARCHAR(50) NULL,
CONSTRAINT [PK_OmniTestStates_Position] PRIMARY KEY ([Position]),
CONSTRAINT [CHK_OmniTestStates_Position] CHECK ([Position] BETWEEN 1 AND 10)
);
CREATE TABLE [OmniPlus] (
[MeterNr] VARCHAR(32) NOT NULL PRIMARY KEY,
[MeterState] VARCHAR(MAX) NOT NULL
);
------USE [PushExt]
------GO
------IF OBJECT_ID(N'OmniExport') IS NOT NULL DROP TABLE [OmniExport]
------GO
------CREATE TABLE [OmniExport] (
------ [BuildID] INT NOT NULL IDENTITY(1,1) NOT FOR REPLICATION,
------ [OrderNumber] INT NOT NULL,
------ [LineNumber] INT NOT NULL,
------ [ManufacturingSN] VARCHAR(30) NOT NULL,
------ [CustomerSN] VARCHAR(30) NOT NULL,
------ [MeterSN] VARCHAR(30) NOT NULL,
------ [PCBAID] VARCHAR(30) NOT NULL,
------ [EhatPCBAID] VARCHAR(30) NOT NULL,
------ [ManufactureDate] DATETIME NOT NULL,
------ [ShipDate] DATETIME NOT NULL,
------ [Flow1] DECIMAL(4, 1) NOT NULL,
------ [Flow2] DECIMAL(4, 1) NOT NULL,
------ [Flow3] DECIMAL(4, 1) NOT NULL,
------ [Flow4] DECIMAL(4, 1) NOT NULL,
------ [Flow5] DECIMAL(4, 1) NOT NULL,
------ [Flow6] DECIMAL(4, 1) NOT NULL,
------ [PartNumber] VARCHAR(50) NOT NULL
------)
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [PK_OmniExport_BuildID] PRIMARY KEY ([BuildID])
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [DF_OmniExport_Flow1] DEFAULT (0.0) FOR [Flow1]
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [DF_OmniExport_Flow2] DEFAULT (0.1) FOR [Flow2]
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [DF_OmniExport_Flow3] DEFAULT (0.2) FOR [Flow3]
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [DF_OmniExport_Flow4] DEFAULT (0.3) FOR [Flow4]
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [DF_OmniExport_Flow5] DEFAULT (0.4) FOR [Flow5]
------GO
------ALTER TABLE [OmniExport] ADD CONSTRAINT [DF_OmniExport_Flow6] DEFAULT (0.5) FOR [Flow6]
------GO
@@ -28,6 +28,11 @@
this.MessageHandler = this.stream.Send;
}
public override bool IsOpen
{
get => this.stream.IsOpen;
}
public override void Close()
{
this.stream.Close();
@@ -0,0 +1,22 @@
namespace Common.SqlExtensions.Interfaces
{
using System;
using System.Collections.Generic;
public interface ISQLCommand
{
int ExecuteNonQuery();
IEnumerable<T> ExecuteReader<T>(Func<ISQLReader, T> expression);
void ExecuteReader(Action<ISQLReader> expression);
T ExecuteScalar<T>(Func<ISQLReader, T> expression);
T FirstOrDefault<T>(Func<ISQLReader, T> expression);
ISQLCommand SetParameter(string name, object value);
ISQLCommand SetParameters(IEnumerable<KeyValuePair<string, object>> parameters);
}
}
@@ -0,0 +1,15 @@
namespace Common.SqlExtensions.Interfaces
{
/// <summary>
/// <see cref="ISQLConnection"/> simply exposes the <see cref="ISQLConnection.CreateCommand(string)"/> method.
/// </summary>
public interface ISQLConnection
{
/// <summary>
/// Creates a command with given command text.
/// </summary>
/// <param name="commandText"><see cref="System.String"/> - SQL query string.</param>
/// <returns></returns>
ISQLCommand CreateCommand(string commandText);
}
}
@@ -0,0 +1,25 @@
namespace Common.SqlExtensions.Interfaces
{
using System;
public interface ISQLReader
{
bool GetBool(int index = -1);
DateTime GetDate(int index = -1);
int GetInt(int index = -1);
long GetLong(int index = -1);
short GetSmallint(int index = -1);
string GetString(int index = -1);
byte GetTinyint(int index = -1);
T GetValue<T>(int index = -1);
object GetValue(string column);
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SqlExtensions")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SqlExtensions")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b8523894-2c40-4ff0-a399-b7a91fae45ea")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,83 @@
namespace Common.SqlExtensions
{
using Common.SqlExtensions.Interfaces;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
public class SQLCommand : ISQLCommand
{
private readonly SQLConnection sqlConnection;
private readonly IDictionary<string, SqlParameter> parameters;
public SQLCommand(SQLConnection sqlConnection, string commandText)
{
this.sqlConnection = sqlConnection.EnsureNotNull(nameof(sqlConnection));
this.CommandText = commandText.EnsureNotNullOrWhiteSpace(nameof(commandText));
this.parameters = new Dictionary<string, SqlParameter>();
}
internal string CommandText { get; }
internal SqlParameter[] Parameters
=> this.parameters.Values.ToArray();
public int ExecuteNonQuery()
=> this.sqlConnection.ExecuteNonQuery(this);
public IEnumerable<T> ExecuteReader<T>(Func<ISQLReader, T> expression)
{
foreach (var result in this.sqlConnection.ExecuteReader(this, expression))
{
yield return result;
}
}
public void ExecuteReader(Action<ISQLReader> expression)
{
expression.ThrowIfNull(nameof(expression));
this.sqlConnection.ExecuteReader(this, reader =>
{
while (reader.Read())
{
expression(reader);
}
});
}
public T ExecuteScalar<T>(Func<ISQLReader, T> expression)
=> this.sqlConnection.ExecuteScalar(this, expression);
public T FirstOrDefault<T>(Func<ISQLReader, T> expression)
=> this.sqlConnection.FirstOrDefault(this, expression);
public ISQLCommand SetParameter(string name, object value)
{
name.ThrowIfNullOrWhiteSpace(nameof(name));
if (value is null)
{
value = DBNull.Value;
}
var parameter = new SqlParameter(name, value);
this.parameters[name] = parameter;
return this;
}
public ISQLCommand SetParameters(IEnumerable<KeyValuePair<string, object>> parameters)
{
foreach (var kvp in parameters)
{
this.SetParameter(kvp.Key, kvp.Value);
}
return this;
}
}
}
@@ -0,0 +1,218 @@
namespace Common.SqlExtensions
{
using Common.SqlExtensions.Interfaces;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
/// <summary>
/// A wrapper class around the <see cref="System.Data.SqlClient"/>.
/// Exposes <see cref="System.Data.SqlClient.SqlConnection"/>, <see cref="System.Data.SqlClient.SqlCommand"/> and <see cref="System.Data.SqlClient.SqlDataReader"/> classes
/// in a fluent manner, all exposed methods can be chained in a single C# query.
/// </summary>
public class SQLConnection : ISQLConnection
{
private readonly string connectionString;
private readonly Action<string> errorCallback;
/// <summary>
/// When <paramref name="connectionString"/> is null, white space or is not a valid connection string exception is thrown.
/// </summary>
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
private SQLConnection(string connectionString)
{
// connectionString.ThrowIfNullOrWhiteSpace(nameof(connectionString));
var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
this.connectionString = connectionStringBuilder.ToString();
}
/// <summary>
/// When <paramref name="connectionString"/> is null, white space or is not a valid connection string exception is thrown.
/// Additionaly accepts <see cref="System.Action{System.String}"/> for error handling.
/// Whenever the sql query throws error on execution, this will be passesd within the callback.
/// </summary>
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
/// <param name="errorCallback"><see cref="System.Action{System.String}"/> - error handler for SQL execution errors.</param>
private SQLConnection(string connectionString, Action<string> errorCallback = null)
: this(connectionString)
=> this.errorCallback = errorCallback;
/// <summary>
/// Creates a <see cref="Common.SqlExtensions.ISQLCommand"/> wrapper that accepts a SQL query string.
/// </summary>
/// <param name="commandText"><see cref="System.String"/> - SQL query string</param>
/// <returns><see cref="Common.SqlExtensions.ISQLCommand"/> - that exposes basic functionalities from the <see cref="System.Data.SqlClient.SqlCommand" />.</returns>
public ISQLCommand CreateCommand(string commandText)
=> new SQLCommand(this, commandText);
/// <summary>
/// Static method that creates a <see cref="Common.SqlExtensions.ISQLConnection"/> client with given connection string.
/// </summary>
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
/// <returns><see cref="Common.SqlExtensions.ISQLConnection"/></returns>
public static ISQLConnection CreateSQLConnection(string connectionString)
=> new SQLConnection(connectionString);
/// <summary>
/// Static method that creates a <see cref="Common.SqlExtensions.ISQLConnection"/> client with given connection string and error callback that receives all error messages.
/// </summary>
/// <param name="connectionString"><see cref="System.String"/> - SQL connection string.</param>
/// <param name="errorCallback"><see cref="System.Action{System.String}"/> - error handler for SQL execution errors.</param>
/// <returns><see cref="Common.SqlExtensions.ISQLConnection"/></returns>
public static ISQLConnection CreateSQLConnection(string connectionString, Action<string> errorCallback = null)
=> new SQLConnection(connectionString, errorCallback);
/// <summary>
/// Internal method called from <see cref="Common.SqlExtensions.ISQLCommand"/>.
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs INSERT, UPDATE, DELETE queries and returns the number of rows affected.
/// </summary>
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
/// <returns><see cref="System.Int32"/> - the number of rows affected.</returns>
internal int ExecuteNonQuery(SQLCommand command)
{
command.ThrowIfNull(nameof(command));
var rowsAffected = 0;
using (var sqlConnection = new SqlConnection(this.connectionString))
{
sqlConnection.OpenWithErrorHandling(this.errorCallback);
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = command.CommandText;
sqlCommand.Parameters.AddRange(command.Parameters);
rowsAffected = sqlCommand.ExecuteNonQuery();
sqlCommand.Parameters.Clear();
}
}
return rowsAffected;
}
/// <summary>
/// Internal method called from <see cref="Common.SqlExtensions.ISQLCommand"/>.
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs SELECT queries and returns a enumerable of the results readed.
/// </summary>
/// <typeparam name="T">Is the type that returns the <see cref="System.Func{IFluentSQLReader, T} expression"/></typeparam>
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
/// <param name="expression">Expression that reads specified data from the <see cref="Common.SqlExtensions.ISQLReader"/>.</param>
/// <returns><see cref="System.Collections.Generic.IEnumerable{T}"/></returns>
internal IEnumerable<T> ExecuteReader<T>(SQLCommand command, Func<ISQLReader, T> expression)
{
command.ThrowIfNull(nameof(command));
expression.ThrowIfNull(nameof(expression));
using (var sqlConnection = new SqlConnection(this.connectionString))
{
sqlConnection.OpenWithErrorHandling(this.errorCallback);
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = command.CommandText;
sqlCommand.Parameters.AddRange(command.Parameters);
using (SQLReader sqlReader = sqlCommand.ExecuteReader())
{
sqlCommand.Parameters.Clear();
while (sqlReader.Read())
{
yield return expression(sqlReader);
}
}
}
}
}
/// <summary>
/// Internal method called from <see cref="Common.SqlExtensions.ISQLCommand"/>.
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs SELECT queries and returns a enumerable of the results readed.
/// </summary>
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
/// <param name="expression">Expression that reads specified data from the <see cref="Common.SqlExtensions.ISQLReader"/>.</param>
internal void ExecuteReader(SQLCommand command, Action<SQLReader> expression)
{
command.ThrowIfNull(nameof(command));
expression.ThrowIfNull(nameof(expression));
using (var sqlConnection = new SqlConnection(this.connectionString))
{
sqlConnection.OpenWithErrorHandling(this.errorCallback);
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = command.CommandText;
sqlCommand.Parameters.AddRange(command.Parameters);
using (SQLReader sqlReader = sqlCommand.ExecuteReader())
{
sqlCommand.Parameters.Clear();
expression(sqlReader);
}
}
}
}
/// <summary>
/// Internal method called from <see cref="Common.SqlExtensions.ISQLCommand"/>.
/// Like in a <see cref="System.Data.SqlClient.SqlCommand"/> performs SELECT, READ, UPDATE, DELETE queries and returns first column from the first row from the result.
/// </summary>
/// <typeparam name="T">From user specified.</typeparam>
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
/// <param name="expression">Expression that reads specified data from the <see cref="Common.SqlExtensions.ISQLReader"/>.</param>
/// <returns><see cref="System.Collections.Generic.IEnumerable{T}"/></returns>
internal T ExecuteScalar<T>(SQLCommand command, Func<ISQLReader, T> expression)
{
command.ThrowIfNull(nameof(command));
expression.ThrowIfNull(nameof(expression));
var scalarResult = default(T);
using (var sqlConnection = new SqlConnection(this.connectionString))
{
sqlConnection.OpenWithErrorHandling(this.errorCallback);
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = command.CommandText;
sqlCommand.Parameters.AddRange(command.Parameters);
var scalarObject = sqlCommand.ExecuteScalar();
sqlCommand.Parameters.Clear();
if (scalarObject is T scalarValue)
{
scalarResult = scalarValue;
}
}
}
return scalarResult;
}
/// <summary>
/// Is same like <see cref="Common.SqlExtensions.SQLConnection.ExecuteReader{T}(SQLCommand, Func{ISQLReader, T})"/> but returns only the first data row.
/// </summary>
/// <typeparam name="T">From user specified.</typeparam>
/// <param name="command"><see cref="System.String"/> - SQL query string</param>
/// <param name="expression">Expression that reads specified data from the <see cref="Common.SqlExtensions.ISQLReader"/>.</param>
/// <returns><see cref="{T}"/></returns>
internal T FirstOrDefault<T>(SQLCommand command, Func<ISQLReader, T> expression)
=> this
.ExecuteReader(command, expression)
.FirstOrDefault();
}
}
@@ -0,0 +1,62 @@
namespace Common.SqlExtensions
{
using System;
using System.Data.SqlClient;
public static class SQLExtensions
{
internal static T EnsureNotNull<T>(this T value, string member)
{
value.ThrowIfNull(member);
return value;
}
internal static string EnsureNotNullOrWhiteSpace(this string value, string member)
{
value.ThrowIfNullOrWhiteSpace(member);
return value;
}
internal static void ThrowIfNull<T>(this T value, string member)
{
if (value == null)
{
throw new ArgumentException($"{member} should not be null.", member);
}
}
internal static void ThrowIfNullOrWhiteSpace(this string value, string member)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException($"{member} should not be null or white space.", member);
}
}
internal static void OpenWithErrorHandling(this SqlConnection sqlConnection, Action<string> errorCallback)
{
sqlConnection.ThrowIfNull(nameof(sqlConnection));
sqlConnection.FireInfoMessageEventOnUserErrors = true;
if (errorCallback != null)
{
sqlConnection.InfoMessage += (_, args) => errorCallback(args.Message);
}
sqlConnection.Open();
}
public static object SqlValue(this object value, int index)
{
if (value is null)
{
return DBNull.Value;
}
return $"'{new SqlParameter($"x{index}", value).SqlValue}'";
}
}
}
+159
View File
@@ -0,0 +1,159 @@
namespace Common.SqlExtensions
{
using Common.SqlExtensions.Interfaces;
using System;
using System.Data.SqlClient;
public class SQLReader : ISQLReader, IDisposable
{
private readonly SqlDataReader sqlDataReader;
private int index;
private SQLReader(SqlDataReader sqlDataReader)
=> this.sqlDataReader = sqlDataReader.EnsureNotNull(nameof(sqlDataReader));
public void Dispose()
{
this.sqlDataReader.Close();
this.sqlDataReader.Dispose();
}
public bool GetBool(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return this.sqlDataReader.GetBoolean(this.index);
}
return default(bool);
}
public DateTime GetDate(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return this.sqlDataReader.GetDateTime(this.index);
}
return default(DateTime);
}
public int GetInt(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return this.sqlDataReader.GetInt32(this.index);
}
return default(int);
}
public long GetLong(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return this.sqlDataReader.GetInt64(this.index);
}
return default(long);
}
public short GetSmallint(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return this.sqlDataReader.GetInt16(this.index);
}
return default(short);
}
public string GetString(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return $"{this.sqlDataReader.GetValue(this.index)}";
}
return default(string);
}
public byte GetTinyint(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
return this.sqlDataReader.GetByte(this.index);
}
return default(byte);
}
public T GetValue<T>(int index = -1)
{
this.SetIndex(index);
if (!this.sqlDataReader.IsDBNull(this.index))
{
if (this.sqlDataReader.GetValue(this.index) is T value)
{
return value;
}
}
return default(T);
}
public object GetValue(string column)
{
column.EnsureNotNullOrWhiteSpace(nameof(column));
var colIndex = this.sqlDataReader.GetOrdinal(column);
if (colIndex >= 0 && colIndex < this.sqlDataReader.FieldCount - 1)
{
if (!this.sqlDataReader.IsDBNull(colIndex))
{
return this.sqlDataReader.GetValue(colIndex);
}
}
return default(object);
}
internal bool Read()
{
this.index = -1;
return this.sqlDataReader.Read();
}
private void SetIndex(int index)
{
this.index++;
if (index >= 0)
{
this.index = index;
}
}
public static implicit operator SQLReader(SqlDataReader sqlDataReader)
=> new SQLReader(sqlDataReader);
}
}
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B8523894-2C40-4FF0-A399-B7A91FAE45EA}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SqlExtensions</RootNamespace>
<AssemblyName>SqlExtensions</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Interfaces\ISQLCommand.cs" />
<Compile Include="Interfaces\ISQLConnection.cs" />
<Compile Include="Interfaces\ISQLReader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SQLCommand.cs" />
<Compile Include="SQLConnection.cs" />
<Compile Include="SQLExtensions.cs" />
<Compile Include="SQLReader.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>mkdir $(SolutionDir)packages\$(ProjectName)
copy $(TargetDir)* $(SolutionDir)packages\$(ProjectName)\*</PostBuildEvent>
</PropertyGroup>
</Project>