From 2fa212e6ff4018d649df062984d20aefe14e8fe3 Mon Sep 17 00:00:00 2001 From: Michal Buzik Date: Tue, 21 Jul 2026 14:50:59 +0200 Subject: [PATCH] FIX CAMERA - Improve error handling, modularize image processing functions for CJMS11 cameras, and enhance multi-image support in TestStartEndForm. --- .../StandartCameraPurchaseOrder/EntryForm.cs | 291 +++++++----- .../TestStartEndForm.cs | 416 ++++++++++++++---- TBF/Rig/Network/Camera/CJMS11/Camera.cs | 104 ++--- .../Camera/RoiForFixedStartCJMS11/Roi.cs | 6 + .../StandingStartMassCollectionAdvanceSeq.cs | 17 +- ...ingStartMassCollectionAdvanceCollectSeq.cs | 12 +- 6 files changed, 597 insertions(+), 249 deletions(-) diff --git a/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/EntryForm.cs b/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/EntryForm.cs index 091605cbf..fe7247a0f 100644 --- a/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/EntryForm.cs +++ b/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/EntryForm.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; using log4net; -using Common; using TBF.Rig.GenericDevices; +using System.Linq; namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder { @@ -38,32 +38,21 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder public string[] StartImages { get { return startImages; } - set - { - /*if (entryFormCfg.DebugLevel == DebugMode.Simulate ) - { - startImages = new string[] { "C:\\TBF\\Images\\Test\\Image1.jpg", "C:\\TBF\\Images\\Test\\Image2.jpg", - "C:\\TBF\\Images\\Test\\Image3.jpg", "C:\\TBF\\Images\\Test\\Image4.jpg", "C:\\TBF\\Images\\Test\\Image5.jpg", - "C:\\TBF\\Images\\Test\\Image1.jpg", "C:\\TBF\\Images\\Test\\Image2.jpg", "C:\\TBF\\Images\\Test\\Image3.jpg", - "C:\\TBF\\Images\\Test\\Image4.jpg", "C:\\TBF\\Images\\Test\\Image5.jpg", "C:\\TBF\\Images\\Test\\Image1.jpg", - "C:\\TBF\\Images\\Test\\Image2.jpg", "C:\\TBF\\Images\\Test\\Image3.jpg", "C:\\TBF\\Images\\Test\\Image4.jpg", - "C:\\TBF\\Images\\Test\\Image5.jpg", "C:\\TBF\\Images\\Test\\Image1.jpg", "C:\\TBF\\Images\\Test\\Image2.jpg", - "C:\\TBF\\Images\\Test\\Image3.jpg", "C:\\TBF\\Images\\Test\\Image4.jpg", "C:\\TBF\\Images\\Test\\Image5.jpg" }; - } - else*/ - { - startImages = value; - } - } + set { startImages = value; } } - string[] startImages; public string[] EndImages { get { return endImages; } set { endImages = value; } } + + string[] startImages; string[] endImages; + + private readonly List[] startImageLists = new List[TBF.Data.WMsCount]; + + private readonly List[] endImageLists = new List[TBF.Data.WMsCount]; public bool SaveImages { @@ -152,16 +141,27 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder entryFormCfg = cfg as EntryFormCfg; } - public override void Initialize() - { - disabled = new bool[TBF.Data.WMsCount]; - wmStartState = new double[TBF.Data.WMsCount]; - wmStartStateStr = new string[TBF.Data.WMsCount]; - wmEndState = new double[TBF.Data.WMsCount]; - wmCycleEndState = new string[TBF.Data.WMsCount]; - currentOp = CurrentOp.None; - log.FatalFormat("{0} initialized: {1}", Name, this); - } + public override void Initialize() + { + disabled = new bool[TBF.Data.WMsCount]; + wmStartState = new double[TBF.Data.WMsCount]; + wmStartStateStr = new string[TBF.Data.WMsCount]; + wmEndState = new double[TBF.Data.WMsCount]; + wmCycleEndState = new string[TBF.Data.WMsCount]; + + startImages = new string[TBF.Data.WMsCount]; + endImages = new string[TBF.Data.WMsCount]; + + currentOp = CurrentOp.None; + + for (int i = 0; i < TBF.Data.WMsCount; i++) + { + startImageLists[i] = new List(); + endImageLists[i] = new List(); + } + + log.FatalFormat("{0} initialized: {1}", Name, this); + } /// Reference to the operation @@ -202,15 +202,19 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder /// /// /// - public IOperation ShowTestCollectFormOp(IRegReader[] regReaders, double volumeRef, double errLimLo, + public IOperation ShowTestCollectFormOp( + IRegReader[] regReaders, + double volumeRef, + double errLimLo, double errLimHi) { if (currentOp != CurrentOp.None) throw new Exception("Sequence error"); currentOp = CurrentOp.TestBothStates; this.regReaders = regReaders; - this.refVolume = refVolume; + this.refVolume = volumeRef; // = refVolume; this.errLimLo = errLimLo; this.errLimHi = errLimHi; + return this; } @@ -255,21 +259,38 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder void OpenTestStartStatesDlg(EntryForm myRef) { log.Debug("-- OpenTestStartStatesDlg --"); - string ocrMessage; - var ocr = GetOcr(myRef.OcrWorkspace, out ocrMessage); - myRef.modelessDlg = new TestStartEndForm(TBF.Data.WMsCount, myRef.regReaders, ocr, ocrMessage, myRef.OcrStream, - startImages, disabled); + + log.DebugFormat( "Before TestStartEndForm: TBF.Data.WMsCount={0}, regReaders.Length={1}, startImages.Length={2}, disabled.Length={3}", + TBF.Data.WMsCount, + myRef.regReaders == null ? -1 : myRef.regReaders.Length, + startImages == null ? -1 : startImages.Length, + disabled == null ? -1 : disabled.Length); + + if (startImages != null) + { + for (int i = 0; i < startImages.Length; i++) + { + log.DebugFormat( "startImages[{0}]='{1}'", i, startImages[i]); + } + } + + string ocrMessage; + var ocr = GetOcr(myRef.OcrWorkspace, out ocrMessage); + + myRef.modelessDlg = new TestStartEndForm( TBF.Data.WMsCount, myRef.regReaders, ocr, ocrMessage, myRef.OcrStream, startImages, disabled); + modelessDlg.Show(); } /// void OpenTestEndStatesDlg(EntryForm myRef) { - log.Debug("-- OpenTestEndStatesDlg --"); + log.Warn("-- OpenTestEndStatesDlg ENTER --"); string ocrMessage; var ocr = GetOcr(myRef.OcrWorkspace, out ocrMessage); myRef.modelessDlg = new TestStartEndForm(TBF.Data.WMsCount, myRef.regReaders, ocr, ocrMessage, myRef.OcrStream, startImages, wmStartState, wmStartStateStr, endImages, disabled, refVolume, errLimLo, errLimHi); + log.Warn("-- OpenTestEndStatesDlg SHOW --"); modelessDlg.Show(); } @@ -340,6 +361,12 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder /// Start this operation public void Start() { + log.WarnFormat( "EntryForm.Start: currentOp={0}, modelessDlg={1}, resultSaved={2}", + currentOp, + modelessDlg == null ? "" : modelessDlg.GetType().FullName, + resultSaved); + + resultSaved = false; switch (currentOp) { @@ -383,95 +410,80 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder /// Event.ResultsPrinted public Event Run() { + log.WarnFormat( "EntryForm.Run: currentOp={0}, modelessDlg={1}, completed={2}, resultSaved={3}", + currentOp, + modelessDlg == null ? "" : modelessDlg.GetType().FullName, + modelessDlg is IHasCompleted && ((IHasCompleted)modelessDlg).Completed, + resultSaved); + + if ((modelessDlg is IHasCompleted) && !(modelessDlg as IHasCompleted).Completed) { return Event.ModelessFormIsOpen; } - if (!resultSaved) /// This is to save the result only once + if (!resultSaved) { - if ((!entryFormCfg.EnterSerialNrsAtTheEnd && currentOp == CurrentOp.ShowFormAtCycleBeginning) || - (entryFormCfg.EnterSerialNrsAtTheEnd && currentOp == CurrentOp.ShowFormAtCycleEnd)) + try { - CycleBeginningForm dlg = (modelessDlg as CycleBeginningForm); - if (dlg != null) + if ((!entryFormCfg.EnterSerialNrsAtTheEnd && currentOp == CurrentOp.ShowFormAtCycleBeginning) || + (entryFormCfg.EnterSerialNrsAtTheEnd && currentOp == CurrentOp.ShowFormAtCycleEnd)) { - for (int i = 0; i < Math.Min(dlg.WaterMetersCount, waterMeters.Count); i++) - { - if (waterMeters[i] != null) - { - waterMeters[i].Disabled = disabled[i] = dlg.Disabled[i]; - waterMeters[i].SerialNr = dlg.SNText[i]; - if (!entryFormCfg.HideOrder && dlg.PurchaseOrder != null) waterMeters[i].PurchaseOrder = dlg.PurchaseOrder; - } - } - } - } - else if (currentOp == CurrentOp.ShowFormAtCycleEnd) - { - if (modelessDlg is CycleEndForm) - { - CycleEndForm dlg = (modelessDlg as CycleEndForm); - int count = waterMeters.Count; - if ((dlg != null) && (count > dlg.WaterMetersCount)) count = dlg.WaterMetersCount; + CycleBeginningForm dlg = modelessDlg as CycleBeginningForm; - for (int i = 0; i < count; i++) + if (dlg != null) { - if (waterMeters[i] != null) + for (int i = 0; i < Math.Min( dlg.WaterMetersCount, waterMeters.Count); i++) { - /// In case entryFormCfg.ShowCycleEndForm == false dlg would be null, values would be string.Empty - wmCycleEndState[i] = waterMeters[i].EndState = (dlg != null) ? dlg.EndStateText[i] : string.Empty; + if (waterMeters[i] != null) + { + waterMeters[i].Disabled = disabled[i] = dlg.Disabled[i]; + waterMeters[i].SerialNr = dlg.SNText[i]; + + if (!entryFormCfg.HideOrder && dlg.PurchaseOrder != null) + { + waterMeters[i].PurchaseOrder = dlg.PurchaseOrder; + } + } } } } - } - else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.TestStartStates) - { - /// Fixed start/stop: test start - TestStartEndForm dlg = (modelessDlg as TestStartEndForm); - if (dlg != null) - { - for (int i = 0; i < dlg.WaterMetersCount; i++) - { - wmStartState[i] = dlg.WMStartState[i]; - wmStartStateStr[i] = dlg.WMStartStateStr[i]; - } - } - } - else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.TestEndStates) - { - /// Fixed start/stop: test end - TestStartEndForm dlg = (modelessDlg as TestStartEndForm); - if (dlg != null) - { - for (int i = 0; i < dlg.WaterMetersCount; i++) - { - wmStartState[i] = dlg.WMStartState[i]; - wmStartStateStr[i] = dlg.WMStartStateStr[i]; - wmEndState[i] = dlg.WMEndState[i]; - } - } - } - else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.TestBothStates) - { - /// Fixed start/stop: test end - TestStartEndForm dlg = (modelessDlg as TestStartEndForm); - if (dlg != null) - { - for (int i = 0; i < dlg.WaterMetersCount; i++) - { - wmStartState[i] = dlg.WMStartState[i]; - wmStartStateStr[i] = dlg.WMStartStateStr[i]; - wmEndState[i] = dlg.WMEndState[i]; - } - } - } - else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.DeferredTestEval) - { - /// Fixed start/stop: deferred test evaluation - TestStartEndForm dlg = (modelessDlg as TestStartEndForm); - if (dlg != null) + else if (currentOp == CurrentOp.ShowFormAtCycleEnd) { + CycleEndForm dlg = modelessDlg as CycleEndForm; + + if (dlg != null) + { + int count = waterMeters.Count; + + if (count > dlg.WaterMetersCount) + { + count = dlg.WaterMetersCount; + } + + for (int i = 0; i < count; i++) + { + if (waterMeters[i] != null) + { + wmCycleEndState[i] = waterMeters[i].EndState = dlg.EndStateText[i]; + } + } + } + } + else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.TestStartStates) + { + TestStartEndForm dlg = modelessDlg as TestStartEndForm; + + for (int i = 0; i < dlg.WaterMetersCount; i++) + { + wmStartState[i] = dlg.WMStartState[i]; + wmStartStateStr[i] = dlg.WMStartStateStr[i]; + } + } + else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.TestEndStates) + { + TestStartEndForm dlg = modelessDlg as TestStartEndForm; + for (int i = 0; i < dlg.WaterMetersCount; i++) { wmStartState[i] = dlg.WMStartState[i]; @@ -479,12 +491,39 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder wmEndState[i] = dlg.WMEndState[i]; } } + else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.TestBothStates) + { + TestStartEndForm dlg = modelessDlg as TestStartEndForm; + + for (int i = 0; i < dlg.WaterMetersCount; i++) + { + wmStartState[i] = dlg.WMStartState[i]; + wmStartStateStr[i] = dlg.WMStartStateStr[i]; + wmEndState[i] = dlg.WMEndState[i]; + } + } + else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.DeferredTestEval) + { + TestStartEndForm dlg = modelessDlg as TestStartEndForm; + for (int i = 0; i < dlg.WaterMetersCount; i++) + { + wmStartState[i] = dlg.WMStartState[i]; + wmStartStateStr[i] = dlg.WMStartStateStr[i]; + wmEndState[i] = dlg.WMEndState[i]; + } + } + + resultSaved = true; + } + finally + { + log.DebugFormat( "EntryForm operation completed: currentOp={0}", currentOp); + modelessDlg = null; + currentOp = CurrentOp.None; } - resultSaved = true; - modelessDlg = null; } - return Event.ModelessFormClosed; /// Form closed + return Event.ModelessFormClosed; } /// Stop this operation @@ -497,5 +536,31 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder } currentOp = CurrentOp.None; } + + public void AddImages(string[] newStartImages, string[] newEndImages) + { + for (int i = 0; i < TBF.Data.WMsCount; i++) + { + if (newStartImages != null && + i < newStartImages.Length && + !string.IsNullOrEmpty(newStartImages[i]) && + System.IO.File.Exists(newStartImages[i]) && + !startImageLists[i].Any( image => string.Equals( image, newStartImages[i], StringComparison.OrdinalIgnoreCase))) + { + startImageLists[i].Add(newStartImages[i]); + } + + if (newEndImages != null && + i < newEndImages.Length && + !string.IsNullOrEmpty(newEndImages[i]) && + System.IO.File.Exists(newEndImages[i]) && + !endImageLists[i].Any( image => string.Equals( image, newEndImages[i], StringComparison.OrdinalIgnoreCase))) + { + endImageLists[i].Add(newEndImages[i]); + } + } + } + + } } diff --git a/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/TestStartEndForm.cs b/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/TestStartEndForm.cs index d94f7471f..6f1a85ee5 100644 --- a/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/TestStartEndForm.cs +++ b/TBF/Rig/DataEntry/StandartCameraPurchaseOrder/TestStartEndForm.cs @@ -179,7 +179,15 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder if (startImages == null || startImages.Length != WaterMetersCount) { - throw new Exception("Invalid 'startImages' argument"); + throw new Exception( + string.Format( + "Invalid 'startImages' argument. startImages.Length={0}, " + + "WaterMetersCount={1}, requestedWaterMetersCount={2}, " + + "regReaders.Length={3}", + startImages == null ? -1 : startImages.Length, + WaterMetersCount, + waterMetersCount, + regReaders == null ? -1 : regReaders.Length)); } this.endImages = new string[WaterMetersCount]; @@ -721,12 +729,12 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder private void previousButton_Click(object sender, EventArgs e) { - + ShowPreviousImageFromGroup(); } private void nextButton_Click(object sender, EventArgs e) { - + ShowNextImageFromGroup(); } @@ -1142,8 +1150,8 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder private void endTextBox20_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 19); } private void endTextBox21_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 20); } private void endTextBox22_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 21); } - private void endTextBox24_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 22); } - private void endTextBox23_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 23); } + private void endTextBox24_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 23); } + private void endTextBox23_AcceptsTabChanged(object sender, EventArgs e) { LoadImage(sender, Tst.End, 22); } private void endTextBox1_MouseDown(object sender, MouseEventArgs e) { LoadImage(sender, Tst.End, 0); } private void endTextBox2_MouseDown(object sender, MouseEventArgs e) { LoadImage(sender, Tst.End, 1); } private void endTextBox3_MouseDown(object sender, MouseEventArgs e) { LoadImage(sender, Tst.End, 2); } @@ -1290,77 +1298,92 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder return null; } - + /// /// load group of images /// /// - private void LoadImageGroup( - string baseImageFileName) + private void LoadImageGroup(string baseImageFileName) { currentImageGroup.Clear(); currentImageGroupIndex = 0; if (string.IsNullOrWhiteSpace(baseImageFileName)) { + UpdateImageSwitchControls(); return; } - string fullBaseFileName; - try { - fullBaseFileName = - Path.GetFullPath(baseImageFileName); - } - catch (Exception exc) - { - log.Warn( - $"Cannot create image group from invalid path: " + - $"file='{baseImageFileName}', " + - $"error={exc.Message}"); + /* + * Vstup môže byť napríklad: + * + * C:\Tbf\Images\1667\1\Advance_(1_3)-start.bmp + * + * Preview však musí používať výhradne: + * + * C:\Tbf\Images\Temp\1667\1\Advance_(1_3)-start.bmp + * C:\Tbf\Images\Temp\1667\1\Advance_(1_3)-start_img02_....bmp + * C:\Tbf\Images\Temp\1667\1\Advance_(1_3)-start_img03_....bmp + */ + string tempBaseFileName = + GetTempImageFileName(baseImageFileName); - return; - } + if (string.IsNullOrWhiteSpace(tempBaseFileName)) + { + log.WarnFormat( + "Cannot determine Temp image path from '{0}'.", + baseImageFileName); - string directory = - Path.GetDirectoryName(fullBaseFileName); + UpdateImageSwitchControls(); + return; + } - string baseName = - Path.GetFileNameWithoutExtension(fullBaseFileName); + string tempDirectory = + Path.GetDirectoryName(tempBaseFileName); - string extension = - Path.GetExtension(fullBaseFileName); + string baseName = + Path.GetFileNameWithoutExtension(tempBaseFileName); - if (string.IsNullOrWhiteSpace(directory) || - string.IsNullOrWhiteSpace(baseName)) - { - return; - } + string extension = + Path.GetExtension(tempBaseFileName); - /* - * Pôvodný obrázok pridáme ako prvý. - */ - if (File.Exists(fullBaseFileName)) - { - currentImageGroup.Add(fullBaseFileName); - } + if (string.IsNullOrWhiteSpace(tempDirectory) || + string.IsNullOrWhiteSpace(baseName) || + !Directory.Exists(tempDirectory)) + { + log.DebugFormat( + "Temp image directory does not exist: '{0}'.", + tempDirectory); - if (!Directory.Exists(directory)) - { - return; - } + UpdateImageSwitchControls(); + return; + } - string searchPattern = - $"{baseName}_img*{extension}"; + /* + * Prvý obrázok: + * + * Advance_(1_3)-start.bmp + */ + AddImageToCurrentGroup(tempBaseFileName); + + /* + * Ďalšie obrázky: + * + * Advance_(1_3)-start_img02_20260720_094019_248.bmp + * Advance_(1_3)-start_img03_20260720_094019_847.bmp + */ + string timedPattern = string.Format( + "{0}_img*{1}", + baseName, + extension); - try - { List timedImages = Directory .GetFiles( - directory, - searchPattern, + tempDirectory, + timedPattern, SearchOption.TopDirectoryOnly) .OrderBy(GetTimedImageIndex) .ThenBy( @@ -1370,29 +1393,255 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder foreach (string timedImage in timedImages) { - if (!currentImageGroup.Contains( - timedImage, - StringComparer.OrdinalIgnoreCase)) - { - currentImageGroup.Add(timedImage); - } + AddImageToCurrentGroup(timedImage); } - log.Debug( - $"Image group loaded: " + - $"baseFile='{fullBaseFileName}', " + - $"searchPattern='{searchPattern}', " + - $"imagesCount={currentImageGroup.Count}"); + UpdateImageSwitchControls(); + + log.DebugFormat( + "Temp image group loaded: input='{0}', tempBase='{1}', " + + "pattern='{2}', count={3}, files=[{4}]", + baseImageFileName, + tempBaseFileName, + timedPattern, + currentImageGroup.Count, + string.Join( + ", ", + currentImageGroup.Select(Path.GetFileName))); } catch (Exception exc) { - log.Warn( - $"Cannot load image group: " + - $"baseFile='{fullBaseFileName}', " + - $"pattern='{searchPattern}', " + - $"error={exc.Message}"); + log.WarnFormat( + "Cannot load Temp image group: input='{0}', error={1}", + baseImageFileName, + exc.Message); + + currentImageGroup.Clear(); + currentImageGroupIndex = 0; + UpdateImageSwitchControls(); } } + + private static string GetTempImageFileName( + string imageFileName) + { + if (string.IsNullOrWhiteSpace(imageFileName)) + { + return null; + } + + string fullPath; + + try + { + fullPath = Path.GetFullPath(imageFileName); + } + catch + { + return null; + } + + const string tempRoot = + @"C:\Tbf\Images\Temp"; + + const string imagesRoot = + @"C:\Tbf\Images"; + + /* + * Súbor už smeruje do Temp. + */ + if (fullPath.StartsWith( + tempRoot + Path.DirectorySeparatorChar, + StringComparison.OrdinalIgnoreCase)) + { + return fullPath; + } + + /* + * C:\Tbf\Images\1667\1\file.bmp + * + * zmeníme na: + * + * C:\Tbf\Images\Temp\1667\1\file.bmp + */ + if (fullPath.StartsWith( + imagesRoot + Path.DirectorySeparatorChar, + StringComparison.OrdinalIgnoreCase)) + { + string relativePath = + fullPath.Substring( + imagesRoot.Length + 1); + + return Path.Combine( + tempRoot, + relativePath); + } + + /* + * Neznáma cesta – zachováme iba časť od čísla batchu, + * ak už cesta obsahuje adresár Temp. + */ + int tempIndex = fullPath.IndexOf( + @"\Temp\", + StringComparison.OrdinalIgnoreCase); + + if (tempIndex >= 0) + { + string relativePath = + fullPath.Substring( + tempIndex + @"\Temp\".Length); + + return Path.Combine( + tempRoot, + relativePath); + } + + return null; + } + + private static int GetRepetitionIndex(string fileName) + { + if (string.IsNullOrWhiteSpace(fileName)) + { + return int.MaxValue; + } + + Match match = Regex.Match(Path.GetFileNameWithoutExtension(fileName), @"\((?\d+)_\d+\)", + RegexOptions.IgnoreCase); + + int repetition; + + return match.Success && int.TryParse(match.Groups["repetition"].Value, out repetition) + ? repetition + : int.MaxValue; + } + + private void AddImageToCurrentGroup( + string imageFileName) + { + if (string.IsNullOrWhiteSpace(imageFileName) || + !File.Exists(imageFileName)) + { + return; + } + + bool alreadyAdded = + currentImageGroup.Any( + existingFile => + string.Equals( + existingFile, + imageFileName, + StringComparison.OrdinalIgnoreCase)); + + if (!alreadyAdded) + { + currentImageGroup.Add(imageFileName); + } + } + + private void UpdateImageSwitchControls() + { + bool canSwitch = + currentImageGroup.Count > 1; + + //previousButton.Enabled = canSwitch; + //nextButton.Enabled = canSwitch; + + // previousButton.Visible = canSwitch; + // nextButton.Visible = canSwitch; + } + + private void AddTimedImagesToCurrentGroup(string baseImageFileName) + { + if (string.IsNullOrWhiteSpace(baseImageFileName)) + { + return; + } + + string directory = Path.GetDirectoryName(baseImageFileName); + string baseName = Path.GetFileNameWithoutExtension(baseImageFileName); + string extension = Path.GetExtension(baseImageFileName); + + if (string.IsNullOrWhiteSpace(directory) || + string.IsNullOrWhiteSpace(baseName) || + !Directory.Exists(directory)) + { + return; + } + + string searchPattern = string.Format( + "{0}_img*{1}", + baseName, + extension); + + List timedImages = + Directory + .GetFiles( + directory, + searchPattern, + SearchOption.TopDirectoryOnly) + .OrderBy(GetTimedImageIndex) + .ThenBy( + fileName => fileName, + StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (string timedImage in timedImages) + { + AddImageToCurrentGroup(timedImage); + } + } + + private void AddTimedImagesFromDirectory( string directory, string searchPattern) + { + if (string.IsNullOrWhiteSpace(directory) || + string.IsNullOrWhiteSpace(searchPattern) || + !Directory.Exists(directory)) + { + return; + } + + List timedImages = Directory .GetFiles( directory, searchPattern, SearchOption.TopDirectoryOnly) + .OrderBy(GetTimedImageIndex) + .ThenBy( + fileName => fileName, + StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (string timedImage in timedImages) + { + AddImageToCurrentGroup(timedImage); + } + } + + private static string GetCorrespondingTempImageDirectory( string directory) + { + if (string.IsNullOrWhiteSpace(directory)) + { + return null; + } + + const string normalImagesPart = @"\Tbf\Images\"; + const string tempImagesPart = @"\Tbf\Images\Temp\"; + + /* + * Ak už sme v Temp adresári, nič nemeníme. + */ + if (directory.IndexOf( tempImagesPart, StringComparison.OrdinalIgnoreCase) >= 0) + { + return directory; + } + + int imagesIndex = directory.IndexOf( normalImagesPart, StringComparison.OrdinalIgnoreCase); + + if (imagesIndex < 0) + { + return null; + } + + return directory.Substring( 0, imagesIndex) + tempImagesPart + directory.Substring( imagesIndex + normalImagesPart.Length); + } + /// /// grouping by time /// @@ -1576,20 +1825,35 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder int direction) { if (direction == 0 || - currentImageGroup.Count <= 1) + currentImageGroup.Count == 0) { return; } - int newIndex = - currentImageGroupIndex + direction; - /* - * Cyklické prepínanie: - * - * posledný -> prvý - * prvý -> posledný + * Pred prepnutím odstránime súbory, ktoré už medzitým + * prestali existovať. */ + currentImageGroup.RemoveAll( fileName => !File.Exists(fileName)); + + if (currentImageGroup.Count == 0) + { + currentImageGroupIndex = 0; + UpdateImageSwitchControls(); + LoadImageFile(null); + return; + } + + if (currentImageGroup.Count == 1) + { + currentImageGroupIndex = 0; + UpdateImageSwitchControls(); + LoadImageFile(currentImageGroup[0]); + return; + } + + int newIndex = currentImageGroupIndex + direction; + if (newIndex < 0) { newIndex = @@ -1602,10 +1866,10 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder currentImageGroupIndex = newIndex; - LoadImageFile( - currentImageGroup[currentImageGroupIndex]); - } + LoadImageFile( currentImageGroup[currentImageGroupIndex]); + UpdateImageSwitchControls(); + } // --- mouse events --- diff --git a/TBF/Rig/Network/Camera/CJMS11/Camera.cs b/TBF/Rig/Network/Camera/CJMS11/Camera.cs index 552432ddd..8afcb4958 100644 --- a/TBF/Rig/Network/Camera/CJMS11/Camera.cs +++ b/TBF/Rig/Network/Camera/CJMS11/Camera.cs @@ -2385,33 +2385,26 @@ namespace TBF.Rig.Network.Camera.CJMS11 try { - log.Debug( - $"Live stream waiting for camera lock: " + - $"cameraIdx={cameraIdx}"); + log.Debug( $"Live stream waiting for camera lock: cameraIdx={cameraIdx}"); - await cameraOperationLock - .WaitAsync(ct) - .ConfigureAwait(false); + await cameraOperationLock .WaitAsync(ct) .ConfigureAwait(false); lockAcquired = true; - log.Debug( - $"Live stream acquired camera lock: " + - $"cameraIdx={cameraIdx}"); + log.Debug( $"Live stream acquired camera lock: cameraIdx={cameraIdx}"); client = await ConnectCameraAsync( - timeoutMs: 3000, - ct: ct, - maxAttempts: 3, - retryDelayMs: 300) - .ConfigureAwait(false); + timeoutMs: 3000, + ct: ct, + maxAttempts: 3, + retryDelayMs: 300) + .ConfigureAwait(false); stream = client.GetStream(); reader = new CameraLineReader( stream, 64 * 1024); - JmsPacket prepare = - await SendCommandAndWaitToAnswerAsync( + JmsPacket prepare = await SendCommandAndWaitToAnswerAsync( stream, reader, CommandM.prepare_camera_, @@ -2425,10 +2418,8 @@ namespace TBF.Rig.Network.Camera.CJMS11 prepare.JmsMessage != null && prepare.JmsMessage.Status == MessageStatus.NACK && - !string.IsNullOrEmpty( - prepare.JmsMessage.Payload) && - prepare.JmsMessage.Payload.Contains( - "OPENED"); + !string.IsNullOrEmpty( prepare.JmsMessage.Payload) && + prepare.JmsMessage.Payload.Contains( "OPENED"); bool prepared = prepare != null && @@ -2447,8 +2438,7 @@ namespace TBF.Rig.Network.Camera.CJMS11 log.Debug( $"Camera already opened for live stream: cameraIdx={cameraIdx}"); } - JmsPacket start = - await SendCommandAndWaitToAnswerAsync( + JmsPacket start = await SendCommandAndWaitToAnswerAsync( stream, reader, CommandM.start_stream_images_, @@ -2469,30 +2459,39 @@ namespace TBF.Rig.Network.Camera.CJMS11 while (!ct.IsCancellationRequested) { - string response = - await reader.ReadLineAsync( - 10000, - ct) - .ConfigureAwait(false); + string response = await reader.ReadLineAsync( 10000, ct).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(response)) - continue; - - JmsPacket packet = - new JmsPacket(response); - - if (packet.JmsMessage == null) - continue; - - if (packet.JmsMessage.Command != - CommandM.grab_image_) { - log.Debug( $"Unexpected packet during live stream: cameraIdx={cameraIdx}, command={packet.JmsMessage.Command}"); continue; } - if (packet.JmsMessage.Status != - MessageStatus.ACK) + JmsPacket packet = new JmsPacket(response); + + if (packet.JmsMessage == null) + { + continue; + } + + /* + * Server môže po spustení streamu poslať ešte jeden + * oneskorený alebo duplicitný ACK start_stream_images. + * Nie je to chyba streamu. + */ + if (packet.JmsMessage.Command == CommandM.start_stream_images_) + { + log.Debug( $"Ignoring delayed start stream response: cameraIdx={cameraIdx}"); + continue; + } + + if (packet.JmsMessage.Command != CommandM.grab_image_) + { + log.Debug( $"Unexpected packet during live stream: cameraIdx={cameraIdx}, " + + $"command={packet.JmsMessage.Command}"); + continue; + } + + if (packet.JmsMessage.Status != MessageStatus.ACK) { log.Warn( $"Live frame returned NACK: cameraIdx={cameraIdx}, payload={packet.JmsMessage.Payload}"); continue; @@ -2508,17 +2507,13 @@ namespace TBF.Rig.Network.Camera.CJMS11 Image image = parsed.Image; if (image == null) + { continue; + } DrawOverlay(image); - OnImageReceived( - this, - cameraIdx, - image, - RoiConfiguration.ImageRotation, - 0, - 1); + OnImageReceived( this, cameraIdx, image, RoiConfiguration.ImageRotation, 0, 1); } } catch (OperationCanceledException) @@ -2527,15 +2522,18 @@ namespace TBF.Rig.Network.Camera.CJMS11 } catch (TimeoutException exc) { + log.Error( $"Live stream timeout: cameraIdx={cameraIdx}, IP={CameraCfg.IPAddressCJMS}, error={exc.Message}"); } catch (SocketException exc) { - log.Error( $"Live stream socket error: cameraIdx={cameraIdx}, IP={CameraCfg.IPAddressCJMS}, socketError={exc.SocketErrorCode}, " + - $"error={exc.Message}"); + + log.Error( $"Live stream socket error: cameraIdx={cameraIdx}, IP={CameraCfg.IPAddressCJMS}, " + + $"socketError={exc.SocketErrorCode}, error={exc.Message}"); } catch (Exception exc) { + log.Error( $"Live stream exception: cameraIdx={cameraIdx}, error={exc.Message}", exc); UiBridge.Bridge.OnImage( cameraIdx, null); } @@ -2607,6 +2605,14 @@ namespace TBF.Rig.Network.Camera.CJMS11 cameraOperationLock.Release(); } + /* + * Dôležité: + * ak stream skončí timeoutom, socket chybou alebo výnimkou, + * UI musí povoliť nový pokus o spustenie. + */ + stopLiveStreamListenerFlag = true; + lockBrich = CameraUICmd.None; + log.Debug( $"Live stream finished: cameraIdx={cameraIdx}"); } } diff --git a/TBF/Rig/Network/Camera/RoiForFixedStartCJMS11/Roi.cs b/TBF/Rig/Network/Camera/RoiForFixedStartCJMS11/Roi.cs index c28c43730..69a11ba79 100644 --- a/TBF/Rig/Network/Camera/RoiForFixedStartCJMS11/Roi.cs +++ b/TBF/Rig/Network/Camera/RoiForFixedStartCJMS11/Roi.cs @@ -137,6 +137,12 @@ namespace TBF.Rig.Network.Camera.RoiForFixedStartCJMS11 { return null; } + + if (NetCamera.CameraCfg.DebugLevel != DebugMode.Simulate && NetCamera.IPAddress == null) + { + log.WarnFormat( "Skipping GrabImageOp for ROI '{0}': camera '{1}' was not detected.", Name, NetCamera.Name); + return null; + } int imageCount = Math.Max(1, RoiPicCount); diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/StandingStartMassCollectionAdvanceSeq.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/StandingStartMassCollectionAdvanceSeq.cs index 09fad7557..0abbfa3e5 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/StandingStartMassCollectionAdvanceSeq.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvance/StandingStartMassCollectionAdvanceSeq.cs @@ -609,10 +609,14 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvance (rr as Rig.Network.Camera.RoiForFixedStart.Roi).BeginWMState = dataEntryCmpnt.WMStartState(i); if (rr is Rig.Network.Camera.RoiForFixedStartKeyence.Roi) { - (rr as Rig.Network.Camera.RoiForFixedStartKeyence.Roi).BeginWMState = - dataEntryCmpnt.WMStartState(i); + (rr as Rig.Network.Camera.RoiForFixedStartKeyence.Roi).BeginWMState = dataEntryCmpnt.WMStartState(i); log.DebugFormat("BeginWMState [{0}] -> RoiForFixedStartKeyence.Roi",dataEntryCmpnt.WMStartState(i)); } + if (rr is Rig.Network.Camera.RoiForFixedStartCJMS11.Roi) + { + (rr as Rig.Network.Camera.RoiForFixedStartCJMS11.Roi).BeginWMState = dataEntryCmpnt.WMStartState(i); + log.DebugFormat("BeginWMState [{0}] -> RoiForFixedStartCJMS11.Roi",dataEntryCmpnt.WMStartState(i)); + } } } @@ -916,7 +920,7 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvance e = StateMachine.WaitRunDevsRunOps(); if (TestAndLogUiCmdStop(test, e)) { retVal = Event.UiCmdStop; goto stopTest; } } - while (!e.Contains(Event.TestInProgress/*Event.ModelessFormClosed*/)); + while (!e.Contains(Event.TestInProgress/*Event.ModelessFormClosed*/) && !e.Contains(Event.TestCompleted)); if (heatMetersTestParams != null) @@ -954,6 +958,13 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvance dataEntryCmpnt.WMEndState(i); log.DebugFormat(" StandingStartMassCollectionAdvanceSeq.cs - EndWMState [{0}] -> RoiForFixedStartKeyence.Roi",dataEntryCmpnt.WMEndState(i)); } + + if (rr is Rig.Network.Camera.RoiForFixedStartCJMS11.Roi) + { + (rr as Rig.Network.Camera.RoiForFixedStartCJMS11.Roi).EndWMState = + dataEntryCmpnt.WMEndState(i); + log.DebugFormat(" StandingStartMassCollectionAdvanceSeq.cs - EndWMState [{0}] -> RoiForFixedStartCJMS11.Roi",dataEntryCmpnt.WMEndState(i)); + } } } diff --git a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/StandingStartMassCollectionAdvanceCollectSeq.cs b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/StandingStartMassCollectionAdvanceCollectSeq.cs index 4192cd75c..882562da3 100644 --- a/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/StandingStartMassCollectionAdvanceCollectSeq.cs +++ b/TBF/Rig/TestMethods/StandingStartMassCollectionAdvanceCollect/StandingStartMassCollectionAdvanceCollectSeq.cs @@ -159,20 +159,16 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollectionAdvanceCollect if (rr is Rig.Network.Camera.RoiForFixedStartKeyence.Roi) { - (rr as Rig.Network.Camera.RoiForFixedStartKeyence.Roi).EndWMState = - dataEntryCmpnt.WMEndState(i); - (rr as Rig.Network.Camera.RoiForFixedStartKeyence.Roi).BeginWMState = - dataEntryCmpnt.WMStartState(i); + (rr as Rig.Network.Camera.RoiForFixedStartKeyence.Roi).EndWMState = dataEntryCmpnt.WMEndState(i); + (rr as Rig.Network.Camera.RoiForFixedStartKeyence.Roi).BeginWMState = dataEntryCmpnt.WMStartState(i); log.DebugFormat(" StandingStartMassCollectionAdvanceSeq.cs - BeginWMState [{0}], EndWMState [{1}] -> RoiForFixedStartKeyence.Roi",dataEntryCmpnt.WMStartState(i),dataEntryCmpnt.WMEndState(i)); } //New camera CJMS11 - supplier Java Microservices, s.r.o if (rr is Rig.Network.Camera.RoiForFixedStartCJMS11.Roi) { - (rr as Rig.Network.Camera.RoiForFixedStartCJMS11.Roi).EndWMState = - dataEntryCmpnt.WMEndState(i); - (rr as Rig.Network.Camera.RoiForFixedStartCJMS11.Roi).BeginWMState = - dataEntryCmpnt.WMStartState(i); + (rr as Rig.Network.Camera.RoiForFixedStartCJMS11.Roi).EndWMState = dataEntryCmpnt.WMEndState(i); + (rr as Rig.Network.Camera.RoiForFixedStartCJMS11.Roi).BeginWMState = dataEntryCmpnt.WMStartState(i); log.DebugFormat(" StandingStartMassCollectionAdvanceSeq.cs - BeginWMState [{0}], EndWMState [{1}] -> RoiForFixedStartCJMS11.Roi",dataEntryCmpnt.WMStartState(i),dataEntryCmpnt.WMEndState(i)); } }