From a4ef208233f9983cbb5848bec061f67f3f26702a Mon Sep 17 00:00:00 2001 From: Michal Buzik Date: Tue, 18 Aug 2026 16:09:21 +0200 Subject: [PATCH] Fix ver. 3.9.3139 iPerlCommunicationForm.cs problems + exceptions if another regreadrer has mistakely same ports Enhance iPerl dialog layout and error handling: improve `ShuffleTextBoxes` with positional mapping, refine checkbox state tracking, add detailed logging for labels and checkboxes, and handle serial port exceptions. Increment version to 3.9.3139.0. --- TBF/Properties/AssemblyInfo.cs | 4 +- .../communication/Utils/SerialDriver.cs | 18 ++- .../iPerlCommunicationForm.cs | 137 +++++++++++++----- 3 files changed, 122 insertions(+), 37 deletions(-) diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index 7aaf8e427..2aba9610a 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("3.9.3138.0")] -[assembly: AssemblyFileVersion("3.9.3138.0")] +[assembly: AssemblyVersion("3.9.3139.0")] +[assembly: AssemblyFileVersion("3.9.3139.0")] diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs index c08d803a5..2baa56a33 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/Utils/SerialDriver.cs @@ -257,9 +257,17 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils _responseReceived.Set(); } } - catch (TimeoutException te) + catch (TimeoutException) { - // Ignore shutdown race conditions + log.WarnFormat("DataReceivedHandler() - Read timeout on {0}.", GetPortName(sender)); + } + catch (System.IO.IOException ex) + { + log.WarnFormat("DataReceivedHandler() - I/O operation on {0} was aborted: {1}", GetPortName(sender), ex.Message); + } + catch (InvalidOperationException ex) + { + log.WarnFormat("DataReceivedHandler() - Serial port {0} was closed while receiving data: {1}", GetPortName(sender), ex.Message); } finally { @@ -267,6 +275,12 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.Utils } } } + + private static string GetPortName(object sender) + { + SerialPort port = sender as SerialPort; + return port != null ? port.PortName : ""; + } public byte[] SendAndWait(byte[] data, int timeoutMs) { diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs index b769eb77f..4d1f985a4 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs @@ -188,6 +188,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication TextBox[] messages; CheckBoxImage[] checkBoxes; static int[] ckbIndex; + static IList displayedHeadPositions0; static bool[] ckbState; static IList iperlHeads; @@ -345,7 +346,24 @@ namespace TBF.Rig.TestMethods.iPerlCommunication } WaterMetersCount = iperlHeads.Count; - ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize); + IList displayPositions0 = iperlHeads + .Select(head => head.Position - 1) + .ToList(); + + log.WarnFormat( + "IPERL_DIALOG_LAYOUT_V3 Prepare: Assembly={0}, Version={1}, RegisterReaders={2}, Heads={3}, DisplayPositions=[{4}], ReaderIndexes=[{5}]", + typeof(iPerlCommunicationForm).Assembly.Location, + typeof(iPerlCommunicationForm).Assembly.GetName().Version, + ProcessData.RegisterReaders.Length, + string.Join(", ", iperlHeads.Select((head, index) => + string.Format("local{0}:{1}/Position={2}", index, head.Name, head.Position))), + string.Join(",", displayPositions0.Select(position => position + 1)), + string.Join(",", waterMeterPositions0)); + + ShuffleTextBoxes( + WaterMetersCount, + ProcessData.LineSize, + displayPositions0); /// /// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc.. @@ -386,7 +404,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// /// Number of watermeters /// Number of watermeters in one line - void ShuffleTextBoxes(int wmsCount, int lineSize) + void ShuffleTextBoxes(int wmsCount, int lineSize, IList positions0 = null) { labels = new Label[MaxTextBoxesCount] { @@ -421,21 +439,62 @@ namespace TBF.Rig.TestMethods.iPerlCommunication checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48, }; ckbIndex = new int[MaxTextBoxesCount]; + for (int i = 0; i < ckbIndex.Length; i++) + { + ckbIndex[i] = -1; + } ckbState = new bool[MaxTextBoxesCount]; textBoxesCount = MaxTextBoxesCount; /// - if (wmsCount < textBoxesCount && lineSize > 0) + log.WarnFormat( + "IPERL_DIALOG_LAYOUT_V3 Shuffle start: wmsCount={0}, lineSize={1}, editMode={2}, positions=[{3}]", + wmsCount, + lineSize, + checkBoxesEditMode, + positions0 == null ? "" : string.Join(",", positions0.Select(position => position + 1))); + + if (positions0 != null && positions0.Count == wmsCount) + { + int layoutLines = lineSize > 0 + ? (ProcessData.WMsCount + lineSize - 1) / lineSize + : 1; + int layoutGap = layoutLines > 0 + ? (MaxTextBoxesCount - ProcessData.WMsCount) / layoutLines + : 0; + + for (int dest = 0; dest < positions0.Count; dest++) + { + int headPosition0 = positions0[dest]; + int visualLine = lineSize > 0 ? headPosition0 / lineSize : 0; + int origin = headPosition0 + visualLine * layoutGap; + if (origin < 0 || origin >= MaxTextBoxesCount) + throw new ArgumentOutOfRangeException(nameof(positions0)); + + labels[dest] = labels[origin]; + counters[dest] = counters[origin]; + messages[dest] = messages[origin]; + checkBoxes[dest] = checkBoxes[origin]; + ckbIndex[origin] = dest; + + log.WarnFormat( + "IPERL_DIALOG_LAYOUT_V3 Map: localIndex={0}, headPosition={1}, visualSlot={2}, labelControl={3}, messageControl={4}, checkBoxControl={5}", + dest, + headPosition0 + 1, + origin + 1, + labels[dest].Name, + messages[dest].Name, + checkBoxes[dest].Name); + } + + textBoxesCount = wmsCount; + } + else if (wmsCount < textBoxesCount && lineSize > 0) { int nrLines = (wmsCount + lineSize - 1) / lineSize; int gap = (textBoxesCount - wmsCount) / nrLines; - for (int i = 0; i < ckbIndex.Length; i++) - { - ckbIndex[i] = -1; /// Initialize with invalid indices - } - int dest = 0; for (int l = 0; l < nrLines; l++) { @@ -454,10 +513,20 @@ namespace TBF.Rig.TestMethods.iPerlCommunication textBoxesCount = wmsCount; } + displayedHeadPositions0 = positions0 != null && positions0.Count == textBoxesCount + ? positions0.ToList() + : Enumerable.Range(0, textBoxesCount).ToList(); + int count = checkBoxesEditMode ? textBoxesCount : Math.Min(textBoxesCount, iperlHeads.Count); for (int j = 0; j < count; j++) { - labels[j].Text = (j + 1).ToString(); + labels[j].Text = (displayedHeadPositions0[j] + 1).ToString(); + + log.WarnFormat( + "IPERL_DIALOG_LAYOUT_V3 Label: localIndex={0}, control={1}, text={2}", + j, + labels[j].Name, + labels[j].Text); } ResizeDlgToFitEnabledControls(); @@ -3009,13 +3078,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// Long bitfield private long GetCheckBoxStates() { - long result = 0; - for (int i = 0; i < 48; i++) + long result = Program.LocalSettings.OptoHeadsEnabled; + for (int localIndex = 0; localIndex < textBoxesCount; localIndex++) { - int wmNr0 = ckbIndex[i]; - if (wmNr0 >= 0 && ckbState[wmNr0]) + int headPosition0 = displayedHeadPositions0[localIndex]; + long mask = 1L << headPosition0; + + if (ckbState[localIndex]) { - result += (1L << wmNr0); + result |= mask; + } + else + { + result &= ~mask; } } return result; @@ -3026,26 +3101,22 @@ namespace TBF.Rig.TestMethods.iPerlCommunication /// private void SetCheckBoxStates(long state) { - CheckBoxImage[] chkBoxes = new CheckBoxImage[48] - { - checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, - checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10, - checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, - checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20, - checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, - checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30, - checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, - checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40, - checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, - checkBoxImage46, checkBoxImage47, checkBoxImage48, - }; - for (int i = 0; i < 48; i++) + log.WarnFormat( + "IPERL_DIALOG_LAYOUT_V3 SetCheckBoxStates: state=0x{0:X12}, displayedHeadPositions=[{1}]", + state, + string.Join(",", displayedHeadPositions0.Select(position => position + 1))); + + for (int localIndex = 0; localIndex < textBoxesCount; localIndex++) { - int wmNr0 = ckbIndex[i]; - if (wmNr0 >= 0) - { - chkBoxes[i].Checked = ckbState[wmNr0] = ((state & (1L << wmNr0)) != 0); - } + int headPosition0 = displayedHeadPositions0[localIndex]; + bool enabled = (state & (1L << headPosition0)) != 0; + checkBoxes[localIndex].Checked = ckbState[localIndex] = enabled; + log.WarnFormat( + "IPERL_DIALOG_LAYOUT_V3 Enabled: headPosition={0}, localIndex={1}, enabled={2}, control={3}", + headPosition0 + 1, + localIndex, + enabled, + checkBoxes[localIndex].Name); } }