Переглянути джерело

随机辨识已基本正常,试验时还不正常

l2736 1 місяць тому
батько
коміт
85d4fbe615
37 змінених файлів з 529 додано та 295 видалено
  1. 1 1
      Avalonia/ShakerApp/ShakerApp.csproj
  2. 1 0
      Avalonia/ShakerApp/Styles/ResourceDictionary.axaml
  3. 1 0
      Avalonia/ShakerApp/ViewModels/DataReview/BaseDataReviewItemViewModel.cs
  4. 1 0
      Avalonia/ShakerApp/ViewModels/DataReview/SineDataReviewViewModel.cs
  5. 29 0
      Avalonia/ShakerApp/ViewModels/MainPage/RandomMainPageViewModel.cs
  6. 1 0
      Avalonia/ShakerApp/ViewModels/MainPage/SineMainPageViewModel.cs
  7. 27 0
      Avalonia/ShakerApp/ViewModels/OilSourceConfig/OilSourceConfigViewModel.cs
  8. 3 0
      Avalonia/ShakerApp/ViewModels/ShakerConfig/RandomConfigViewModel.cs
  9. 1 0
      Avalonia/ShakerApp/ViewModels/ShakerConfig/RandomTransferFunctionViewModel.cs
  10. 3 1
      Avalonia/ShakerApp/ViewModels/ShakerConfig/SweepConfigViewModel.cs
  11. 1 0
      Avalonia/ShakerApp/ViewModels/ShakerStatus/ShakerStatusViewModel.cs
  12. 1 0
      Avalonia/ShakerApp/ViewModels/SignalPreview/AnalogSignalPreviewViewModel.cs
  13. 51 0
      Avalonia/ShakerApp/Views/MainPage/RandomLevelView.axaml
  14. 13 0
      Avalonia/ShakerApp/Views/MainPage/RandomLevelView.axaml.cs
  15. 11 0
      Avalonia/ShakerApp/Views/MainPage/RandomMainPage.axaml
  16. 8 84
      Avalonia/ShakerApp/Views/ShakerConfig/RandomConfigView.axaml
  17. 2 1
      Language/Zh-CN/Language.axaml
  18. 2 0
      Shaker.Model/Models/AllConfig.cs
  19. 1 4
      Shaker.Model/Models/BitAddressConfig.cs
  20. 6 2
      Shaker.Model/Models/OilSourceAnalogAddressConfig.cs
  21. 72 0
      Shaker.Model/Models/OilSourceConfig.cs
  22. 7 4
      Shaker.Model/Models/OilSourcePumpAddressConfig.cs
  23. 1 0
      Shaker.Model/Models/RandomDataModel.cs
  24. 6 0
      Shaker.Model/Shaker.Models.csproj
  25. 15 0
      Shaker.Model/Tools/Tools.cs
  26. 2 0
      Shaker/CpuUsage.cs
  27. 105 74
      Shaker/OilSource/OilSource.cs
  28. 0 93
      Shaker/OilSource/OilSourceConfig.cs
  29. 4 3
      Shaker/Program.cs
  30. 2 1
      Shaker/Service.cs
  31. 1 0
      Shaker/ShakerService.Control.cs
  32. 1 0
      Shaker/ShakerService.ReadFifo.cs
  33. 6 3
      Shaker/Tools/Log.cs
  34. 89 0
      Shaker/ViewModel/ServiceOilSourceConfigViewModel.cs
  35. 8 6
      Shaker/ViewModel/ServiceRandomConfigViewModel.cs
  36. 17 7
      Shaker/ViewModel/ServiceRandomDataViewModel.cs
  37. 29 11
      Shaker/log4net.config

+ 1 - 1
Avalonia/ShakerApp/ShakerApp.csproj

@@ -30,7 +30,7 @@
     <PackageReference Include="Avalonia.Desktop" Version="11.2.3" />
     <PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="11.2.3" />
     <PackageReference Include="Avalonia.Themes.Simple" Version="11.2.3" />
-    <PackageReference Include="Avalonia.Diagnostics" Version="11.2.3"/>
+    <PackageReference Include="Avalonia.Diagnostics" Version="11.2.3" />
     <PackageReference Condition="'$(Configuration)'=='Debug'" Include="HotAvalonia" Version="2.1.0" />
     <PackageReference Condition="'$(Configuration)'=='Debug'" Include="HotAvalonia.Extensions" Version="2.1.0" />
     <PackageReference Include="MessagePack" Version="3.1.3" />

+ 1 - 0
Avalonia/ShakerApp/Styles/ResourceDictionary.axaml

@@ -14,6 +14,7 @@
     <s:Double x:Key="ItemHeight">32</s:Double>
     <s:Double x:Key="TabItemHeight">38</s:Double>
     <s:Double x:Key="TabItemFontSize">16</s:Double>
+  <StreamGeometry x:Key="NextLevelGeometry">m0,0l614.4,464.384l0,68.4032l-614.4,419.4304l0,-154.8288l457.216,-297.984l0,-6.144l-457.216,-337.6128l0,-155.648zm614.4,0l614.4,464.384l0,68.4032l-614.4,419.4304l0,-154.8288l457.216,-297.984l0,-6.144l-457.216,-337.6128l0,-155.648z</StreamGeometry>
     <StreamGeometry x:Key="SelectFileGeometry">m463.5648,0a89.6,89.6 0 0 1 58.9952,22.1568l2.816,2.5856l291.648,277.9264a89.6,89.6 0 0 1 27.712,61.0048l0.0768,3.8528l0,170.0736a38.4,38.4 0 0 1 -76.736,2.2528l-0.0768,-2.2528l0,-140.8l-236.8,0a89.6,89.6 0 0 1 -89.5488,-86.528l-0.0512,-3.072l0,-230.4l-352,0a12.8,12.8 0 0 0 -12.7104,11.3024l-0.0896,1.4976l0,793.6a12.8,12.8 0 0 0 11.3024,12.7104l1.4976,0.0896l183.808,0a38.4,38.4 0 0 1 2.2656,76.736l-2.2656,0.064l-183.808,0a89.6,89.6 0 0 1 -89.5488,-86.528l-0.0512,-3.072l0,-793.6a89.6,89.6 0 0 1 86.528,-89.5488l3.072,-0.0512l373.9648,0zm260.3136,320l-205.4784,-195.8272l0,183.0272a12.8,12.8 0 0 0 11.3024,12.7104l1.4976,0.0896l192.6784,0zm-103.0784,204.8a38.4,38.4 0 0 1 38.336,36.1472l0.064,2.2528l0,153.6l147.2,0a38.4,38.4 0 0 1 2.2528,76.736l-2.2528,0.064l-147.2,0l0,140.8a38.4,38.4 0 0 1 -76.736,2.2528l-0.064,-2.2528l0,-140.8l-147.2,0a38.4,38.4 0 0 1 -2.2528,-76.736l2.2528,-0.064l147.2,0l0,-153.6a38.4,38.4 0 0 1 38.4,-38.4z</StreamGeometry>
     <StreamGeometry x:Key="WaveGeometry">m1181.54971,466.31537l-205.312,-5.26629a20149.54057,20149.54057 0 0 0 -77.89714,-253.36685c-8.92343,-14.62857 -12.43429,-27.57486 -28.52571,-27.57486s-23.40572,18.65143 -27.06286,34.66971l-127.63429,553.25257l-159.89028,-736.54857c-2.56,-18.87085 -7.75315,-30.57371 -26.77029,-31.45143c-19.01714,-0.73143 -22.82057,12.14172 -27.06286,30.72l-138.82514,577.97486l-55.296,-148.40686c-3.072,-17.77371 -18.13943,-28.52571 -36.13257,-29.40342l-226.96229,0c-21.57714,0 -44.17828,7.02171 -44.17828,28.52571c0,21.57714 20.04114,31.232 41.54514,31.232l217.96572,0l76.06857,217.89257c5.12,13.312 16.82285,41.984 34.15771,41.984c17.26171,0 29.696,-26.47771 33.64572,-43.59314l126.61028,-556.61714l151.04,745.76457c4.38857,18.28571 12.8,38.912 31.45143,39.13143c18.79771,0.21942 32.62171,-17.55429 37.44914,-35.62058l125.29372,-584.704l54.784,162.66972c10.45943,20.62628 14.848,33.64571 34.59657,38.47314l214.30857,0c21.65029,0 47.03086,-1.97486 47.03086,-23.62514c0,-21.57714 -22.74743,-26.112 -44.39772,-26.112z</StreamGeometry>
     <StreamGeometry x:Key="LanguageIcon">M1024 511.488C1024 228.864 794.624 0 512 0S0 228.864 0 511.488c0 261.12 195.584 476.16 448.512 507.904 14.336 3.072 31.744 4.608 52.224 4.608 5.632 0 11.264-0.512 16.896-1.024A511.232 511.232 0 0 0 1024 511.488z m-73.216 7.168a505.472 505.472 0 0 0-9.728-74.752c0.512-8.704 0.512-16.896 0.512-24.576 6.144 29.696 9.728 60.416 9.728 92.16-0.512 2.56-0.512 5.12-0.512 7.168zM73.216 511.488c0-31.232 3.072-61.44 9.216-90.624 18.944 20.48 63.488 19.968 74.752-10.24 19.456 11.776 45.568 13.824 45.568 36.864 0 76.8 2.56 158.72 72.192 160.256 2.048 0 38.912 13.824 56.32 59.392 6.144 15.872 30.208 0 56.32 0 13.312 0 0 22.016 0 70.144 0 47.616 102.912 120.832 102.912 120.832a550.4 550.4 0 0 0 3.584 77.312 170.24 170.24 0 0 0-57.856 7.68 437.568 437.568 0 0 1-363.008-431.616z m546.816 424.96c-2.048-11.264-12.288-17.408-30.208-12.288 14.336-61.952 21.504-96.256 51.712-122.368 43.52-37.888 5.12-79.872-28.16-75.264-26.112 4.096-9.728-32.256-33.28-34.304-23.552-2.048-54.272-48.64-87.552-64.512-17.92-8.704-35.328-31.232-62.976-32.256-24.576-1.024-59.904 20.48-59.904 4.096 0-53.76-5.632-92.16-6.656-107.008-1.024-12.288-8.192-4.096 25.088-3.584 17.92 0.512 9.216-36.352 27.136-37.376 17.408-1.536 58.88 16.384 69.632 9.216 9.728-6.656 72.192 164.352 72.192 28.16 0-16.384-8.192-44.032 0-59.392 33.28-60.416 64-109.568 61.44-116.736-1.536-4.096-33.792-7.168-59.392 1.024-8.704 3.072 2.56 16.384-9.728 19.456-47.104 10.752-88.064-12.8-73.728-34.816 14.848-22.528 68.608-9.728 73.216-55.296 2.56-26.112 5.12-55.808 6.656-78.336 62.976 9.728 56.32-81.92-37.888-91.648a438.784 438.784 0 0 1 409.6 294.912c-3.072-2.56-6.656-4.608-10.24-4.608-28.16-70.656-97.28-19.456-73.728 43.008-124.928 96.256-93.184 163.328-52.224 201.728 21.504 19.968 42.496 50.688 55.808 72.192-14.848 42.496 53.76 25.6 87.552-46.592a440.32 440.32 0 0 1-314.368 302.592z</StreamGeometry>

+ 1 - 0
Avalonia/ShakerApp/ViewModels/DataReview/BaseDataReviewItemViewModel.cs

@@ -474,6 +474,7 @@ namespace ShakerApp.ViewModels
                             DataFieldX = nameof(DataPoint.X),
                             DataFieldY = nameof(DataPoint.Y),
                             Title = App.Current?.FindResource(ch.Name)+"",
+                            Tag = ch.Unit,
                         });
                     }
                     freqchannel = _Group.Contains(nameof(SweepData.Frequency)) ? _Group[nameof(SweepData.Frequency)] : null;

+ 1 - 0
Avalonia/ShakerApp/ViewModels/DataReview/SineDataReviewViewModel.cs

@@ -63,6 +63,7 @@ namespace ShakerApp.ViewModels
                 line.LineStyle = lineStyles[i];
                 line.XAxisKey = "X";
                 line.YAxisKey = "Y";
+                line.Tag = "g";
                 LineSeries.Add(line);
                 PlotModel.Series.Add(line);
             }

+ 29 - 0
Avalonia/ShakerApp/ViewModels/MainPage/RandomMainPageViewModel.cs

@@ -2,6 +2,7 @@
 using Avalonia.Collections;
 using Avalonia.Controls;
 using Avalonia.Controls.ApplicationLifetimes;
+using CommunityToolkit.Mvvm.Input;
 using OxyPlot;
 using OxyPlot.Series;
 using Shaker.Models;
@@ -13,12 +14,16 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using System.Windows.Input;
 
 namespace ShakerApp.ViewModels
 {
     internal class RandomMainPageViewModel:BaseMainPageViewModel<RandomDataModel>
     {
         public const string SpectrumData = "SpectrumData";
+
+        [PropertyAssociation(nameof(RandomDataModel.TestTotalRunTime))]
+        public uint TestTotalRunTime => Model.TestTotalRunTime;
         [PropertyAssociation(nameof(RandomDataModel.CurrentIdentifyDisplacement))]
         public double CurrentIdentifyDisplacement => Model.CurrentIdentifyDisplacement;
         [PropertyAssociation(nameof(RandomDataModel.CurrentIdentifyRms))]
@@ -29,10 +34,12 @@ namespace ShakerApp.ViewModels
         public RandomStatus RandomStatus => Model.RandomStatus;
         [PropertyAssociation(nameof(RandomDataModel.TimeDomainRMS))]
         public double TimeDomainRMS => Model.TimeDomainRMS;
+        public bool NextButtonVisilily => RandomTestStep == RandomTestStep.Test;
         [PropertyAssociation(nameof(RandomDataModel.RandomTestStep))]
         public RandomTestStep RandomTestStep => Model.RandomTestStep;
         [PropertyAssociation(nameof(RandomDataModel.RandomTestStep))]
         public string RandomTestStepKey => RandomTestStep.Description();
+        public bool NextButtonIsEnabled { get => nextButtonIsEnabled; set =>SetProperty(ref nextButtonIsEnabled , value); }
         [PropertyAssociation(nameof(RandomDataModel.CurrentTestLevel))]
         public double CurrentTestLevel => Model.CurrentTestLevel;
         [PropertyAssociation(nameof(RandomDataModel.CurrentTestTime))]
@@ -44,6 +51,8 @@ namespace ShakerApp.ViewModels
         List<LineStyle> lineStyles = new List<LineStyle>() { LineStyle.Solid, LineStyle.Solid, LineStyle.Solid, LineStyle.Solid, LineStyle.Solid, LineStyle.LongDashDotDot, LineStyle.LongDashDotDot };
         List<string> properties = new List<string>() {nameof(RandomData.Driver), nameof(RandomData.Acceleration), nameof(RandomData.TargetAcceleration), nameof(RandomData.UpStopAcceleration), nameof(RandomData.DownStopAcceleration), nameof(RandomData.UpWarnAcceleration), nameof(RandomData.DownWarnAcceleration) };
         List<RandomData> datas = new List<RandomData>();
+        private bool nextButtonIsEnabled = true;
+
         private RandomMainPageViewModel()
         {
             Content = typeof(Views.RandomMainPage);
@@ -79,6 +88,7 @@ namespace ShakerApp.ViewModels
                 line.LineStyle = lineStyles[i];
                 line.XAxisKey = "Freq";
                 line.YAxisKey = "Ampt";
+                line.Tag = App.Current?.FindResource("RandomValueUnit")?.ToString() ?? string.Empty;
                 LineSeries.Add(line);
                 PlotModel.Series.Add(line);
             }
@@ -140,6 +150,14 @@ namespace ShakerApp.ViewModels
         public override void InitUI()
         {
 
+        }
+        public ICommand NextLevelCommand => new RelayCommand(NextLevel);
+        private async void NextLevel()
+        {
+            NextButtonIsEnabled = false;
+            CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.RANDOMNEXTLEVEL)?.Publish(this);
+            await Task.Delay(1000);
+            NextButtonIsEnabled = true;
         }
         public override void SaveTdmsConfig(TDMS.ITDMSFile? config)
         {
@@ -206,6 +224,17 @@ namespace ShakerApp.ViewModels
         }
         public override void UpDateModel(RandomDataModel model)
         {
+            if (RandomConfigViewModel.Instance.Model.PlanItems.Count > 0)
+            {
+                if (model.CurrentTestLevel == RandomConfigViewModel.Instance.Model.PlanItems[^1].Level)
+                {
+                    NextButtonIsEnabled = false;
+                }
+                else
+                {
+                    NextButtonIsEnabled = true;
+                }
+            }
             base.UpDateModel(model);
             int startindex = (int)(RandomConfigViewModel.Instance.MinFrequency / RandomConfigViewModel.Instance.FrequencyResolution);
             for(int i=0;i<datas.Count;i++)

+ 1 - 0
Avalonia/ShakerApp/ViewModels/MainPage/SineMainPageViewModel.cs

@@ -61,6 +61,7 @@ namespace ShakerApp.ViewModels
                 line.LineStyle = lineStyles[i];
                 line.XAxisKey = "Freq";
                 line.YAxisKey = "Ampt";
+                line.Tag = "g";
                 LineSeries.Add(line);
                 PlotModel.Series.Add(line);
             }

+ 27 - 0
Avalonia/ShakerApp/ViewModels/OilSourceConfig/OilSourceConfigViewModel.cs

@@ -0,0 +1,27 @@
+using IPLCConnect;
+using Shaker.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.ServiceModel.Description;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ShakerApp.ViewModels
+{
+    internal class OilSourceConfigViewModel:DisplayViewModelBase<OilSourceConfig>
+    {
+        public bool IsEnabled { get=>Model.IsEnabled; set=>SetProperty(ref Model.IsEnabled,value); }
+        public string IP { get => Model.IP; set => SetProperty(ref Model.IP, value); }
+        public int Port { get => Model.Port; set => SetProperty(ref Model.Port, value); }
+        public LevelLogic LevelLogic { get => Model.LevelLogic; set => SetProperty(ref Model.LevelLogic, value); }
+        public int LevelTime { get => Model.LevelTime; set => SetProperty(ref Model.LevelTime, value); }
+        public PLCProtocol Protocol { get => Model.Protocol; set => SetProperty(ref Model.Protocol, value); }
+
+    }
+    internal class BitAddressConfigViewModel:ViewModelBase<BitAddressConfig>
+    {
+        public string Address { get => Model.Address; set => SetProperty(ref Model.Address, value); }
+        public byte BitIndex { get => Model.BitIndex; set => SetProperty(ref Model.BitIndex, value); }
+    }
+}

+ 3 - 0
Avalonia/ShakerApp/ViewModels/ShakerConfig/RandomConfigViewModel.cs

@@ -55,6 +55,7 @@ namespace ShakerApp.ViewModels
                 line.LineStyle = lineStyles[i];
                 line.XAxisKey = "Freq";
                 line.YAxisKey = "Ampt";
+                line.Tag = "g";
                 lineSeries.Add(line);
                 AccelerationModel.Series.Add(line);
             }
@@ -95,6 +96,7 @@ namespace ShakerApp.ViewModels
             velocity.LineStyle = lineStyles[0];
             velocity.XAxisKey = "Freq";
             velocity.YAxisKey = "Ampt";
+            velocity.Tag = "m/s";
             VelocityModel.Series.Add(velocity);
             #endregion
 
@@ -129,6 +131,7 @@ namespace ShakerApp.ViewModels
             displacement.LineStyle = lineStyles[0];
             displacement.XAxisKey = "Freq";
             displacement.YAxisKey = "Ampt";
+            displacement.Tag = "mm";
             DisplacementModel.Series.Add(displacement);
             #endregion
 

+ 1 - 0
Avalonia/ShakerApp/ViewModels/ShakerConfig/RandomTransferFunctionViewModel.cs

@@ -91,6 +91,7 @@ namespace ShakerApp.ViewModels
                 return;
             }
             CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.STARTRANDOMTEST)?.Publish(this, null);
+            RandomMainPageViewModel.Instance.NextButtonIsEnabled = true;
             CloseWindowAction?.Invoke();
         }
         protected override void Cancel()

+ 3 - 1
Avalonia/ShakerApp/ViewModels/ShakerConfig/SweepConfigViewModel.cs

@@ -70,6 +70,7 @@ namespace ShakerApp.ViewModels
                 line.LineStyle = lineStyles[i];
                 line.XAxisKey = "Freq";
                 line.YAxisKey = "Ampt";
+                line.Tag = "g";
                 lineSeries.Add(line);
                 AccelerationModel.Series.Add(line);
             }
@@ -110,6 +111,7 @@ namespace ShakerApp.ViewModels
             velocity.LineStyle = lineStyles[0];
             velocity.XAxisKey = "Freq";
             velocity.YAxisKey = "Ampt";
+            velocity.Tag = "m/s";
             VelocityModel.Series.Add(velocity);
             #endregion
 
@@ -144,6 +146,7 @@ namespace ShakerApp.ViewModels
             displacement.LineStyle = lineStyles[0];
             displacement.XAxisKey = "Freq";
             displacement.YAxisKey = "Ampt";
+            displacement.Tag = "mm";
             DisplacementModel.Series.Add(displacement);
             #endregion
 
@@ -325,7 +328,6 @@ namespace ShakerApp.ViewModels
             {
                 var temp = Math.Round(value, 2);
                 if (Math.Abs(temp - Model.OnceSweepTime) <= Increment || double.IsNaN(temp)|| temp ==Model.OnceSweepTime) return;
-                System.Diagnostics.Debug.WriteLine(temp+"  "+ Model.OnceSweepTime);
                 Model.OnceSweepTime = temp;
                 OnPropertyChanged(nameof(OnceSweepTime));
                 //SetProperty(ref Model.OnceSweepTime, temp);

+ 1 - 0
Avalonia/ShakerApp/ViewModels/ShakerStatus/ShakerStatusViewModel.cs

@@ -117,6 +117,7 @@ namespace ShakerApp.ViewModels
             GetEvent<AllConfig>().Subscrip((sender, args) =>
             {
                 valvePower = false;
+                OnPropertyChanged(nameof(ValvePower));
                 UpDateModel(args.Data.ShakerStatus);
                 CommunicationViewModel.Instance.LocalCommunication?.GetEvent<ShakerStatusModel>()?.Subscrip((sender, args) =>
                 {

+ 1 - 0
Avalonia/ShakerApp/ViewModels/SignalPreview/AnalogSignalPreviewViewModel.cs

@@ -194,6 +194,7 @@ namespace ShakerApp.ViewModels
                     }
                     series.XAxisKey = "X";
                     series.YAxisKey = "Y";
+                    series.Tag = allconfig[i].Unit;
                     series.DataFieldX = nameof(DataPoint.X);
                     series.DataFieldY = nameof(DataPoint.Y);
                     Statistics.Add(new StatisticsViewModel(new Models.StatisticsModel()

+ 51 - 0
Avalonia/ShakerApp/Views/MainPage/RandomLevelView.axaml

@@ -0,0 +1,51 @@
+<UserControl
+    x:Class="ShakerApp.Views.RandomLevelView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:vm="using:ShakerApp.ViewModels"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    x:DataType="vm:RandomMainPageViewModel"
+    DataContext="{Binding Source={x:Static vm:RandomMainPageViewModel.Instance}}"
+    mc:Ignorable="d">
+    <StackPanel>
+        <StackPanel>
+            <TextBlock>
+                <Run Text="{DynamicResource CurrentTestLevel}" />
+                <Run Text=":" />
+            </TextBlock>
+            <TextBlock
+                FontSize="24"
+                FontWeight="Black"
+                Text="{Binding CurrentTestLevel, StringFormat={}{0:F2}dB}" />
+        </StackPanel>
+        <StackPanel>
+            <TextBlock>
+                <Run Text="{DynamicResource CurrentTestTime}" />
+                <Run Text=":" />
+            </TextBlock>
+            <TextBlock
+                FontSize="24"
+                FontWeight="Black"
+                Text="{Binding CurrentTestTime, Converter={StaticResource TimeToStringConverter}}" />
+        </StackPanel>
+        <StackPanel>
+            <TextBlock>
+                <Run Text="{DynamicResource CurrentLevelTestMaxTime}" />
+                <Run Text=":" />
+            </TextBlock>
+            <TextBlock
+                FontSize="24"
+                FontWeight="Black"
+                Text="{Binding CurrentLevelTestMaxTime, Converter={StaticResource TimeToStringConverter}}" />
+        </StackPanel>
+        <Button Foreground="Green" IsEnabled="{Binding NextButtonIsEnabled}">
+            <StackPanel>
+                <PathIcon Data="{StaticResource NextLevelGeometry}" Foreground="Green" />
+                <TextBlock Foreground="Green" Text="{DynamicResource NextLevel}" />
+            </StackPanel>
+        </Button>
+    </StackPanel>
+</UserControl>

+ 13 - 0
Avalonia/ShakerApp/Views/MainPage/RandomLevelView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ShakerApp.Views;
+
+public partial class RandomLevelView : UserControl
+{
+    public RandomLevelView()
+    {
+        InitializeComponent();
+    }
+}

+ 11 - 0
Avalonia/ShakerApp/Views/MainPage/RandomMainPage.axaml

@@ -77,6 +77,17 @@
                             </TextBlock>
                             <TextBlock Text="{Binding CurrentLevelTestMaxTime, Converter={StaticResource TimeToStringConverter}}" />
                         </StackPanel>
+                        <StackPanel IsVisible="{Binding RandomTestStep, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static models:RandomTestStep.Test}}">
+                            <TextBlock>
+                                <Run Text="{DynamicResource RunTime}" />
+                                <Run Text=":" />
+                            </TextBlock>
+                            <TextBlock
+                                FontSize="24"
+                                FontWeight="Black"
+                                Text="{Binding TestTotalRunTime, Converter={StaticResource TimeToStringConverter}}" />
+                        </StackPanel>
+                        <view:RandomLevelView IsVisible="{Binding NextButtonVisilily}" />
                     </StackPanel>
                 </Expander>
             </StackPanel>

+ 8 - 84
Avalonia/ShakerApp/Views/ShakerConfig/RandomConfigView.axaml

@@ -18,8 +18,10 @@
 
     <Grid RowDefinitions="1.2*,*">
         <Grid ColumnDefinitions="*,*,*">
-            <oxy:PlotView Background="Transparent" Model="{Binding AccelerationModel}">l
-            </oxy:PlotView>
+            <oxy:PlotView
+                Background="Transparent"
+                DefaultTrackerTemplate="{StaticResource DefaultTrackerTemplate}"
+                Model="{Binding AccelerationModel}" />
             <Button
                 Margin="0,0,16,56"
                 HorizontalAlignment="Right"
@@ -45,47 +47,8 @@
             <oxy:PlotView
                 Grid.Column="1"
                 Background="Transparent"
-                Model="{Binding VelocityModel}">
-
-                <oxy:PlotView.DefaultTrackerTemplate>
-                    <ControlTemplate>
-                        <oxy:TrackerControl
-                            Background="#6F999999"
-                            BorderBrush="Transparent"
-                            CornerRadius="6"
-                            HorizontalLineVisibility="False"
-                            LineExtents="{Binding PlotModel.PlotArea}"
-                            LineStroke="Gray"
-                            Position="{Binding Position}"
-                            ShowPointer="True"
-                            VerticalLineVisibility="True">
-                            <oxy:TrackerControl.Content>
-                                <StackPanel Margin="10">
-                                    <TextBlock Text="{DynamicResource Value}" />
-                                    <TextBlock>
-                                        <Run Text="{Binding XAxis.Title}" />
-                                        <Run Text=":" />
-                                        <Run Text="{Binding TrackerDatas[0].DataPoint.X, StringFormat='{}{0:F2}'}" />
-                                        <Run Text="{Binding XAxis.Unit}" />
-                                    </TextBlock>
-                                    <ItemsControl ItemsSource="{Binding TrackerDatas}">
-                                        <ItemsControl.ItemTemplate>
-                                            <DataTemplate>
-                                                <TextBlock IsVisible="{Binding Series.IsVisible}">
-                                                    <Run Text="{Binding Series.Title}" />
-                                                    <Run Text=":" />
-                                                    <Run Text="{Binding DataPoint.Y, StringFormat='{}{0:F4}'}" />
-                                                    <Run Text="{Binding $parent[ItemsControl].DataContext.YAxis.Unit}" />
-                                                </TextBlock>
-                                            </DataTemplate>
-                                        </ItemsControl.ItemTemplate>
-                                    </ItemsControl>
-                                </StackPanel>
-                            </oxy:TrackerControl.Content>
-                        </oxy:TrackerControl>
-                    </ControlTemplate>
-                </oxy:PlotView.DefaultTrackerTemplate>
-            </oxy:PlotView>
+                DefaultTrackerTemplate="{StaticResource DefaultTrackerTemplate}"
+                Model="{Binding VelocityModel}" />
             <Button
                 Grid.Column="1"
                 Margin="0,0,16,56"
@@ -112,47 +75,8 @@
             <oxy:PlotView
                 Grid.Column="2"
                 Background="Transparent"
-                Model="{Binding DisplacementModel}">
-
-                <oxy:PlotView.DefaultTrackerTemplate>
-                    <ControlTemplate>
-                        <oxy:TrackerControl
-                            Background="#6F999999"
-                            BorderBrush="Transparent"
-                            CornerRadius="6"
-                            HorizontalLineVisibility="False"
-                            LineExtents="{Binding PlotModel.PlotArea}"
-                            LineStroke="Gray"
-                            Position="{Binding Position}"
-                            ShowPointer="True"
-                            VerticalLineVisibility="True">
-                            <oxy:TrackerControl.Content>
-                                <StackPanel Margin="10">
-                                    <TextBlock Text="{DynamicResource Value}" />
-                                    <TextBlock>
-                                        <Run Text="{Binding XAxis.Title}" />
-                                        <Run Text=":" />
-                                        <Run Text="{Binding TrackerDatas[0].DataPoint.X, StringFormat='{}{0:F2}'}" />
-                                        <Run Text="{Binding XAxis.Unit}" />
-                                    </TextBlock>
-                                    <ItemsControl ItemsSource="{Binding TrackerDatas}">
-                                        <ItemsControl.ItemTemplate>
-                                            <DataTemplate>
-                                                <TextBlock IsVisible="{Binding Series.IsVisible}">
-                                                    <Run Text="{Binding Series.Title}" />
-                                                    <Run Text=":" />
-                                                    <Run Text="{Binding DataPoint.Y, StringFormat='{}{0:F4}'}" />
-                                                    <Run Text="{Binding $parent[ItemsControl].DataContext.YAxis.Unit}" />
-                                                </TextBlock>
-                                            </DataTemplate>
-                                        </ItemsControl.ItemTemplate>
-                                    </ItemsControl>
-                                </StackPanel>
-                            </oxy:TrackerControl.Content>
-                        </oxy:TrackerControl>
-                    </ControlTemplate>
-                </oxy:PlotView.DefaultTrackerTemplate>
-            </oxy:PlotView>
+                DefaultTrackerTemplate="{StaticResource DefaultTrackerTemplate}"
+                Model="{Binding DisplacementModel}" />
             <Button
                 Grid.Column="2"
                 Margin="0,0,16,56"

+ 2 - 1
Language/Zh-CN/Language.axaml

@@ -221,7 +221,7 @@
     <s:String x:Key="CurrentIdentifyRms">当前辨识均方根</s:String>
     <s:String x:Key="IdentifyIndex">已辨识帧数</s:String>
     <s:String x:Key="CurrentTestLevel">当前量级</s:String>
-    <s:String x:Key="CurrentTestTime">已运行时间</s:String>
+    <s:String x:Key="CurrentTestTime">当前量级已运行时间</s:String>
     <s:String x:Key="CurrentLevelTestMaxTime">当前量级试验时间</s:String>
     <s:String x:Key="StartRandomTest">继续试验</s:String>
 
@@ -244,6 +244,7 @@
     <s:String x:Key="Message">消息</s:String>
     <s:String x:Key="SelectSignalType">选择信号</s:String>
     <s:String x:Key="MenuShakerControl">液压台控制</s:String>
+    <s:String x:Key="NextLevel">下一量级</s:String>
 
     <s:String x:Key="SpectrumItems">参考谱</s:String>
     <s:String x:Key="UpFrequency">频率上限</s:String>

+ 2 - 0
Shaker.Model/Models/AllConfig.cs

@@ -26,5 +26,7 @@ namespace Shaker.Models
         public RandomConfigModel RandomConfig { get; set; }
         [AllowNull]
         public ShakerChannelModel ShakerChannel { get; set; }
+        [AllowNull]
+        public OilSourceConfig OilSourceConfig { get; set; }
     }
 }

+ 1 - 4
Shaker/OilSource/BitAddressConfig.cs → Shaker.Model/Models/BitAddressConfig.cs

@@ -1,7 +1,4 @@
-
-using Shaker.Models;
-
-namespace ShakerService.OilSource
+namespace Shaker.Models
 {
     public class BitAddressConfig:BaseModel
     {

+ 6 - 2
Shaker/OilSource/OilSourceAnalogAddressConfig.cs → Shaker.Model/Models/OilSourceAnalogAddressConfig.cs

@@ -1,6 +1,6 @@
-namespace ShakerService.OilSource
+namespace Shaker.Models
 {
-    public class OilSourceAnalogAddressConfig
+    public class OilSourceAnalogAddressConfig:BaseModel
     {
         /// <summary>
         /// 名字,与多语言字典文件中的key相同
@@ -48,5 +48,9 @@
         /// </summary>
         public byte LowerErrorBitIndex = 0;
 
+        public override object Clone()
+        {
+            return this.CloneBase();
+        }
     }
 }

+ 72 - 0
Shaker.Model/Models/OilSourceConfig.cs

@@ -0,0 +1,72 @@
+
+using IPLCConnect;
+using Shaker.Models;
+
+namespace Shaker.Models
+{
+    public class OilSourceConfig : BaseModel
+    {
+        /// <summary>
+        /// 是否启用
+        /// </summary>
+        public bool IsEnabled = true;
+        /// <summary>
+        /// 油源IP地址
+        /// </summary>
+        public string IP = "127.0.0.1";
+        /// <summary>
+        /// 端口号
+        /// </summary>
+        public int Port = 502;
+        /// <summary>
+        /// 开关控制逻辑
+        /// </summary>
+        public LevelLogic LevelLogic = LevelLogic.Edge;
+        /// <summary>
+        /// 电平保持时间
+        /// </summary>
+        public int LevelTime = 50;
+        /// <summary>
+        /// 通信协议
+        /// </summary>
+        public PLCProtocol Protocol = PLCProtocol.S7;
+        /// <summary>
+        /// 主油泵地址
+        /// </summary>
+        public List<OilSourcePumpAddressConfig> MainPumpAddress = new List<OilSourcePumpAddressConfig>();
+        /// <summary>
+        /// 先导泵地址
+        /// </summary>
+        public OilSourcePumpAddressConfig ForerunnerAddress = new OilSourcePumpAddressConfig();
+        /// <summary>
+        /// 循环泵地址
+        /// </summary>
+        public OilSourcePumpAddressConfig CirculateAddress = new OilSourcePumpAddressConfig();
+        /// <summary>
+        /// 辅助油路地址
+        /// </summary>
+        public OilSourcePumpAddressConfig AssistantAddress = new OilSourcePumpAddressConfig();
+
+        /// <summary>
+        /// 远程/本地地址
+        /// </summary>
+        public BitAddressConfig IsRemoteAddress = new BitAddressConfig();
+        /// <summary>
+        /// 急停地址
+        /// </summary>
+        public BitAddressConfig EmergencyStopAddress = new BitAddressConfig();
+        /// <summary>
+        /// 模拟量地址
+        /// </summary>
+        public List<OilSourceAnalogAddressConfig> AnalogAddress = new List<OilSourceAnalogAddressConfig>();
+        /// <summary>
+        /// 错误信息地址
+        /// </summary>
+        public List<BitAddressConfig> ErrorAddress = new List<BitAddressConfig>();
+
+        public override object Clone()
+        {
+            return this.CloneBase();
+        }
+    }
+}

+ 7 - 4
Shaker/OilSource/OilSourcePumpAddressConfig.cs → Shaker.Model/Models/OilSourcePumpAddressConfig.cs

@@ -1,8 +1,7 @@
-using MessagePack.Formatters;
-
-namespace ShakerService.OilSource
+
+namespace Shaker.Models
 {
-    public class OilSourcePumpAddressConfig
+    public class OilSourcePumpAddressConfig:BaseModel
     {
         /// <summary>
         /// 名字
@@ -79,5 +78,9 @@ namespace ShakerService.OilSource
         /// 卸载地址位
         /// </summary>
         public byte UnLoadBitIndex = 0;
+        public override object Clone()
+        {
+            return this.CloneBase();
+        }
     }
 }

+ 1 - 0
Shaker.Model/Models/RandomDataModel.cs

@@ -21,6 +21,7 @@ namespace Shaker.Models
         public double TimeDomainRMS = 0;
         public RandomStatus RandomStatus = RandomStatus.Start;
         public RandomTestStep RandomTestStep = RandomTestStep.Start;
+        public uint TestTotalRunTime = 0;
         public double CurrentTestLevel = 0;
         public uint CurrentTestTime = 0;
         public uint CurrentLevelTestMaxTime = 0;

+ 6 - 0
Shaker.Model/Shaker.Models.csproj

@@ -12,4 +12,10 @@
     <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
   </ItemGroup>
 
+
+
+  <ItemGroup>
+    <ProjectReference Include="..\PLCConnect\IPLCConnect\IPLCConnect.csproj" />
+  </ItemGroup>
+
 </Project>

+ 15 - 0
Shaker.Model/Tools/Tools.cs

@@ -11,6 +11,21 @@ namespace Shaker.Models.Tools
 {
     public static  class Tools
     {
+        /// <summary>
+        /// 单边谱扩展到双边谱
+        /// </summary>
+        /// <param name="unilateralSpectrum"></param>
+        /// <returns></returns>
+        public static double[] UnilateralSpectrumToBilateralSpectrum(double[] unilateralSpectrum) 
+        {
+            double[] result = new double[unilateralSpectrum.Length << 1];
+            result[0] = unilateralSpectrum[0];
+            Unsafe.CopyBlock(ref Unsafe.As<double, byte>(ref result[1]), ref Unsafe.As<double, byte>(ref unilateralSpectrum[0]), (uint)(unilateralSpectrum.Length * Unsafe.SizeOf<double>()));
+            double[] temp = unilateralSpectrum.Reverse().ToArray();
+            Unsafe.CopyBlock(ref Unsafe.As<double, byte>(ref result[unilateralSpectrum.Length+1]), ref Unsafe.As<double, byte>(ref temp[0]), (uint)((unilateralSpectrum.Length-1) * Unsafe.SizeOf<double>()));
+            return result;
+        }
+
         public static void CalcSlope(double[] x, double[] y,ref double k,ref double b)
         {
             if(x ==null || y==null || x.Length!=2||y.Length!=2)

+ 2 - 0
Shaker/CpuUsage.cs

@@ -20,6 +20,7 @@ namespace ShakerService
 
         public CpuUsage()
         {
+            if (!System.IO.File.Exists(ProcStatPath)) return;
             _previousCpuData = ReadCpuData();
             ParseCpuData(_previousCpuData, out _previousTotalUserTime, out _previousTotalUserNiceTime, out _previousTotalSystemTime, out _previousTotalIdleTime);
         }
@@ -28,6 +29,7 @@ namespace ShakerService
         {
             if ((DateTime.Now - dateTime).TotalMilliseconds < 2000) return lastusage;
             dateTime = DateTime.Now;
+            if (!System.IO.File.Exists(ProcStatPath)) return lastusage;
             string currentCpuData = ReadCpuData();
             ParseCpuData(currentCpuData, out long currentTotalUserTime, out long currentTotalUserNiceTime, out long currentTotalSystemTime, out long currentTotalIdleTime);
 

+ 105 - 74
Shaker/OilSource/OilSource.cs

@@ -1,6 +1,7 @@
 using MessagePack.Formatters;
 using Shaker.Models;
 using ShakerService.Tools;
+using ShakerService.ViewModel;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
@@ -21,7 +22,6 @@ namespace ShakerService.OilSource
         [AllowNull]
         private IPLCConnect.IPLCConnect _PLCConnect;
         private static string PluginPath = System.AppDomain.CurrentDomain.BaseDirectory + "PLCConnect";
-        private OilSourceConfig oilSourceConfig = new OilSourceConfig();
         public OilSourceStatusModel OilSourceStatus { get; } = new OilSourceStatusModel();
         public static OilSource Default { get; } = new OilSource();
         private object locker = new object();
@@ -31,8 +31,7 @@ namespace ShakerService.OilSource
         private System.Timers.Timer _timer = new System.Timers.Timer(5000);
         public void Init()
         {
-            oilSourceConfig = OilSourceConfig.ReadConfig();
-            var analog = oilSourceConfig.AnalogAddress.Where(x => !string.IsNullOrEmpty(x.ValueAddress) && !string.IsNullOrEmpty(x.Name)).ToList();
+            var analog = ServiceOilSourceConfigViewModel.Instance.AnalogAddress.Where(x => !string.IsNullOrEmpty(x.ValueAddress) && !string.IsNullOrEmpty(x.Name)).ToList();
             if (analog.Count > 0)
             {
                 OilSourceStatus.OilSourceAnalogs.AddRange(analog.Select(x=>new OilSourceAnalogModel()
@@ -41,8 +40,7 @@ namespace ShakerService.OilSource
                     Unit = x.Unit,
                 }));
             }
-            oilSourceConfig.AnalogAddress = analog;
-            var mainpump = oilSourceConfig.MainPumpAddress.Where(x => !string.IsNullOrEmpty(x.Address) && x.IsEnabled).ToList();
+            var mainpump = ServiceOilSourceConfigViewModel.Instance.MainPumpAddress.Where(x => !string.IsNullOrEmpty(x.Address) && x.IsEnabled).ToList();
             if (mainpump.Count > 0)
             {
                 OilSourceStatus.Circuit.AddRange(mainpump.Select(x=>new CircuitModel()
@@ -53,32 +51,30 @@ namespace ShakerService.OilSource
                     IsEnablePressure= x.IsPressureEnabled,
                 }));
             }
-            oilSourceConfig.MainPumpAddress = mainpump;
-            OilSourceStatus.Circulate.Name = oilSourceConfig.CirculateAddress.Name;
-            OilSourceStatus.Circulate.IsEnableLoad = oilSourceConfig.CirculateAddress.IsLoadEnabled;
-            OilSourceStatus.Circulate.IsEnable= oilSourceConfig.CirculateAddress.IsEnabled;
-            OilSourceStatus.Circulate.IsEnablePressure = oilSourceConfig.CirculateAddress.IsPressureEnabled;
+            OilSourceStatus.Circulate.Name = ServiceOilSourceConfigViewModel.Instance.CirculateAddress.Name;
+            OilSourceStatus.Circulate.IsEnableLoad = ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsLoadEnabled;
+            OilSourceStatus.Circulate.IsEnable= ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsEnabled;
+            OilSourceStatus.Circulate.IsEnablePressure = ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsPressureEnabled;
 
 
-            OilSourceStatus.Forerunner.Name = oilSourceConfig.ForerunnerAddress.Name;
-            OilSourceStatus.Forerunner.IsEnableLoad = oilSourceConfig.ForerunnerAddress.IsLoadEnabled;
-            OilSourceStatus.Forerunner.IsEnable = oilSourceConfig.ForerunnerAddress.IsEnabled;
-            OilSourceStatus.Forerunner.IsEnablePressure = oilSourceConfig.ForerunnerAddress.IsPressureEnabled;
+            OilSourceStatus.Forerunner.Name = ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.Name;
+            OilSourceStatus.Forerunner.IsEnableLoad = ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsLoadEnabled;
+            OilSourceStatus.Forerunner.IsEnable = ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsEnabled;
+            OilSourceStatus.Forerunner.IsEnablePressure = ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsPressureEnabled;
 
-            OilSourceStatus.Assistant.Name = oilSourceConfig.AssistantAddress.Name;
-            OilSourceStatus.Assistant.IsEnableLoad = oilSourceConfig.AssistantAddress.IsLoadEnabled;
-            OilSourceStatus.Assistant.IsEnable = oilSourceConfig.AssistantAddress.IsEnabled;
-            OilSourceStatus.Assistant.IsEnablePressure = oilSourceConfig.AssistantAddress.IsPressureEnabled;
+            OilSourceStatus.Assistant.Name = ServiceOilSourceConfigViewModel.Instance.AssistantAddress.Name;
+            OilSourceStatus.Assistant.IsEnableLoad = ServiceOilSourceConfigViewModel.Instance.AssistantAddress.IsLoadEnabled;
+            OilSourceStatus.Assistant.IsEnable = ServiceOilSourceConfigViewModel.Instance.AssistantAddress.IsEnabled;
+            OilSourceStatus.Assistant.IsEnablePressure = ServiceOilSourceConfigViewModel.Instance.AssistantAddress.IsPressureEnabled;
 
-            oilSourceConfig.ErrorAddress = oilSourceConfig.ErrorAddress.Where(x => !string.IsNullOrEmpty(x.Address)).ToList();
-            if (oilSourceConfig.ErrorAddress.Count > 0)
+            if (ServiceOilSourceConfigViewModel.Instance.ErrorAddress.Count > 0)
             {
-                OilSourceStatus.OilErrors.AddRange(Enumerable.Repeat(new ErrorInfoModel(), oilSourceConfig.ErrorAddress.Count));
+                OilSourceStatus.OilErrors.AddRange(Enumerable.Repeat(new ErrorInfoModel(), ServiceOilSourceConfigViewModel.Instance.ErrorAddress.Count));
             }
-            OilSourceStatus.IsEnabled = oilSourceConfig.IsEnabled;
+            OilSourceStatus.IsEnabled = ServiceOilSourceConfigViewModel.Instance.IsEnabled;
             if (!IsEnabled) return;
             var plcs = Tools.PluginsLoader.Defalut.Load<IPLCConnect.IPLCConnect>(PluginPath);
-            _PLCConnect = plcs.FirstOrDefault(x => x.Protocol == oilSourceConfig.Protocol);
+            _PLCConnect = plcs.FirstOrDefault(x => x.Protocol == ServiceOilSourceConfigViewModel.Instance.Protocol);
             if (_PLCConnect == null)
             {
                 OilSourceStatus.IsEnabled = false;
@@ -86,7 +82,7 @@ namespace ShakerService.OilSource
             }
             try
             {
-                _PLCConnect.Init(oilSourceConfig.IP, oilSourceConfig.Port);
+                _PLCConnect.Init(ServiceOilSourceConfigViewModel.Instance.IP, ServiceOilSourceConfigViewModel.Instance.Port);
                 _PLCConnect.StatusChanged += PLCConnect_StatusChanged;
                 _PLCConnect.Connect();
             }
@@ -100,6 +96,41 @@ namespace ShakerService.OilSource
                 RepeatConnectPLC();
             }
         }
+        public void ChangedPLCConfig()
+        {
+            if(_PLCConnect.Protocol == ServiceOilSourceConfigViewModel.Instance.Protocol)
+            {
+                Connect();
+                return;
+            }
+            if (_PLCConnect != null)
+            {
+                _PLCConnect.StatusChanged -= PLCConnect_StatusChanged;
+                _PLCConnect.Dispose();
+            }
+            var plcs = Tools.PluginsLoader.Defalut.Load<IPLCConnect.IPLCConnect>(PluginPath);
+            _PLCConnect = plcs.FirstOrDefault(x => x.Protocol == ServiceOilSourceConfigViewModel.Instance.Protocol);
+            if (_PLCConnect == null)
+            {
+                OilSourceStatus.IsEnabled = false;
+                return;
+            }
+            try
+            {
+                _PLCConnect.Init(ServiceOilSourceConfigViewModel.Instance.IP, ServiceOilSourceConfigViewModel.Instance.Port);
+                _PLCConnect.StatusChanged += PLCConnect_StatusChanged;
+                _PLCConnect.Connect();
+            }
+            catch
+            {
+
+            }
+            OilSourceStatus.IsConnect = _PLCConnect.IsConnected;
+            if (!_PLCConnect.IsConnected)
+            {
+                RepeatConnectPLC();
+            }
+        }
         private void RepeatConnectPLC()
         {
             _timer.Enabled = true;
@@ -116,22 +147,22 @@ namespace ShakerService.OilSource
             {
                 if(args.Data.Length>=2 && args.Data[0] is int index && args.Data[1] is float pressure)
                 {
-                    if (!oilSourceConfig.MainPumpAddress[index].IsPressureEnabled) return;
-                    _PLCConnect?.Write(oilSourceConfig.MainPumpAddress[index].Address, pressure);
+                    if (!ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].IsPressureEnabled) return;
+                    _PLCConnect?.Write(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].Address, pressure);
                 }
             });
             Communication.Instance.Context.GetEvent(Topic.CircuitStart)?.Subscrip((sender, args) =>
             {
                 if (args.Data.Length >= 2 && args.Data[0] is int index && args.Data[1] is bool state)
                 {
-                    if (!oilSourceConfig.MainPumpAddress[index].IsEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].IsEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.MainPumpAddress[index].StartAddress, oilSourceConfig.MainPumpAddress[index].StartBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].StartAddress, ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].StartBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.MainPumpAddress[index].StopAddress, oilSourceConfig.MainPumpAddress[index].StopBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].StopAddress, ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].StopBitIndex, true);
                     }
                 }
             });
@@ -139,14 +170,14 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 2 && args.Data[0] is int index && args.Data[1] is bool state)
                 {
-                    if (!oilSourceConfig.MainPumpAddress[index].IsLoadEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].IsLoadEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.MainPumpAddress[index].LoadAddress, oilSourceConfig.MainPumpAddress[index].LoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].LoadAddress, ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].LoadBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.MainPumpAddress[index].UnLoadAddress, oilSourceConfig.MainPumpAddress[index].UnLoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].UnLoadAddress, ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[index].UnLoadBitIndex, true);
                     }
                 }
             });
@@ -155,22 +186,22 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 1 && args.Data[0] is float pressure)
                 {
-                    if (!oilSourceConfig.ForerunnerAddress.IsPressureEnabled) return;
-                    _PLCConnect?.Write(oilSourceConfig.ForerunnerAddress.Address, pressure);
+                    if (!ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsPressureEnabled) return;
+                    _PLCConnect?.Write(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.Address, pressure);
                 }
             });
             Communication.Instance.Context.GetEvent(Topic.ForerunnerStart)?.Subscrip((sender, args) =>
             {
                 if (args.Data.Length >= 1  && args.Data[0] is bool state)
                 {
-                    if (!oilSourceConfig.ForerunnerAddress.IsEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.ForerunnerAddress.StartAddress, oilSourceConfig.ForerunnerAddress.StartBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.StartAddress, ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.StartBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.ForerunnerAddress.StopAddress, oilSourceConfig.ForerunnerAddress.StopBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.StopAddress, ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.StopBitIndex, true);
                     }
                 }
             });
@@ -178,14 +209,14 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 1  && args.Data[0] is bool state)
                 {
-                    if (!oilSourceConfig.ForerunnerAddress.IsLoadEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsLoadEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.ForerunnerAddress.LoadAddress, oilSourceConfig.ForerunnerAddress.LoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.LoadAddress, ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.LoadBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.ForerunnerAddress.UnLoadAddress, oilSourceConfig.ForerunnerAddress.UnLoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.UnLoadAddress, ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.UnLoadBitIndex, true);
                     }
                 }
             });
@@ -194,22 +225,22 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 1 && args.Data[0] is float pressure)
                 {
-                    if (!oilSourceConfig.AssistantAddress.IsPressureEnabled) return;
-                    _PLCConnect?.Write(oilSourceConfig.AssistantAddress.Address, pressure);
+                    if (!ServiceOilSourceConfigViewModel.Instance.AssistantAddress.IsPressureEnabled) return;
+                    _PLCConnect?.Write(ServiceOilSourceConfigViewModel.Instance.AssistantAddress.Address, pressure);
                 }
             });
             Communication.Instance.Context.GetEvent(Topic.AssistantStart)?.Subscrip((sender, args) =>
             {
                 if (args.Data.Length >= 1  && args.Data[0] is bool state)
                 {
-                    if (!oilSourceConfig.AssistantAddress.IsEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.AssistantAddress.IsEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.AssistantAddress.StartAddress, oilSourceConfig.AssistantAddress.StartBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.AssistantAddress.StartAddress, ServiceOilSourceConfigViewModel.Instance.AssistantAddress.StartBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.AssistantAddress.StopAddress, oilSourceConfig.AssistantAddress.StopBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.AssistantAddress.StopAddress, ServiceOilSourceConfigViewModel.Instance.AssistantAddress.StopBitIndex, true);
                     }
                 }
             });
@@ -217,14 +248,14 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 1  && args.Data[0] is bool state)
                 {
-                    if (!oilSourceConfig.AssistantAddress.IsLoadEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.AssistantAddress.IsLoadEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.AssistantAddress.LoadAddress, oilSourceConfig.AssistantAddress.LoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.AssistantAddress.LoadAddress, ServiceOilSourceConfigViewModel.Instance.AssistantAddress.LoadBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.AssistantAddress.UnLoadAddress, oilSourceConfig.AssistantAddress.UnLoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.AssistantAddress.UnLoadAddress, ServiceOilSourceConfigViewModel.Instance.AssistantAddress.UnLoadBitIndex, true);
                     }
                 }
             });
@@ -233,22 +264,22 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 1  && args.Data[0] is float pressure)
                 {
-                    if (!oilSourceConfig.CirculateAddress.IsPressureEnabled) return;
-                    _PLCConnect?.Write(oilSourceConfig.CirculateAddress.Address, pressure);
+                    if (!ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsPressureEnabled) return;
+                    _PLCConnect?.Write(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.Address, pressure);
                 }
             });
             Communication.Instance.Context.GetEvent(Topic.CirculateStart)?.Subscrip((sender, args) =>
             {
                 if (args.Data.Length >= 1  && args.Data[0] is bool state)
                 {
-                    if (!oilSourceConfig.CirculateAddress.IsEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.CirculateAddress.StartAddress, oilSourceConfig.CirculateAddress.StartBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.StartAddress, ServiceOilSourceConfigViewModel.Instance.CirculateAddress.StartBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.CirculateAddress.StopAddress, oilSourceConfig.CirculateAddress.StopBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.StopAddress, ServiceOilSourceConfigViewModel.Instance.CirculateAddress.StopBitIndex, true);
                     }
                 }
             });
@@ -256,14 +287,14 @@ namespace ShakerService.OilSource
             {
                 if (args.Data.Length >= 1  && args.Data[0] is bool state)
                 {
-                    if (!oilSourceConfig.CirculateAddress.IsLoadEnabled) return;
+                    if (!ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsLoadEnabled) return;
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.CirculateAddress.LoadAddress, oilSourceConfig.CirculateAddress.LoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.LoadAddress, ServiceOilSourceConfigViewModel.Instance.CirculateAddress.LoadBitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.CirculateAddress.UnLoadAddress, oilSourceConfig.CirculateAddress.UnLoadBitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.UnLoadAddress, ServiceOilSourceConfigViewModel.Instance.CirculateAddress.UnLoadBitIndex, true);
                     }
                 }
             });
@@ -274,11 +305,11 @@ namespace ShakerService.OilSource
                 {
                     if (state)
                     {
-                        SetLevel(oilSourceConfig.EmergencyStopAddress.Address, oilSourceConfig.EmergencyStopAddress.BitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.EmergencyStopAddress.Address, ServiceOilSourceConfigViewModel.Instance.EmergencyStopAddress.BitIndex, true);
                     }
                     else
                     {
-                        SetLevel(oilSourceConfig.EmergencyStopAddress.Address, oilSourceConfig.EmergencyStopAddress.BitIndex, true);
+                        SetLevel(ServiceOilSourceConfigViewModel.Instance.EmergencyStopAddress.Address, ServiceOilSourceConfigViewModel.Instance.EmergencyStopAddress.BitIndex, true);
                     }
                 }
             });
@@ -290,7 +321,7 @@ namespace ShakerService.OilSource
             try
             {
                 Ping ping = new Ping();
-                if(ping.Send(oilSourceConfig.IP).Status == IPStatus.Success)
+                if(ping.Send(ServiceOilSourceConfigViewModel.Instance.IP).Status == IPStatus.Success)
                 {
                     //_PLCConnect.Init(oilSourceConfig.IP, oilSourceConfig.Port);
                     lock (locker)
@@ -307,14 +338,14 @@ namespace ShakerService.OilSource
 
         private async void SetLevel(string address ,byte bitindex,bool value)
         {
-            if(oilSourceConfig.LevelLogic == LevelLogic.Level)
+            if(ServiceOilSourceConfigViewModel.Instance.LevelLogic == LevelLogic.Level)
             {
                 _PLCConnect?.Writebit(address, bitindex, value);
             }
             else
             {
                 _PLCConnect?.Writebit(address, bitindex, !value);
-                await Task.Delay(oilSourceConfig.LevelTime);
+                await Task.Delay(ServiceOilSourceConfigViewModel.Instance.LevelTime);
                 _PLCConnect?.Writebit(address, bitindex, value);
             }
         }
@@ -358,30 +389,30 @@ namespace ShakerService.OilSource
                 }
                 for (int i = 0; i < OilSourceStatus.Circuit.Count; i++)
                 {
-                    OilSourceStatus.Circuit[i].IsStart = _PLCConnect.ReadBit(oilSourceConfig.MainPumpAddress[i].IsStartAddress, oilSourceConfig.MainPumpAddress[i].IsStartBitIndex);
+                    OilSourceStatus.Circuit[i].IsStart = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[i].IsStartAddress, ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[i].IsStartBitIndex);
                     //OilSourceStatus.Circuit[i].Pressure = _PLCConnect.Read<float>(oilSourceConfig.MainPumpAddress[i].Address);
-                    OilSourceStatus.Circuit[i].IsLoadPressure = _PLCConnect.ReadBit(oilSourceConfig.MainPumpAddress[i].IsLoadAddress, oilSourceConfig.MainPumpAddress[i].IsLoadBitIndex);
+                    OilSourceStatus.Circuit[i].IsLoadPressure = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[i].IsLoadAddress, ServiceOilSourceConfigViewModel.Instance.MainPumpAddress[i].IsLoadBitIndex);
                 }
 
-                OilSourceStatus.Circulate.IsLoadPressure = _PLCConnect.ReadBit(oilSourceConfig.CirculateAddress.IsLoadAddress, oilSourceConfig.CirculateAddress.IsLoadBitIndex);
+                OilSourceStatus.Circulate.IsLoadPressure = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsLoadAddress, ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsLoadBitIndex);
 
-                OilSourceStatus.Circulate.IsStart = _PLCConnect.ReadBit(oilSourceConfig.CirculateAddress.IsStartAddress, oilSourceConfig.CirculateAddress.IsStartBitIndex);
+                OilSourceStatus.Circulate.IsStart = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsStartAddress, ServiceOilSourceConfigViewModel.Instance.CirculateAddress.IsStartBitIndex);
 
 
-                OilSourceStatus.Forerunner.IsStart = _PLCConnect.ReadBit(oilSourceConfig.ForerunnerAddress.IsStartAddress, oilSourceConfig.ForerunnerAddress.IsStartBitIndex);
-                OilSourceStatus.Forerunner.IsLoadPressure = _PLCConnect.ReadBit(oilSourceConfig.ForerunnerAddress.IsLoadAddress, oilSourceConfig.ForerunnerAddress.IsLoadBitIndex);
+                OilSourceStatus.Forerunner.IsStart = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsStartAddress, ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsStartBitIndex);
+                OilSourceStatus.Forerunner.IsLoadPressure = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsLoadAddress, ServiceOilSourceConfigViewModel.Instance.ForerunnerAddress.IsLoadBitIndex);
                 for (int i = 0; i < OilSourceStatus.OilErrors.Count; i++)
                 {
-                    OilSourceStatus.OilErrors[i].Status = _PLCConnect.ReadBit(oilSourceConfig.ErrorAddress[i].Address, oilSourceConfig.ErrorAddress[i].BitIndex);
+                    OilSourceStatus.OilErrors[i].Status = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.ErrorAddress[i].Address, ServiceOilSourceConfigViewModel.Instance.ErrorAddress[i].BitIndex);
                 }
-                OilSourceStatus.IsRemote = _PLCConnect.ReadBit(oilSourceConfig.IsRemoteAddress.Address, oilSourceConfig.IsRemoteAddress.BitIndex);
+                OilSourceStatus.IsRemote = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.IsRemoteAddress.Address, ServiceOilSourceConfigViewModel.Instance.IsRemoteAddress.BitIndex);
                 for (int i = 0; i < OilSourceStatus.OilSourceAnalogs.Count; i++)
                 {
-                    OilSourceStatus.OilSourceAnalogs[i].Value = _PLCConnect.Read<float>(oilSourceConfig.AnalogAddress[i].ValueAddress);
-                    OilSourceStatus.OilSourceAnalogs[i].IsLowerError = _PLCConnect.ReadBit(oilSourceConfig.AnalogAddress[i].LowerErrorAddress, oilSourceConfig.AnalogAddress[i].LowerErrorBitIndex);
-                    OilSourceStatus.OilSourceAnalogs[i].IsLowerWarn = _PLCConnect.ReadBit(oilSourceConfig.AnalogAddress[i].LowerWarnAddress, oilSourceConfig.AnalogAddress[i].LowerWarnBitIndex);
-                    OilSourceStatus.OilSourceAnalogs[i].IsUpperError = _PLCConnect.ReadBit(oilSourceConfig.AnalogAddress[i].UpperErrorAddress, oilSourceConfig.AnalogAddress[i].UpperErrorBitIndex);
-                    OilSourceStatus.OilSourceAnalogs[i].IsUpperWarn = _PLCConnect.ReadBit(oilSourceConfig.AnalogAddress[i].UpperWarnAddress, oilSourceConfig.AnalogAddress[i].UpperWarnBitIndex);
+                    OilSourceStatus.OilSourceAnalogs[i].Value = _PLCConnect.Read<float>(ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].ValueAddress);
+                    OilSourceStatus.OilSourceAnalogs[i].IsLowerError = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].LowerErrorAddress, ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].LowerErrorBitIndex);
+                    OilSourceStatus.OilSourceAnalogs[i].IsLowerWarn = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].LowerWarnAddress, ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].LowerWarnBitIndex);
+                    OilSourceStatus.OilSourceAnalogs[i].IsUpperError = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].UpperErrorAddress, ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].UpperErrorBitIndex);
+                    OilSourceStatus.OilSourceAnalogs[i].IsUpperWarn = _PLCConnect.ReadBit(ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].UpperWarnAddress, ServiceOilSourceConfigViewModel.Instance.AnalogAddress[i].UpperWarnBitIndex);
                 }
                 Communication.Instance.Context.GetEvent<OilSourceStatusModel>()?.Publish(this, OilSourceStatus);
             }

+ 0 - 93
Shaker/OilSource/OilSourceConfig.cs

@@ -1,93 +0,0 @@
-
-using Shaker.Models;
-
-namespace ShakerService.OilSource
-{
-    public class OilSourceConfig : BaseModel
-    {
-        /// <summary>
-        /// 是否启用
-        /// </summary>
-        public bool IsEnabled = true;
-        /// <summary>
-        /// 油源IP地址
-        /// </summary>
-        public string IP = "127.0.0.1";
-        /// <summary>
-        /// 端口号
-        /// </summary>
-        public int Port = 502;
-        /// <summary>
-        /// 开关控制逻辑
-        /// </summary>
-        public LevelLogic LevelLogic = LevelLogic.Edge;
-        /// <summary>
-        /// 电平保持时间
-        /// </summary>
-        public int LevelTime = 50;
-        /// <summary>
-        /// 通信协议
-        /// </summary>
-        public IPLCConnect.PLCProtocol Protocol = IPLCConnect.PLCProtocol.S7;
-        /// <summary>
-        /// 主油泵地址
-        /// </summary>
-        public List<OilSourcePumpAddressConfig> MainPumpAddress = new List<OilSourcePumpAddressConfig>();
-        /// <summary>
-        /// 先导泵地址
-        /// </summary>
-        public OilSourcePumpAddressConfig ForerunnerAddress = new OilSourcePumpAddressConfig();
-        /// <summary>
-        /// 循环泵地址
-        /// </summary>
-        public OilSourcePumpAddressConfig CirculateAddress = new OilSourcePumpAddressConfig();
-        /// <summary>
-        /// 辅助油路地址
-        /// </summary>
-        public OilSourcePumpAddressConfig AssistantAddress = new OilSourcePumpAddressConfig();
-
-        /// <summary>
-        /// 远程/本地地址
-        /// </summary>
-        public BitAddressConfig IsRemoteAddress = new BitAddressConfig();
-        /// <summary>
-        /// 急停地址
-        /// </summary>
-        public BitAddressConfig EmergencyStopAddress = new BitAddressConfig();
-        /// <summary>
-        /// 模拟量地址
-        /// </summary>
-        public List<OilSourceAnalogAddressConfig> AnalogAddress = new List<OilSourceAnalogAddressConfig>();
-        /// <summary>
-        /// 错误信息地址
-        /// </summary>
-        public List<BitAddressConfig> ErrorAddress = new List<BitAddressConfig>();
-        public static OilSourceConfig ReadConfig()
-        {
-            Communication.Instance.DbConnection.CreateTable<OilSourceConfig>();
-            var config= Communication.Instance.DbConnection.Query<OilSourceConfig>($"SELECT * FROM {nameof(OilSourceConfig)} LIMIT 1")?.FirstOrDefault();
-            config ??= new OilSourceConfig();
-            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName:nameof(MainPumpAddress));
-            config.MainPumpAddress.AddRange(Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(MainPumpAddress)}") ?? new List<OilSourcePumpAddressConfig>());
-            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(ForerunnerAddress));
-            config.ForerunnerAddress = Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(ForerunnerAddress)} limit 1")?.FirstOrDefault() ?? new OilSourcePumpAddressConfig();
-            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(CirculateAddress));
-            config.CirculateAddress = Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(CirculateAddress)} limit 1")?.FirstOrDefault() ?? new OilSourcePumpAddressConfig();
-            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(AssistantAddress));
-            config.AssistantAddress = Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(AssistantAddress)} limit 1")?.FirstOrDefault() ?? new OilSourcePumpAddressConfig();
-            Communication.Instance.DbConnection.CreateTable<BitAddressConfig>(tableName: nameof(IsRemoteAddress));
-            config.IsRemoteAddress = Communication.Instance.DbConnection.Query<BitAddressConfig>($"select * from {nameof(IsRemoteAddress)} limit 1")?.FirstOrDefault() ?? new BitAddressConfig();
-            Communication.Instance.DbConnection.CreateTable<BitAddressConfig>(tableName: nameof(EmergencyStopAddress));
-            config.EmergencyStopAddress = Communication.Instance.DbConnection.Query<BitAddressConfig>($"select * from {nameof(EmergencyStopAddress)} limit 1")?.FirstOrDefault() ?? new BitAddressConfig();
-            Communication.Instance.DbConnection.CreateTable<OilSourceAnalogAddressConfig>(tableName: nameof(AnalogAddress));
-            config.AnalogAddress.AddRange(Communication.Instance.DbConnection.Query<OilSourceAnalogAddressConfig>($"select * from {nameof(AnalogAddress)}") ?? new List<OilSourceAnalogAddressConfig>());
-            Communication.Instance.DbConnection.CreateTable<BitAddressConfig>(tableName: nameof(ErrorAddress));
-            config.ErrorAddress.AddRange(Communication.Instance.DbConnection.Query<BitAddressConfig>($"select * from {nameof(ErrorAddress)}") ?? new List<BitAddressConfig>());
-            return config;
-        }
-        public override object Clone()
-        {
-            return this.CloneBase();
-        }
-    }
-}

+ 4 - 3
Shaker/Program.cs

@@ -1,5 +1,6 @@
 using FxpConvert.Common;
 using Microsoft.CodeAnalysis;
+using ShakerService.Tools;
 using System.Diagnostics;
 using System.Numerics;
 using System.Reflection;
@@ -13,16 +14,16 @@ namespace ShakerService
     {
         static  void Main(string[] args)
         {
-            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
             try
             {
+                Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
                 Service service = new Service();
                 service.Init();
                 service.StartService();
             }
-            catch
+            catch(Exception ex)
             {
-
+                Log.Default.Info(ex.Message);
             }
             Thread.Sleep(-1);
         }

+ 2 - 1
Shaker/Service.cs

@@ -35,7 +35,6 @@ namespace ShakerService
                 });
             InitControl();
             
-            //var psd =  ServiceRandomConfigViewModel.Instance.RandomData.CalcPSD(data);
             ServiceShakerConfigViewModel.Instance.CreateTime = dateTime;
         }
 
@@ -254,6 +253,7 @@ namespace ShakerService
             ServiceDataCacheViewModel.Instance.CurrentTestType = Data.TestType.Sine;
             ServiceDataCacheViewModel.Instance.IsSignalStart = false;
             ShakerFpga.Instance.Start.Value = false;
+            ShakerFpga.Instance.ValvePower.Value = false;
             ShakerFpga.Instance.SignalStop.Value = true;
             ShakerFpga.Instance.SignalStart.Value = false;
             ServiceShakerControlViewModel.Instance.OutSignal = false;
@@ -270,6 +270,7 @@ namespace ShakerService
             ServiceDataCacheViewModel.Instance.CurrentTestType = Data.TestType.Sine;
             ServiceDataCacheViewModel.Instance.IsSignalStart = false;
             ShakerFpga.Instance.Start.Value = false;
+            ShakerFpga.Instance.ValvePower.Value = false;
             ShakerFpga.Instance.SignalStop.Value = true;
             ShakerFpga.Instance.SignalStart.Value = false;
             ServiceShakerControlViewModel.Instance.SelfLoop = false;

+ 1 - 0
Shaker/ShakerService.Control.cs

@@ -63,6 +63,7 @@ namespace ShakerService
                     ShakerStatus = ServiceShakerStatusViewModel.Instance.Model,
                     RandomConfig = ServiceRandomConfigViewModel.Instance.Model,
                     ShakerChannel = ServiceShakerChannelViewModel.Instance.Model,
+                    OilSourceConfig = ServiceOilSourceConfigViewModel.Instance.Model,
                 };
                 Log.Default.Info("同步参数");
                 return config;

+ 1 - 0
Shaker/ShakerService.ReadFifo.cs

@@ -196,6 +196,7 @@ namespace ShakerService
                                     ServiceRandomConfigViewModel.Instance.RandomData.AddDriverPSD(data, true);
                                     ServiceRandomConfigViewModel.Instance.RandomData.CalcRandomTestDriver(ref isstop, ref drver);
                                     ServiceRandomConfigViewModel.Instance.RandomData.CurrentTestTime += ServiceConfigViewModel.Instance.ReadFrameCount;
+                                    ServiceRandomConfigViewModel.Instance.RandomData.TestTotalRunTime += ServiceConfigViewModel.Instance.ReadFrameCount;
                                     uint count = 0;
                                     ShakerFpga.Instance.Read.Write(ref drver[0],0,(uint)drver.Length,ref count);
                                     if(isstop)

+ 6 - 3
Shaker/Tools/Log.cs

@@ -1,4 +1,5 @@
-using System;
+using log4net;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
@@ -12,6 +13,8 @@ namespace ShakerService.Tools
         private Log()
         {
             log = log4net.LogManager.GetLogger(typeof(Service));
+            System.IO.FileInfo file = new System.IO.FileInfo(AppDomain.CurrentDomain.BaseDirectory + @"log4net.config");
+            log4net.Config.XmlConfigurator.ConfigureAndWatch(LogManager.GetRepository(typeof(Service).Assembly), file);
         }
         static Log()
         {
@@ -22,10 +25,10 @@ namespace ShakerService.Tools
             log.Info($"{DateTime.Now}:{msg}");
             Debug(msg);
         }
-        public void Debug(string msg)
+        private void Debug(string msg)
         {
 #if DEBUG
-            log.Debug($"{DateTime.Now}:{msg}");
+            //log.Debug($"{DateTime.Now}:{msg}");
             if(System.Console.IsOutputRedirected)
             {
                 System.Diagnostics.Debug.WriteLine($"{DateTime.Now}:{msg}");

+ 89 - 0
Shaker/ViewModel/ServiceOilSourceConfigViewModel.cs

@@ -0,0 +1,89 @@
+using IPLCConnect;
+using Shaker.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ShakerService.ViewModel
+{
+    internal class ServiceOilSourceConfigViewModel:BaseServiceViewModel<OilSourceConfig>
+    {
+        private ServiceOilSourceConfigViewModel()
+        {
+            Communication.Instance.DbConnection.CreateTable<OilSourceConfig>();
+            var config = Communication.Instance.DbConnection.Query<OilSourceConfig>($"SELECT * FROM {nameof(OilSourceConfig)} LIMIT 1")?.FirstOrDefault();
+            config ??= new OilSourceConfig();
+            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(MainPumpAddress));
+            config.MainPumpAddress.AddRange(Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(MainPumpAddress)}")?.Where(x => !string.IsNullOrEmpty(x.Address) && x.IsEnabled).ToList() ?? new List<OilSourcePumpAddressConfig>());
+            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(ForerunnerAddress));
+            config.ForerunnerAddress = Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(ForerunnerAddress)} limit 1")?.FirstOrDefault() ?? new OilSourcePumpAddressConfig();
+            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(CirculateAddress));
+            config.CirculateAddress = Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(CirculateAddress)} limit 1")?.FirstOrDefault() ?? new OilSourcePumpAddressConfig();
+            Communication.Instance.DbConnection.CreateTable<OilSourcePumpAddressConfig>(tableName: nameof(AssistantAddress));
+            config.AssistantAddress = Communication.Instance.DbConnection.Query<OilSourcePumpAddressConfig>($"select * from {nameof(AssistantAddress)} limit 1")?.FirstOrDefault() ?? new OilSourcePumpAddressConfig();
+            Communication.Instance.DbConnection.CreateTable<BitAddressConfig>(tableName: nameof(IsRemoteAddress));
+            config.IsRemoteAddress = Communication.Instance.DbConnection.Query<BitAddressConfig>($"select * from {nameof(IsRemoteAddress)} limit 1")?.FirstOrDefault() ?? new BitAddressConfig();
+            Communication.Instance.DbConnection.CreateTable<BitAddressConfig>(tableName: nameof(EmergencyStopAddress));
+            config.EmergencyStopAddress = Communication.Instance.DbConnection.Query<BitAddressConfig>($"select * from {nameof(EmergencyStopAddress)} limit 1")?.FirstOrDefault() ?? new BitAddressConfig();
+            Communication.Instance.DbConnection.CreateTable<OilSourceAnalogAddressConfig>(tableName: nameof(AnalogAddress));
+            config.AnalogAddress.AddRange(Communication.Instance.DbConnection.Query<OilSourceAnalogAddressConfig>($"select * from {nameof(AnalogAddress)}")?.Where(x => !string.IsNullOrEmpty(x.ValueAddress) && !string.IsNullOrEmpty(x.Name)).ToList() ?? new List<OilSourceAnalogAddressConfig>());
+            Communication.Instance.DbConnection.CreateTable<BitAddressConfig>(tableName: nameof(ErrorAddress));
+            config.ErrorAddress.AddRange(Communication.Instance.DbConnection.Query<BitAddressConfig>($"select * from {nameof(ErrorAddress)}")?.Where(x => !string.IsNullOrEmpty(x.Address)).ToList() ?? new List<BitAddressConfig>());
+            UpModel(config);
+            Communication.Instance.Context?.GetEvent<OilSourceConfig>()?.Subscrip((sender, args) =>
+            {
+                OilSource.OilSource.Default.Disconnect();
+                var c = args.Data;
+                c.AnalogAddress = c.AnalogAddress.Where(x => !string.IsNullOrEmpty(x.ValueAddress) && !string.IsNullOrEmpty(x.Name)).ToList();
+                c.MainPumpAddress = c.MainPumpAddress.Where(x => !string.IsNullOrEmpty(x.Address) && x.IsEnabled).ToList();
+                c.ErrorAddress = c.ErrorAddress.Where(x => !string.IsNullOrEmpty(x.Address)).ToList();
+                UpModel(c);
+                SaveData();
+                OilSource.OilSource.Default.ChangedPLCConfig();
+            });
+            
+        }
+        static ServiceOilSourceConfigViewModel()
+        {
+
+        }
+        private protected override void SaveData()
+        {
+            base.SaveData();
+            Communication.Instance.DbConnection.DeleteAll<OilSourcePumpAddressConfig>(tableName: nameof(MainPumpAddress));
+            Communication.Instance.DbConnection.InsertAll(MainPumpAddress, tableName: nameof(MainPumpAddress));
+            Communication.Instance.DbConnection.DeleteAll<OilSourcePumpAddressConfig>(tableName: nameof(ForerunnerAddress));
+            Communication.Instance.DbConnection.Insert(ForerunnerAddress, tableName: nameof(ForerunnerAddress));
+            Communication.Instance.DbConnection.DeleteAll<OilSourcePumpAddressConfig>(tableName: nameof(CirculateAddress));
+            Communication.Instance.DbConnection.Insert(CirculateAddress, tableName: nameof(CirculateAddress));
+            Communication.Instance.DbConnection.DeleteAll<OilSourcePumpAddressConfig>(tableName: nameof(AssistantAddress));
+            Communication.Instance.DbConnection.Insert(AssistantAddress, tableName: nameof(AssistantAddress));
+            Communication.Instance.DbConnection.DeleteAll<BitAddressConfig>(tableName: nameof(IsRemoteAddress));
+            Communication.Instance.DbConnection.Insert(IsRemoteAddress, tableName: nameof(IsRemoteAddress));
+            Communication.Instance.DbConnection.DeleteAll<BitAddressConfig>(tableName: nameof(EmergencyStopAddress));
+            Communication.Instance.DbConnection.Insert(EmergencyStopAddress, tableName: nameof(EmergencyStopAddress));
+            Communication.Instance.DbConnection.DeleteAll<OilSourceAnalogAddressConfig>(tableName: nameof(AnalogAddress));
+            Communication.Instance.DbConnection.InsertAll(AnalogAddress, tableName: nameof(AnalogAddress));
+            Communication.Instance.DbConnection.DeleteAll<BitAddressConfig>(tableName: nameof(ErrorAddress));
+            Communication.Instance.DbConnection.InsertAll(ErrorAddress, tableName: nameof(ErrorAddress));
+
+        }
+        public bool IsEnabled => Model.IsEnabled;
+        public string IP => Model.IP;
+        public int Port => Model.Port;
+        public LevelLogic LevelLogic => Model.LevelLogic;
+        public int LevelTime => Model.LevelTime;
+        public PLCProtocol Protocol => Model.Protocol;
+        public List<OilSourcePumpAddressConfig> MainPumpAddress =>Model.MainPumpAddress;
+        public OilSourcePumpAddressConfig ForerunnerAddress => Model.ForerunnerAddress;
+        public OilSourcePumpAddressConfig CirculateAddress => Model.CirculateAddress;
+        public OilSourcePumpAddressConfig AssistantAddress => Model.AssistantAddress;
+        public BitAddressConfig IsRemoteAddress => Model.IsRemoteAddress;
+        public BitAddressConfig EmergencyStopAddress => Model.EmergencyStopAddress;
+        public List<OilSourceAnalogAddressConfig> AnalogAddress => Model.AnalogAddress;
+        public List<BitAddressConfig> ErrorAddress => Model.ErrorAddress;
+        public static ServiceOilSourceConfigViewModel Instance { get; } = new ServiceOilSourceConfigViewModel();
+    }
+}

+ 8 - 6
Shaker/ViewModel/ServiceRandomConfigViewModel.cs

@@ -12,7 +12,8 @@ namespace ShakerService.ViewModel
 {
     internal class ServiceRandomConfigViewModel:BaseServiceViewModel<RandomConfigModel>
     {
-        
+
+        public double[] BilateralPSDWindow { get; private set; } = new double[0];
         public double[] PSDWindow { get;private set;} = new double[0];
         public double[] FixedWindow { get; private set; } = new double[0];
         public double HanningWindowCompensationCoefficient => Model.HanningWindowCompensationCoefficient;
@@ -128,16 +129,17 @@ namespace ShakerService.ViewModel
             FFTFrameLength = (uint)((double)RandomSampleRate / MaxFrequency * SpectrumLines);
             FFTHalfFrameLength = FFTFrameLength >> 1;
             PSDWindow = Enumerable.Range(0, (int)FFTHalfFrameLength).Select(x => (x * FrequencyResolution >= MinFrequency && x * FrequencyResolution <= MaxFrequency) ? 1d : 0d).ToArray();
+            BilateralPSDWindow = Shaker.Models.Tools.Tools.UnilateralSpectrumToBilateralSpectrum(PSDWindow);
             FixedWindow = Enumerable.Repeat(1d, (int)FFTFrameLength).ToArray();
-            StartWindow = new double[FFTHalfFrameLength];
-            StopWindow = new double[FFTHalfFrameLength];
-            for(int i=0;i< FFTHalfFrameLength; i++)
+            StartWindow = new double[FFTFrameLength];
+            StopWindow = new double[FFTFrameLength];
+            for(int i=0;i< FFTFrameLength; i++)
             {
-                double d = i * double.Pi / (FFTHalfFrameLength << 1);
+                double d = i * double.Pi / (FFTFrameLength << 1);
                 StartWindow[i] = Math.Pow(Math.Sin(d),3);
                 StopWindow[i] = Math.Pow(Math.Cos(d), 3);
             }
-            HanningWindow = CalcHanningWindow(FFTHalfFrameLength);
+            HanningWindow = CalcHanningWindow(FFTFrameLength);
         }
         private double[] CalcHanningWindow(uint count)
         {

+ 17 - 7
Shaker/ViewModel/ServiceRandomDataViewModel.cs

@@ -22,6 +22,7 @@ namespace ShakerService.ViewModel
             CurrentTestLevel = ServiceRandomConfigViewModel.Instance.PlanItems.First().Level;
             CurrentLevelIndex = 0;
             CurrentTestTime = 0;
+            TestTotalRunTime = 0;
             CurrentLevelTestMaxTime = ServiceRandomConfigViewModel.Instance.PlanItems.First().Time;
         }
         private bool GetNextLevel()
@@ -37,6 +38,8 @@ namespace ShakerService.ViewModel
             CurrentTestTime = 0;
             return false;
         }
+
+        public uint TestTotalRunTime { get => Model.TestTotalRunTime; set => Model.TestTotalRunTime = value; }
         private double[] UpWarnLevel = new double[0];
         private double[] UpStopLevel = new double[0];
         private double[] DownWarnLevel = new double[0];
@@ -52,6 +55,7 @@ namespace ShakerService.ViewModel
         public int IdentifyIndex { get => Model.IdentifyIndex; set => Model.IdentifyIndex = value; }
         public List<double[]> CurrentAccelerationPSD { get => Model.CurrentAccelerationPSD; set => Model.CurrentAccelerationPSD = value; }
         public List<double> CurrentAccelerationSpectrumRMS { get; } = new List<double>();
+        public bool ShowLevelControl => RandomTestStep == RandomTestStep.Test;
         public RandomTestStep RandomTestStep { get => Model.RandomTestStep; set => Model.RandomTestStep = value; }
         public double[] CurrentAccelerationSynthesisPSD { get => Model.CurrentAccelerationSynthesisPSD; set => Model.CurrentAccelerationSynthesisPSD = value; }
 
@@ -224,16 +228,22 @@ namespace ShakerService.ViewModel
         }
         private void CalcRandomTestDriver(double level,ref double[] result)
         {
-            double[] real = new double[TransferFunction.Length];
+            double[] tempreal = new double[TransferFunction.Length];
             double[] img = new double[TransferFunction.Length];
-            ServiceDataCacheViewModel.Instance.Calc.Division.Division(ref Model.TransferFunction[0], ref Model.CurrentAccelerationSynthesisPSD[0], (uint)TransferFunction.Length,ref real[0]);
-            ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref real[0], level, (uint)real.Length);
-            double[] whitenoise = CalcWhiteNoiseFFT().Select(x=>x.Magnitude).ToArray();
+            ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref Model.TransferFunction[0], ref Model.CurrentAccelerationSynthesisPSD[0], (uint)TransferFunction.Length,ref tempreal[0]);
+            for(int i=0;i<tempreal.Length;i++)
+            {
+                tempreal[i] = (double.IsNaN(tempreal[i]) || double.IsInfinity(tempreal[i]) || tempreal[i] == 0) ? 8E-14 : tempreal[i];
+            }
+            ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref tempreal[0], level, (uint)tempreal.Length);
+            double[] real = Shaker.Models.Tools.Tools.UnilateralSpectrumToBilateralSpectrum(tempreal);
+            double[] whitenoise = CalcWhiteNoiseFFT().Select(x=>x.Real).ToArray();
             ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref real[0], ref whitenoise[0], (uint)real.Length);
             double rms = Math.Abs(ServiceDataCacheViewModel.Instance.Calc.Sum.Rms(ref real[0], (uint)real.Length))*ServiceRandomConfigViewModel.Instance.Sigma;
             ServiceDataCacheViewModel.Instance.Calc.Clamp.Clamp(ref real[0], -rms, rms, (uint)real.Length);
+            img = new double[result.Length];
             ServiceDataCacheViewModel.Instance.Calc.FFT.IFFT(real, img);
-            ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref real[0], ref ServiceRandomConfigViewModel.Instance.PSDWindow[0], (uint)real.Length);
+            ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref real[0], ref ServiceRandomConfigViewModel.Instance.BilateralPSDWindow[0], (uint)real.Length);
             ServiceDataCacheViewModel.Instance.Calc.FFT.FFT(real, img);
             result = new double[real.Length * ServiceShakerConfigViewModel.Instance.SampleRate / ServiceRandomConfigViewModel.Instance.RandomSampleRate];
             var linear = MathNet.Numerics.Interpolate.Linear(Enumerable.Range(0, real.Length).Select(x => (double)x), real);
@@ -242,7 +252,7 @@ namespace ShakerService.ViewModel
                 result[i] = linear.Interpolate((double)i / result.Length * real.Length);
             };
         }
-        private Complex[] CalcWhiteNoiseFFT()
+        public Complex[] CalcWhiteNoiseFFT()
         {
             Complex[] data = new Complex[ServiceRandomConfigViewModel.Instance.FFTFrameLength];
             Random rdm = new Random();
@@ -258,7 +268,7 @@ namespace ShakerService.ViewModel
         }
         public double[] CalcPSD(double[] data)
         {
-            double[] result = new double[ServiceRandomConfigViewModel.Instance.FFTHalfFrameLength];
+            double[] result = new double[ServiceRandomConfigViewModel.Instance.FFTFrameLength];
             for (int i = 0; i < result.Length; i++)
             {
                 result[i] = data[i * ServiceShakerConfigViewModel.Instance.SampleRate / ServiceRandomConfigViewModel.Instance.RandomSampleRate];

+ 29 - 11
Shaker/log4net.config

@@ -1,12 +1,30 @@
 <?xml version="1.0" encoding="utf-8" ?>
-<log4net>
-  <root>
-    <level value="DEBUG" />
-    <appender-ref ref="consoleAppender" />
-  </root>
-  <appender name="consoleAppender" type="log4net.Appender.ConsoleAppender">
-    <layout type="log4net.Layout.PatternLayout">
-      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
-    </layout>
-  </appender>
-</log4net>
+<configuration>
+  <configSections>
+    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
+  </configSections>
+  <log4net debug="true">
+    <root>
+      <level value="DEBUG" />
+      <appender-ref ref="RollingLogFileAppender" />
+      <appender-ref ref="ConsoleAppender" />
+    </root>
+    <appender name="ConsoleAppender"  type="log4net.Appender.ConsoleAppender" >
+      <layout type="log4net.Layout.PatternLayout">
+        <conversionPattern value="[%date] %level [%thread][%c{1}:%line] - %m%n" />
+      </layout>
+    </appender>
+    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender" >
+      <param name="File" value="Log/"/>
+      <param name="DatePattern" value="'Shaker 'yyyy-MM-dd'.log'"/>
+      <param name="StaticLogFileName" value ="false"/>
+      <param name="AppendToFile" value="true" />
+      <param name="rollingStyle" value="Composite" />
+      <param name="maxSizeRollBackups" value="-1"/>
+      <param name="maximumFileSize" value="10MB"/>
+      <layout type="log4net.Layout.PatternLayout">
+        <conversionPattern value="[%date] %level [%thread][%c{1}:%line] - %m%n" />
+      </layout>
+    </appender>
+  </log4net>
+</configuration>