From 63afb2dcfba5bdb87c61aad775350a8f2e903155 Mon Sep 17 00:00:00 2001 From: meelstorm <8780022+TesAnti@users.noreply.github.com> Date: Wed, 1 Oct 2025 08:17:10 +0200 Subject: [PATCH] 1.0.6 --- .../Program.cs | 19 ++++-- .../HawkeyeCameraImageSource.cs | 11 ++-- .../Modules/Barcode/CandyboxBarcodeReader.cs | 60 +++++++++++++------ .../Modules/CandyboxImageProcessingControl.cs | 2 +- Plugins/CandyboxPlugin/Plugin.cs | 9 ++- Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs | 3 + .../PackstrasseBarcodeReaderModule.cs | 19 +++--- .../BaseRecognitionControlSettings.cs | 6 +- VisionBuilder.UI.Common/UIConfiguration.cs | 6 ++ .../ViewModel/ErrorPreviewVM.cs | 2 +- .../ViewModel/SingleCameraVM.cs | 13 +++- .../ModuleExtensions.cs | 2 +- .../VisionBuilderStatistics.cs | 59 +++++++++++++++--- .../Form1.Designer.cs | 7 ++- VisionBuilder.UI.Windows.Test/Form1.cs | 2 + .../VisionBuilder.UI.Windows.Uno.csproj | 2 +- .../Components/SingleCameraControl.cs | 1 + 17 files changed, 168 insertions(+), 55 deletions(-) diff --git a/Hawkeye.VisionBuilder.UI.RecipeConverter/Program.cs b/Hawkeye.VisionBuilder.UI.RecipeConverter/Program.cs index 2e709b7..96ccebf 100644 --- a/Hawkeye.VisionBuilder.UI.RecipeConverter/Program.cs +++ b/Hawkeye.VisionBuilder.UI.RecipeConverter/Program.cs @@ -1,11 +1,22 @@ using System.Xml; using Hawkeye.VisionBuilder.Workflow; -WorkflowList workflowList = new WorkflowList(); -var file = File.OpenRead("gold_b97.hrcp"); -using (var br = new BinaryReader(file)) +var files = Directory.GetFiles(AppContext.BaseDirectory, "*.hrcp", SearchOption.TopDirectoryOnly); +foreach (var file in files) { - workflowList.Load(br,new OperationDiscoveryService(workflowList)); + try + { + Console.WriteLine($"Converting {file}"); + var f = File.OpenRead(file); + WorkflowList list = new WorkflowList(); + list.Load(new BinaryReader(f),new OperationDiscoveryService(list)); + list.SaveJSON(Path.GetFileNameWithoutExtension(file)+".jhrcp"); + } + catch (Exception ex) + { + Console.WriteLine($"Error processing file {file}: {ex.Message}"); + } } + diff --git a/Hawkeye.VisionBuilder.UI.Sources.Hawkeye/HawkeyeCameraImageSource.cs b/Hawkeye.VisionBuilder.UI.Sources.Hawkeye/HawkeyeCameraImageSource.cs index da8409d..f008a15 100644 --- a/Hawkeye.VisionBuilder.UI.Sources.Hawkeye/HawkeyeCameraImageSource.cs +++ b/Hawkeye.VisionBuilder.UI.Sources.Hawkeye/HawkeyeCameraImageSource.cs @@ -59,10 +59,10 @@ namespace Hawkeye.VisionBuilder.UI.Sources.Hawkeye if (File.Exists(_settings?.SettingsFile)) { _cameraSettings = UICameraSettings.LoadSettingsLocal(_settings.SettingsFile).ToCameraSettings(); - _client.ApplySettings(_cameraSettings); + } - + _client.ApplySettings(_cameraSettings); } public Task GetImage(CancellationToken token) @@ -98,6 +98,7 @@ namespace Hawkeye.VisionBuilder.UI.Sources.Hawkeye try { Log.Debug("Got image on {adapter}", _settings.Adapter); + Log.Debug("Bytes: {bytes}", obj.Length); //FlipLines(obj, _flipBuffer); var pinnedArray = GCHandle.Alloc(obj, GCHandleType.Pinned); @@ -113,10 +114,10 @@ namespace Hawkeye.VisionBuilder.UI.Sources.Hawkeye _cameraSettings.OffsetX; // crop the image with opencv - _lastImage = image[0, _cameraSettings.ImageSettings.Lines, xCrop, - xCrop + _cameraSettings.ImageWidth].Clone(); + //_lastImage = image[0, _cameraSettings.ImageSettings.Lines, xCrop, + // xCrop + _cameraSettings.ImageWidth].Clone(); + _lastImage = image; - if (_cameraSettings.BayerFilter) diff --git a/Plugins/CandyboxPlugin/Modules/Barcode/CandyboxBarcodeReader.cs b/Plugins/CandyboxPlugin/Modules/Barcode/CandyboxBarcodeReader.cs index ab4d37d..f62566d 100644 --- a/Plugins/CandyboxPlugin/Modules/Barcode/CandyboxBarcodeReader.cs +++ b/Plugins/CandyboxPlugin/Modules/Barcode/CandyboxBarcodeReader.cs @@ -13,22 +13,23 @@ public class CandyboxBarcodeReader : IVisionBuilderModule private readonly ILoadingService _loadingService; private readonly CandyboxBarcodeReaderSettings _settings; - private readonly IRecognitionControl _recognitionControl; + private readonly SingleCameraVM _singleCameraVm; private readonly VisionBuilderStatistics _statistics; private SerialPort _port; public EReaderState _readerState = EReaderState.ReadingRecipe; private MaterialCancellableLoader? _loader; - public CandyboxBarcodeReader(CandyboxBarcodeReaderSettings settings, IRecognitionControl recognitionControl, VisionBuilderStatistics statistics) + public CandyboxBarcodeReader(CandyboxBarcodeReaderSettings settings, SingleCameraVM singleCameraVm, VisionBuilderStatistics statistics) { _settings = settings; - _recognitionControl = recognitionControl; + _singleCameraVm = singleCameraVm; _statistics = statistics; } private void _port_DataReceived(object sender, SerialDataReceivedEventArgs e) { - Thread.Sleep(100); + Thread.Sleep(500); + if(_singleCameraVm.IsRunning)return; if(_readerState == EReaderState.ReadingRecipe) ReadRecipe(); if (_readerState == EReaderState.ReadingAUF) @@ -37,14 +38,21 @@ public class CandyboxBarcodeReader : IVisionBuilderModule private void ReadRecipe() { - if (_recognitionControl.IsRunning) return; + if (_singleCameraVm.IsRunning) return; byte[] buffer = new byte[_port.BytesToRead]; _port.Read(buffer, 0, _port.BytesToRead); var data = Encoding.ASCII.GetString(buffer).Trim(); - var recipes = _recognitionControl.GetRecipesData(); + if (string.IsNullOrEmpty(data)) + { + Log.Warning("Received empty recipe"); + return; + } + var vm = _singleCameraVm.GetRecipeSelectionVm(); + var recipes = vm.Recipes; string searchString = data; + Log.Information("Read Recipe: {Recipe}", data); if (_settings.BarcodeRecipeMappings.Any(x => x.Barcode == searchString)) { searchString = _settings.BarcodeRecipeMappings.First(x => x.Barcode == searchString).RecipeName; @@ -56,20 +64,29 @@ public class CandyboxBarcodeReader : IVisionBuilderModule Log.Warning("No matching recipe found for data: {Data}", data); return; } - - _recognitionControl.SetRecipe(existingRecipe); + vm.SelectedRecipe = vm.Recipes.FirstOrDefault(r => r.RecipeName == existingRecipe.RecipeName); + _singleCameraVm.SynchronizationContext!.Post((_) => + { + _loader = new MaterialCancellableLoader(); + _loader.StartLoading("Waiting for AUF..."); + _loader.LoadingCancelled += CancelWaiting; + _singleCameraVm.ProcessRecipeSelectionVm(vm); + }, null); + Application.DoEvents(); _readerState = EReaderState.ReadingAUF; - _loader = new MaterialCancellableLoader(); - _loader.StartLoading("Waiting for AUF..."); - _loader.LoadingCancelled += CancelWaiting; + } private void CancelWaiting(object? sender, string e) { + _singleCameraVm.SynchronizationContext!.Post((_) => + { + _loader.FinishLoading("Waiting for AUF..."); + _loader.LoadingCancelled -= CancelWaiting; + _loader = null; + }, null); _readerState = EReaderState.ReadingRecipe; - _loader.Close(); - _loader.LoadingCancelled -= CancelWaiting; - _loader = null; + } private void ReadAUF() @@ -77,17 +94,22 @@ public class CandyboxBarcodeReader : IVisionBuilderModule byte[] buffer = new byte[_port.BytesToRead]; _port.Read(buffer, 0, _port.BytesToRead); var data = Encoding.ASCII.GetString(buffer).Trim(); + if (string.IsNullOrEmpty(data)) + { + Log.Warning("Received empty AUF"); + return; + } + Log.Information("Read AUF: {AUF}", data); if (_loader != null) { - _loader.Close(); - _loader.LoadingCancelled -= CancelWaiting; - _loader = null; + CancelWaiting(this, string.Empty); } _statistics.Metadata = data; - _recognitionControl.Start(); - _readerState = EReaderState.ReadingAUF; + _=_singleCameraVm.Start().ConfigureAwait(false); + Application.DoEvents(); + _readerState = EReaderState.ReadingRecipe; } diff --git a/Plugins/CandyboxPlugin/Modules/CandyboxImageProcessingControl.cs b/Plugins/CandyboxPlugin/Modules/CandyboxImageProcessingControl.cs index e15a9a3..efdda64 100644 --- a/Plugins/CandyboxPlugin/Modules/CandyboxImageProcessingControl.cs +++ b/Plugins/CandyboxPlugin/Modules/CandyboxImageProcessingControl.cs @@ -94,7 +94,7 @@ public class CandyboxImageProcessingControl : BaseRecognitionControl swTotal.Stop(); var allErrors = - res.ErrorPoints.Select(x => x.ToString()) + res.ErrorPoints.Select(x => "Position "+x.ToString()) .Concat( res.ErrorReason.Where(x=>x != EErrorReason.Good).Select(x=>x.ToString()) ).ToArray(); diff --git a/Plugins/CandyboxPlugin/Plugin.cs b/Plugins/CandyboxPlugin/Plugin.cs index 2d4adec..d445731 100644 --- a/Plugins/CandyboxPlugin/Plugin.cs +++ b/Plugins/CandyboxPlugin/Plugin.cs @@ -3,6 +3,7 @@ using Inspectron.Settings; using Ninject; using System.Reflection; using CandyboxPlugin.Modules.Barcode; +using Ninject.Planning.Bindings; using VisionBuilder.UI.Common; using VisionBuilder.UI.Common.Plugins; using VisionBuilder.UI.Common.Processing; @@ -21,7 +22,13 @@ namespace CandyboxPlugin public void RegisterCameraModules(IKernel kernel, string cameraName) { - kernel.Bind().ToConstant(new CandyboxRecognitionControlSettings(cameraName)); + + // remove settings binding + var existingRecognitionControlSettings = kernel.GetBindings(typeof(BaseRecognitionControlSettings)).First(); + var toRemove = kernel.GetBindings(typeof(ISettings)).First(x => x.ProviderCallback.Target == existingRecognitionControlSettings.ProviderCallback.Target); + kernel.RemoveBinding(toRemove); + + kernel.Bind().ToConstant(new CandyboxRecognitionControlSettings(cameraName)); kernel.Rebind().To().InSingletonScope(); diff --git a/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs b/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs index f1fa630..10b3271 100644 --- a/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs +++ b/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs @@ -477,6 +477,8 @@ namespace CandyboxPlugin.Recipe if(_learnedParameters.CandyParameters.Count==0)errorReason.Add(EErrorReason.NotLearned); + Thread.Sleep(50); + return new ProcessingResult(framedImage, final, _learnedParameters.CandyParameters.Count == 0 || wasError, (int) sw.ElapsedMilliseconds, errorReason) @@ -487,6 +489,7 @@ namespace CandyboxPlugin.Recipe } catch(Exception ex) { + Thread.Sleep(50); return new ProcessingResult(image, image, true, (int)sw.ElapsedMilliseconds, new List() {EErrorReason.Unknown}) diff --git a/Plugins/Pralinen/PackstrasseBarcodeReader/PackstrasseBarcodeReaderModule.cs b/Plugins/Pralinen/PackstrasseBarcodeReader/PackstrasseBarcodeReaderModule.cs index 09d937d..6afa855 100644 --- a/Plugins/Pralinen/PackstrasseBarcodeReader/PackstrasseBarcodeReaderModule.cs +++ b/Plugins/Pralinen/PackstrasseBarcodeReader/PackstrasseBarcodeReaderModule.cs @@ -10,14 +10,15 @@ namespace PackstrasseBarcodeReader public class PackstrasseBarcodeReaderModule : IVisionBuilderModule { private readonly PackstrasseBarcodeReaderSettings _settings; - private readonly IRecognitionControl _recognitionControl; + private readonly SingleCameraVM _singleCameraVm; private SerialPort _port; - public PackstrasseBarcodeReaderModule(PackstrasseBarcodeReaderSettings settings, IRecognitionControl recognitionControl) + public PackstrasseBarcodeReaderModule(PackstrasseBarcodeReaderSettings settings, SingleCameraVM singleCameraVm) { _settings = settings; - _recognitionControl = recognitionControl; + _singleCameraVm = singleCameraVm; + } private void _port_DataReceived(object sender, SerialDataReceivedEventArgs e) @@ -26,7 +27,8 @@ namespace PackstrasseBarcodeReader byte[] buffer = new byte[_port.BytesToRead]; _port.Read(buffer, 0, _port.BytesToRead); var data = Encoding.ASCII.GetString(buffer).Trim(); - var recipes = _recognitionControl.GetRecipesData(); + var vm = _singleCameraVm.GetRecipeSelectionVm(); + string searchString = data; if (_settings.BarcodeRecipeMappings.Any(x=>x.Barcode==searchString)) @@ -34,14 +36,17 @@ namespace PackstrasseBarcodeReader searchString = _settings.BarcodeRecipeMappings.First(x => x.Barcode == searchString).RecipeName; } - var existingRecipe=recipes.FirstOrDefault(x => x.RecipeName == searchString); + var existingRecipe= vm.Recipes.FirstOrDefault(x => x.RecipeName == searchString); if (existingRecipe == null) { Log.Warning("No matching recipe found for data: {Data}", data); return; } - - _recognitionControl.SetRecipe(existingRecipe); + vm.SelectedRecipe = vm.Recipes.FirstOrDefault(r => r.RecipeName == existingRecipe.RecipeName); + _singleCameraVm.SynchronizationContext!.Post((_) => + { + _singleCameraVm.ProcessRecipeSelectionVm(vm); + }, null); } diff --git a/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs b/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs index 6487b41..9d3e5f8 100644 --- a/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs +++ b/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs @@ -12,8 +12,8 @@ public abstract class BaseRecognitionControlSettings(string cameraName) : ISetti public virtual void RegisterSettings(InspectronSettings settings) { - settings.RegisterSimple(this, () => this.MinimumProcessingTime, CameraName + "/Hawkeye recognition", "Minimum processing time (ms)"); - settings.RegisterSimple(this, () => this.RecipeNameFilter, CameraName + "/Hawkeye recognition", nameof(RecipeNameFilter)); - settings.RegisterSimple(this, () => this.ErrorsInSequenceAlarm, CameraName + "/Hawkeye recognition", nameof(ErrorsInSequenceAlarm)); + settings.RegisterSimple(this, () => this.MinimumProcessingTime, CameraName + "/Recognition", "Minimum processing time (ms)"); + settings.RegisterSimple(this, () => this.RecipeNameFilter, CameraName + "/Recognition", nameof(RecipeNameFilter)); + settings.RegisterSimple(this, () => this.ErrorsInSequenceAlarm, CameraName + "/Recognition", nameof(ErrorsInSequenceAlarm)); } } \ No newline at end of file diff --git a/VisionBuilder.UI.Common/UIConfiguration.cs b/VisionBuilder.UI.Common/UIConfiguration.cs index 1283c33..0549f15 100644 --- a/VisionBuilder.UI.Common/UIConfiguration.cs +++ b/VisionBuilder.UI.Common/UIConfiguration.cs @@ -16,6 +16,10 @@ public class UIConfiguration: ISettings public bool ProtectSettingsWithPassword { get; set; }=false; + public bool ShowPauseButton { get; set; }=false; + + public bool ShowTestModeButton { get; set; } = false; + public List ErrorShortNames { get; set; } = new List(); public void RegisterSettings(InspectronSettings settings) @@ -24,6 +28,8 @@ public class UIConfiguration: ISettings settings.RegisterSimple(this, () => this.AdminPassword, "System", "Password"); settings.RegisterSimple(this, () => this.ProtectSettingsWithPassword, "System", nameof(ProtectSettingsWithPassword)); settings.RegisterSimple(this, () => this.ErrorShortNames, "Errors", "Error short names"); + settings.RegisterSimple(this, () => this.ShowPauseButton, "System", nameof(ShowPauseButton)); + settings.RegisterSimple(this, () => this.ShowTestModeButton, "System", nameof(ShowTestModeButton)); } diff --git a/VisionBuilder.UI.Common/ViewModel/ErrorPreviewVM.cs b/VisionBuilder.UI.Common/ViewModel/ErrorPreviewVM.cs index e9703d8..e322310 100644 --- a/VisionBuilder.UI.Common/ViewModel/ErrorPreviewVM.cs +++ b/VisionBuilder.UI.Common/ViewModel/ErrorPreviewVM.cs @@ -100,7 +100,7 @@ public partial class ErrorPreviewVM:ObservableObject [RelayCommand(CanExecute = nameof(LearnButtonVisible))] public void Learn() { - if (string.IsNullOrEmpty(_uiConfiguration.AdminPassword)) + if (!string.IsNullOrEmpty(_uiConfiguration.AdminPassword)) { var passwordOk= _passwordInputService.GetPassword()==_uiConfiguration.AdminPassword; if (!passwordOk) return; diff --git a/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs b/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs index 1f92ac6..977e326 100644 --- a/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs +++ b/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs @@ -15,7 +15,8 @@ namespace VisionBuilder.UI.Common public partial class SingleCameraVM : ObservableObject, IEventHandler { public SynchronizationContext? SynchronizationContext { get; set; } - + + private readonly UIConfiguration _uiConfiguration; private readonly IRecipeSelectionDialogService _recipeSelectionDialogService; private readonly IRecognitionControl _recognitionControl; @@ -56,8 +57,10 @@ namespace VisionBuilder.UI.Common public bool CanStop => IsRunning; public bool CanStart => !IsRunning && SelectedRecipe!=null; - public bool CanPause => IsRunning && !IsPaused; - public bool CanResume => IsRunning && IsPaused; + public bool CanPause => (IsRunning && !IsPaused)&&_uiConfiguration.ShowPauseButton; + public bool CanResume => (IsRunning && IsPaused) && _uiConfiguration.ShowPauseButton; + + public bool IsNotRunning => !IsRunning; private bool _handlingEnabled = true; @@ -77,10 +80,12 @@ namespace VisionBuilder.UI.Common [NotifyPropertyChangedFor(nameof(RecipeSelected))] [NotifyPropertyChangedFor(nameof(RecipeNotSelected))] private RecipeData? _selectedRecipe; + public SingleCameraVM(CameraSettings cameraSettings, UIConfiguration uiConfiguration, IRecipeSelectionDialogService recipeSelectionDialogService, IRecognitionControl recognitionControl, IImagePreviewService imagePreviewService, ILearningTool learningTool, IPasswordInputService passwordInputService) { + _uiConfiguration = uiConfiguration; _recipeSelectionDialogService = recipeSelectionDialogService; _recognitionControl = recognitionControl; @@ -94,6 +99,8 @@ namespace VisionBuilder.UI.Common recognitionControl.SessionStarted += StatisticsVm.Handle; recognitionControl.SessionStarted += ErrorsVm.Handle; + + } diff --git a/VisionBuilder.UI.Recipes.HawkeyeRecipe/ModuleExtensions.cs b/VisionBuilder.UI.Recipes.HawkeyeRecipe/ModuleExtensions.cs index cd84eba..8d5e20a 100644 --- a/VisionBuilder.UI.Recipes.HawkeyeRecipe/ModuleExtensions.cs +++ b/VisionBuilder.UI.Recipes.HawkeyeRecipe/ModuleExtensions.cs @@ -8,7 +8,7 @@ public static class ModuleExtensions { public static IChildKernel UseHawkeyeRecipes(this IChildKernel self, string cameraName) { - self.Bind().ToConstant(new HawkeyeRecognitionSettings(cameraName)); + self.Bind().ToConstant(new HawkeyeRecognitionSettings(cameraName)); self.Bind().To().InSingletonScope(); return self; } diff --git a/VisionBuilder.UI.Statistics/VisionBuilderStatistics.cs b/VisionBuilder.UI.Statistics/VisionBuilderStatistics.cs index a051bcc..4e656d0 100644 --- a/VisionBuilder.UI.Statistics/VisionBuilderStatistics.cs +++ b/VisionBuilder.UI.Statistics/VisionBuilderStatistics.cs @@ -25,11 +25,14 @@ namespace VisionBuilder.UI.Statistics private string _currentRecipe; private string _fileName; private string _directoryPath; + private int _total = 0; private const string BY_EVENTS_FILE_NAME = "statistics_by_events.csv"; private const string MONTHLY_FILE_NAME = "statistics_month.csv"; private const string EMPTY_DATE = ""; private const string EMPTY_TIME = ""; + private const string DATE_FORMAT = "dd.MM.yyyy"; + private const string TIME_FORMAT = "HH:mm:ss"; public bool DoNotDeleteTempFiles { get; set; } = false; public VisionBuilderStatistics(VisionBuilderStatisticsSettings settings, IRecognitionControl recognitionControl, ILoadingService loadingService) @@ -51,7 +54,7 @@ namespace VisionBuilder.UI.Statistics _loadingService.StartLoading("Writing statistics for " + _settings.CameraName); try { - _csvStatistics.WriteLine([_startTime.ToString("d"), _startTime.ToString("T"), endedAt.ToString("d"), endedAt.ToString("T"), "", "", ""]); + _csvStatistics.WriteLine([_startTime.ToString(DATE_FORMAT), _startTime.ToString(TIME_FORMAT), endedAt.ToString(DATE_FORMAT), endedAt.ToString(TIME_FORMAT), "", "", ""]); _csvStatistics.Dispose(); _csvStatistics = null; @@ -67,19 +70,21 @@ namespace VisionBuilder.UI.Statistics private void _recognitionControl_ImageProcessed(ImageProcessedEvent obj) { var sw = Stopwatch.StartNew(); + _total++; if (obj.HasError) { RecordBadImage(obj.ErrorNames[0]); } sw.Stop(); - Console.WriteLine($"Recording statistics took {sw.ElapsedMilliseconds} ms"); + Log.Debug($"Recording statistics took {sw.ElapsedMilliseconds} ms"); } private void _recognitionControl_SessionStarted(SessionStartedEvent obj) { _startTime = obj.SessionStarted; + _total = 0; _currentRecipe = obj.RecipeName; - _fileName = "tmp_"+Guid.NewGuid().ToString()+".csv"; + _fileName = BY_EVENTS_FILE_NAME; _directoryPath = PathSettingsUtils.ConvertVariables(_settings.PathTemplate, _startTime, _startTime, obj.RecipeName, cameraName: _settings.CameraName); _filePath = Path.Combine(_directoryPath, _fileName); @@ -89,7 +94,7 @@ namespace VisionBuilder.UI.Statistics Directory.CreateDirectory(Path.GetDirectoryName(_filePath)); } _csvStatistics = new CsvStatistics(_filePath, headers); - _csvStatistics.WriteLine([_startTime.ToString("d"), _startTime.ToString("T")]); // session started + _csvStatistics.WriteLine([_startTime.ToString(DATE_FORMAT), _startTime.ToString(TIME_FORMAT)]); // session started _defects = new ConcurrentDictionary(); } @@ -101,7 +106,7 @@ namespace VisionBuilder.UI.Statistics _csvStatistics.WriteLine( - [_startTime.ToString("d"), _startTime.ToString("T"), EMPTY_DATE, EMPTY_TIME, DateTime.Now.ToString("T"), _currentRecipe, defectName, Metadata] + [_startTime.ToString(DATE_FORMAT), _startTime.ToString(TIME_FORMAT), EMPTY_DATE, EMPTY_TIME, DateTime.Now.ToString(TIME_FORMAT), _currentRecipe, defectName, Metadata] ); @@ -119,16 +124,56 @@ namespace VisionBuilder.UI.Statistics var monthFilePath = Path.Combine(_directoryPath, MONTHLY_FILE_NAME); var monthStatistics = new CsvStatistics(monthFilePath, [ - "Date start","Time start","Date end", "Time end" ,"Product","Error type","Error count" + ]); + monthStatistics.WriteLine( + ["Start", _startTime.ToString($"{DATE_FORMAT} {TIME_FORMAT}")] + ); + monthStatistics.WriteLine([ + _settings.MetadataColumnName, Metadata + ]); + monthStatistics.WriteLine( + [_settings.ProductColumnName, _currentRecipe] + ); + monthStatistics.WriteLine( + [_settings.ErrorColumnName, "Amount"] + ); + foreach (var defect in _defects) { monthStatistics.WriteLine( - [startDate.ToString("d"), startTime.ToString("T"), endDate.ToString("d"), endTime.ToString("T"), _currentRecipe, defect.Key, defect.Value.ToString()] + [defect.Key, defect.Value.ToString()] ); } + var totalDefects = 0; + foreach (var defect in _defects) + { + totalDefects += defect.Value; + } + + monthStatistics.WriteLine([]); + monthStatistics.WriteLine( + ["Total errors", totalDefects.ToString()] + ); + monthStatistics.WriteLine( + ["Total produced(including errors)", _total.ToString()] + ); + + var percentage = _total > 0 ? (double)totalDefects / _total * 100 : 0; + + monthStatistics.WriteLine( + ["Error rate", percentage.ToString("F2") + "%"] + ); + + monthStatistics.WriteLine( + [ + "End", _endTime.ToString($"{DATE_FORMAT} {TIME_FORMAT}") + ]); + + monthStatistics.WriteLine([]); + monthStatistics.WriteLine([]); monthStatistics.Dispose(); diff --git a/VisionBuilder.UI.Windows.Test/Form1.Designer.cs b/VisionBuilder.UI.Windows.Test/Form1.Designer.cs index 3391538..2f2d354 100644 --- a/VisionBuilder.UI.Windows.Test/Form1.Designer.cs +++ b/VisionBuilder.UI.Windows.Test/Form1.Designer.cs @@ -135,14 +135,16 @@ // flowLayoutPanel1 // flowLayoutPanel1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + flowLayoutPanel1.AutoSize = true; + flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; flowLayoutPanel1.BackColor = Color.Transparent; flowLayoutPanel1.Controls.Add(btnTestMode); flowLayoutPanel1.Controls.Add(btnSettings); flowLayoutPanel1.Controls.Add(btnMinimize); flowLayoutPanel1.Controls.Add(btnExit); - flowLayoutPanel1.Location = new Point(664, 992); + flowLayoutPanel1.Location = new Point(664, 1002); flowLayoutPanel1.Name = "flowLayoutPanel1"; - flowLayoutPanel1.Size = new Size(728, 80); + flowLayoutPanel1.Size = new Size(728, 70); flowLayoutPanel1.TabIndex = 12; // // lblVersion @@ -170,6 +172,7 @@ Text = "Form1"; flowLayoutPanel1.ResumeLayout(false); ResumeLayout(false); + PerformLayout(); } #endregion diff --git a/VisionBuilder.UI.Windows.Test/Form1.cs b/VisionBuilder.UI.Windows.Test/Form1.cs index 1c215c7..1f4b80e 100644 --- a/VisionBuilder.UI.Windows.Test/Form1.cs +++ b/VisionBuilder.UI.Windows.Test/Form1.cs @@ -29,6 +29,8 @@ namespace VisionBuilder.UI.Windows.Test Load += Form1_Load; _mainWindowVm.PropertyChanged += _mainWindowVm_PropertyChanged; lblVersion.Text = $"v{Application.ProductVersion.Split('+')[0]}"; + if(!_uiConfiguration.ShowTestModeButton) + flowLayoutPanel1.Controls.Remove(btnTestMode); } diff --git a/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj b/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj index 31eef46..d74e59d 100644 --- a/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj +++ b/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj @@ -8,7 +8,7 @@ enable Inspectron icon-512.ico false - 1.0.5 + 1.0.6 diff --git a/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs b/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs index 9daa563..0c3fa93 100644 --- a/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs +++ b/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs @@ -47,6 +47,7 @@ namespace VisionBuilder.UI.Windows.Components btnSelectRecipe.DataBindings.Add(nameof(btnSelectRecipe.Primary), _singleCameraVm, nameof(_singleCameraVm.RecipeNotSelected), true, DataSourceUpdateMode.OnPropertyChanged); btnPause.DataBindings.Add(nameof(btnPause.Visible), _singleCameraVm, nameof(_singleCameraVm.CanPause), true, DataSourceUpdateMode.OnPropertyChanged); btnResume.DataBindings.Add(nameof(btnResume.Visible), _singleCameraVm, nameof(_singleCameraVm.CanResume), true, DataSourceUpdateMode.OnPropertyChanged); + }