diff --git a/Workplace/CheckItems/MyProgressBar.cs b/Workplace/CheckItems/MyProgressBar.cs new file mode 100644 index 000000000..54a926454 --- /dev/null +++ b/Workplace/CheckItems/MyProgressBar.cs @@ -0,0 +1,28 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace Workplace.CheckItems +{ + public class MyProgressBar : ProgressBar + { + public int ColorId = 0; + + public MyProgressBar() + { + this.SetStyle(ControlStyles.UserPaint, true); + } + + protected override void OnPaint(PaintEventArgs e) + { + Rectangle rec = e.ClipRectangle; + + rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4; + if(ProgressBarRenderer.IsSupported) + ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle); + rec.Height = rec.Height - 4; + + Brush brush = (ColorId == 1) ? Brushes.Yellow : (ColorId == 2) ? Brushes.Red : Brushes.Green; + e.Graphics.FillRectangle(brush, 2, 2, rec.Width, rec.Height); + } + } +} diff --git a/Workplace/CheckItems/S640Stream.Designer.cs b/Workplace/CheckItems/S640Stream.Designer.cs index 0bd534915..5a0134da6 100644 --- a/Workplace/CheckItems/S640Stream.Designer.cs +++ b/Workplace/CheckItems/S640Stream.Designer.cs @@ -35,6 +35,7 @@ this.descriptionMaterialuLabel = new System.Windows.Forms.Label(); this.pcbNumberTextBox = new System.Windows.Forms.TextBox(); this.pcbNumberLabel = new System.Windows.Forms.Label(); + this.pcbNumberProgressBar = new MyProgressBar(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); // @@ -95,10 +96,18 @@ this.pcbNumberLabel.TabIndex = 8; this.pcbNumberLabel.Text = "PCB Number"; // + // pcbNumberProgressBar + // + this.pcbNumberProgressBar.Location = new System.Drawing.Point(241, 65); + this.pcbNumberProgressBar.Name = "pcbNumberProgressBar"; + this.pcbNumberProgressBar.Size = new System.Drawing.Size(227, 19); + this.pcbNumberProgressBar.TabIndex = 9; + // // S640Stream // this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.pcbNumberProgressBar); this.Controls.Add(this.pcbNumberLabel); this.Controls.Add(this.pcbNumberTextBox); this.Controls.Add(this.descriptionMaterialuLabel); @@ -123,5 +132,6 @@ private System.Windows.Forms.Label descriptionMaterialuLabel; private System.Windows.Forms.TextBox pcbNumberTextBox; private System.Windows.Forms.Label pcbNumberLabel; + private MyProgressBar pcbNumberProgressBar; } } diff --git a/Workplace/CheckItems/S640Stream.cs b/Workplace/CheckItems/S640Stream.cs index 17d8a2ae3..7ee7bc4f6 100644 --- a/Workplace/CheckItems/S640Stream.cs +++ b/Workplace/CheckItems/S640Stream.cs @@ -1,19 +1,23 @@ /// -/// Copyright (c) 2020 Sensus Slovensko a.s. +/// Copyright (c) 2020-2023 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; +using System.Drawing; using System.IO.Ports; -using System.Linq; using System.Windows.Forms; using log4net; using SharedDatabase.Entities; -using System.Drawing; namespace Workplace.CheckItems { public partial class S640Stream : UserControl, IDevice, ICheckItem { + const Int64 MaxDropoutTime = 500; /// ms + const Int64 MinHoldTime = 2500; /// ms + const Int64 MinBreakTime = 10000; /// ms + + private static readonly ILog log = LogManager.GetLogger(typeof(S640Stream)); public override string ToString() @@ -21,6 +25,7 @@ namespace Workplace.CheckItems return string.Format("S640Stream: {0} {1}", IxPolozky, Part.Name); } + /// /// Check item related variables /// @@ -44,29 +49,36 @@ namespace Workplace.CheckItems /// SerialPort serialPort; /// Used in DebugMode.Normal - const int FramesBufferSize = 32; /// 8 sec @ 4 Hz - S640.DatastreamFrame[] optoData; - int optoDataIx; string partOfTelegram; /// Data unprocessed by ReadDatastream(...), contains incomplete frame + Int64 currentRawVolumeUnwrapped; Int64 currentRawTimeUnwrapped; + S640.DatastreamFrame frame = new S640.DatastreamFrame(); + char[] pcbNrStr = new char[12]; + char[] radioAddrStr = new char[10]; + /// + Int64 validPcbNumber; + Int64 validRadioAddress; + Int64 firstValidTime; + Int64 lastValidTime; + /// + Int64 currentPcbNr; + Int64 currentRadioAddr; + /// /// PCB Number and Radio address from data stream /// public Int64 PcbNumber; public Int64 RadioAddress; /// - IList prwList; - Int64 lastPcbNumber; - Int64 lastNonzeroPcbNumber; + Int64 lastSentNonzeroPcbNumber; S640Stream() { InitializeComponent(); BlackListedCodes = new List(); - prwList = new List(); } /// Empty implementation, might be overriden in derived classes @@ -90,18 +102,16 @@ namespace Workplace.CheckItems public void Initialize() { + partOfTelegram = string.Empty; currentRawVolumeUnwrapped = 0; currentRawTimeUnwrapped = 0; + validPcbNumber = (long)-1; + validRadioAddress = (long)-1; + firstValidTime = 0; + lastValidTime = 0; - partOfTelegram = string.Empty; - - /// Allocate memory for opto-data from iPerl - optoData = new S640.DatastreamFrame[FramesBufferSize]; - for (int i = 0; i < FramesBufferSize; i++) - { - optoData[i] = new S640.DatastreamFrame { DateTime = DateTime.MinValue }; - } - optoDataIx = 0; + sendPcbNr = false; + lastSentNonzeroPcbNumber = (long)-1; /// Prepare serial port string comPortName = string.Format("COM{0}", Program.LocalSettings.ScaleSerialPort); @@ -112,64 +122,84 @@ namespace Workplace.CheckItems log.FatalFormat("{0} initialized: {1}", Name, this); } - public void ClearCode() { } public void SubmitCode(string code) { } bool hasFocus; - bool sendLastPcbNr; + bool sendPcbNr; private void setFocusButton_Click(object sender, EventArgs e) { - if (!hasFocus && !sendLastPcbNr && PcbNumber != 0 && PcbNumber != lastNonzeroPcbNumber) + setFocusButton.Text = ">"; + + if (!hasFocus && !sendPcbNr && PcbNumber != 0 && PcbNumber != lastSentNonzeroPcbNumber) { - lastNonzeroPcbNumber = PcbNumber; - sendLastPcbNr = true; + sendPcbNr = true; } hasFocus = true; - setFocusButton.Text = ">"; - parent.OnFocusPressed(this, new FocusPressedEventArgs(IxPolozky, Part.CodeLocation)); + parent.OnFocusPressed(this, new FocusPressedEventArgs(IxPolozky, Part.CodeLocation)); } public void ResetFocus() { - hasFocus = false; setFocusButton.Text = ""; + hasFocus = false; } public void SetFocus() { - if (!hasFocus && !sendLastPcbNr && PcbNumber != 0 && PcbNumber != lastNonzeroPcbNumber) + setFocusButton.Text = ">"; + + if (!hasFocus && !sendPcbNr && PcbNumber != 0 && PcbNumber != lastSentNonzeroPcbNumber) { - lastNonzeroPcbNumber = PcbNumber; - sendLastPcbNr = true; + sendPcbNr = true; } hasFocus = true; - setFocusButton.Text = ">"; } public void RunDeviceBefore() { - lastPcbNumber = PcbNumber; - ReadDatastream(); - ProcessBuffer_UpdatePcbNrAndRA(); - pcbNumberTextBox.Text = (PcbNumber != 0) ? PcbNumber.ToString() : string.Empty; /// Always displayed - - //if (sendLastPcbNr) - //{ - // sendLastPcbNr = false; - // parent.OnBarcodeReceived(this, new BarcodeReceivedEventArgs(lastNonzeroPcbNumber.ToString(), IxPolozky, - // Part.CodeLocation, PartError.None)); - //} - // - //if (hasFocus && PcbNumber != 0 && PcbNumber != lastNonzeroPcbNumber) - - if (PcbNumber != 0 && PcbNumber != lastNonzeroPcbNumber) + /// Send if required + if (sendPcbNr) { - lastNonzeroPcbNumber = PcbNumber; - parent.OnBarcodeReceived(this, new BarcodeReceivedEventArgs(PcbNumber.ToString(), IxPolozky, - Part.CodeLocation, PartError.None)); + lastSentNonzeroPcbNumber = PcbNumber; + sendPcbNr = false; + if (PcbNumber > 0) + { + parent.OnBarcodeReceived(this, + new BarcodeReceivedEventArgs(PcbNumber.ToString(), IxPolozky, Part.CodeLocation, PartError.None)); + } } + + ReadDatastream(); + + if (hasFocus && PcbNumber != 0 && PcbNumber != lastSentNonzeroPcbNumber) + { + /// This control owned focus and the PcbNumber became valid + sendPcbNr = true; + } + + /// Send if required + if (sendPcbNr) + { + lastSentNonzeroPcbNumber = PcbNumber; + sendPcbNr = false; + if (PcbNumber > 0) + { + parent.OnBarcodeReceived(this, + new BarcodeReceivedEventArgs(PcbNumber.ToString(), IxPolozky, Part.CodeLocation, PartError.None)); + } + } + + /// Update UI + pcbNumberTextBox.Text = (currentPcbNr > 0) ? currentPcbNr.ToString() : string.Empty; /// Always displayed + /// + int denominator = (currentPcbNr == (Int64)(-1)) ? (int)MinBreakTime : (int)MinHoldTime; + int numerator = Math.Min(Math.Max(0, + Convert.ToInt32((currentPcbNr == (Int64)(-1)) ? MinBreakTime - lastValidTime + firstValidTime : lastValidTime - firstValidTime)), + denominator); + pcbNumberProgressBar.Value = (currentPcbNr != 0) ? (100 * numerator / denominator) : 0; + pcbNumberProgressBar.ColorId = (currentPcbNr > 0) ? 0 : 1; } public void RunDeviceAfter() { } @@ -238,7 +268,7 @@ namespace Workplace.CheckItems { /// No CR+LF found =>stop processing => wait for more characters in the buffer in the next invocation partOfTelegram = allRcvd; - return; + break; } else if (pos < S640.DatastreamFrame.FrameLength - 2) { @@ -247,24 +277,79 @@ namespace Workplace.CheckItems } else { - bool frameOk = optoData[optoDataIx].UpdateFromString(allRcvd.Substring(pos - S640.DatastreamFrame.FrameLength + 2, S640.DatastreamFrame.FrameLength), - ref currentRawVolumeUnwrapped, ref currentRawTimeUnwrapped); + bool frameOk = frame.UpdateFromString(allRcvd.Substring(pos - S640.DatastreamFrame.FrameLength + 2, + S640.DatastreamFrame.FrameLength), + ref currentRawVolumeUnwrapped, + ref currentRawTimeUnwrapped); if (frameOk) { - /// Frame OK => Move to the next frame - optoDataIx++; - if (optoDataIx >= FramesBufferSize) optoDataIx = 0; - } - else - { - /// Invalid frame => Invalidate it (age it) - optoData[optoDataIx].DateTime = DateTime.MinValue; + Array.Copy(frame.Data, 0, pcbNrStr, 0, 12); + Array.Copy(frame.Data, 12, radioAddrStr, 0, 10); + if (Int64.TryParse(new string(pcbNrStr), out currentPcbNr) && Int64.TryParse(new string(radioAddrStr), out currentRadioAddr) + && currentPcbNr != 0 && currentRadioAddr != 0) + { + if (currentRawTimeUnwrapped - lastValidTime <= MaxDropoutTime && + currentPcbNr == validPcbNumber && + currentRadioAddr == validRadioAddress && + currentPcbNr != lastSentNonzeroPcbNumber) + { + /// No datastream dropout and data have not changed: extend the validity time + lastValidTime = currentRawTimeUnwrapped; + + if ((lastValidTime - firstValidTime) >= MinHoldTime) + { + PcbNumber = validPcbNumber; + RadioAddress = validRadioAddress; + } + } + else if (currentPcbNr != lastSentNonzeroPcbNumber) + { + /// Either a datastream dropout or data changed: consider this frame to be the first one for evaluation + validPcbNumber = currentPcbNr; + validRadioAddress = currentRadioAddr; + firstValidTime = currentRawTimeUnwrapped; + lastValidTime = currentRawTimeUnwrapped; + + PcbNumber = 0; + RadioAddress = 0; + } + } } allRcvd = allRcvd.Substring(pos + 2); } } } + + if (receivedBytes == 0 || currentPcbNr == lastSentNonzeroPcbNumber || currentPcbNr == (long)-1) + { + /// No data received (= dropout, but no new data) + currentPcbNr = (long)-1; + currentRadioAddr = (long)-1; + + if (currentPcbNr == validPcbNumber && currentRadioAddr == validRadioAddress) + { + /// Next time + lastValidTime = lastValidTime + (long)Const.Interval; + } + else + { + /// First time + firstValidTime = lastValidTime + (long)Const.Interval; + lastValidTime = firstValidTime; + validPcbNumber = currentPcbNr; + validRadioAddress = currentRadioAddr; + + PcbNumber = 0; + RadioAddress = 0; + } + + if ((lastValidTime - firstValidTime) >= MinBreakTime) + { + PcbNumber = validPcbNumber; + RadioAddress = validRadioAddress; + } + } } catch (Exception e) { @@ -275,42 +360,5 @@ namespace Workplace.CheckItems } } } - - void ProcessBuffer_UpdatePcbNrAndRA() - { - DateTime now = DateTime.Now; - - char[] pcbNrStr = new char[12]; - char[] radioAddrStr = new char[10]; - Int64 pcbNr; - Int64 radioAddr; - - prwList.Clear(); - for (int i = 0; i < FramesBufferSize; i++) - { - double age = (now - optoData[i].DateTime).TotalSeconds; - if (age < 5) - { - Array.Copy(optoData[i].Data, 0, pcbNrStr, 0, 12); - Array.Copy(optoData[i].Data, 12, radioAddrStr, 0, 10); - if (Int64.TryParse(new string(pcbNrStr), out pcbNr) && Int64.TryParse(new string(radioAddrStr), out radioAddr)) - { - S640.PcbnrRadioaddrWeight.Accumulate(prwList, pcbNr, radioAddr, 5 - age); - } - } - } - - if (prwList.Count > 0) - { - prwList = prwList.OrderByDescending(x => x.Weight).ToList(); - PcbNumber = prwList[0].PcbNr; - RadioAddress = prwList[0].RadioAddr; - } - else - { - PcbNumber = 0; - RadioAddress = 0; - } - } } } diff --git a/Workplace/Const.cs b/Workplace/Const.cs new file mode 100644 index 000000000..3cfab0101 --- /dev/null +++ b/Workplace/Const.cs @@ -0,0 +1,9 @@ +using System; + +namespace Workplace +{ + public static class Const + { + public const int Interval = 400; /// ms + } +} diff --git a/Workplace/Properties/AssemblyInfo.cs b/Workplace/Properties/AssemblyInfo.cs index 730a38863..d49677b81 100644 --- a/Workplace/Properties/AssemblyInfo.cs +++ b/Workplace/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Workplace")] -[assembly: AssemblyCopyright("Copyright © 2015-2021")] +[assembly: AssemblyCopyright("Copyright © 2015-2023")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.17.0")] -[assembly: AssemblyFileVersion("3.1.17.0")] +[assembly: AssemblyVersion("3.1.19.0")] +[assembly: AssemblyFileVersion("3.1.19.0")] diff --git a/Workplace/Workplace.csproj b/Workplace/Workplace.csproj index a12279aba..0d965895f 100644 --- a/Workplace/Workplace.csproj +++ b/Workplace/Workplace.csproj @@ -95,6 +95,9 @@ Keyboard.cs + + Component + UserControl @@ -122,6 +125,7 @@ SNGeneratorPrinter.cs + Form diff --git a/Workplace/WorkplaceDlg.cs b/Workplace/WorkplaceDlg.cs index 1789c73f5..933939a71 100644 --- a/Workplace/WorkplaceDlg.cs +++ b/Workplace/WorkplaceDlg.cs @@ -189,7 +189,7 @@ namespace Workplace /// Timer for regular 1 second ticks runDeviceTimer = new System.Windows.Forms.Timer(); - runDeviceTimer.Interval = 1000; // ms + runDeviceTimer.Interval = Const.Interval; runDeviceTimer.Tick += new EventHandler(runDeviceTimer_Tick); runDeviceTimer.Start(); @@ -1315,9 +1315,17 @@ namespace Workplace k.ClearCode(); k.ResetFocus(); } - if (komponenty.Count > 0) + if (komponenty.Count >= 1) { - komponenty[0].SetFocus(); + if (komponenty.Count >= 2 && komponenty[0] is CheckItems.SNGeneratorPrinter + && komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator) + { + komponenty[1].SetFocus(); + } + else + { + komponenty[0].SetFocus(); + } } if ((recordProcessing != null) && !wasAlreadyTested && componentsSaved)