From b4dc0d471fb7528d3501022291b8916ca6ecc19b Mon Sep 17 00:00:00 2001 From: Henning von Kielpinski Date: Sat, 9 Dec 2023 14:58:12 +0100 Subject: [PATCH] Increased performance. NEW Smoothing for text. Adjustable sample rate. Use of a statusbar. --- Form1.Designer.cs | 19 +++++++- Form1.cs | 115 ++++++++++++++++++++++++++++------------------ Form1.resx | 12 +++++ 3 files changed, 100 insertions(+), 46 deletions(-) diff --git a/Form1.Designer.cs b/Form1.Designer.cs index 8a9720f..07eba34 100644 --- a/Form1.Designer.cs +++ b/Form1.Designer.cs @@ -29,6 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); pictureBox1 = new PictureBox(); radioButton1 = new RadioButton(); timer1 = new System.Windows.Forms.Timer(components); @@ -58,6 +59,7 @@ private void InitializeComponent() toolStripStatusLabel5 = new ToolStripStatusLabel(); toolStripStatusLabel3 = new ToolStripStatusLabel(); toolStripStatusLabel6 = new ToolStripStatusLabel(); + toolStripDropDownButton1 = new ToolStripDropDownButton(); toolStripStatusLabel7 = new ToolStripStatusLabel(); toolStripStatusLabel8 = new ToolStripStatusLabel(); ((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit(); @@ -319,7 +321,7 @@ private void InitializeComponent() // statusStrip1 // statusStrip1.ImageScalingSize = new Size(24, 24); - statusStrip1.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel1, toolStripStatusLabel4, toolStripStatusLabel2, toolStripStatusLabel5, toolStripStatusLabel3, toolStripStatusLabel6, toolStripStatusLabel7, toolStripStatusLabel8 }); + statusStrip1.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel1, toolStripStatusLabel4, toolStripStatusLabel2, toolStripStatusLabel5, toolStripStatusLabel3, toolStripStatusLabel6, toolStripDropDownButton1, toolStripStatusLabel7, toolStripStatusLabel8 }); statusStrip1.Location = new Point(0, 1197); statusStrip1.Name = "statusStrip1"; statusStrip1.Size = new Size(1640, 36); @@ -375,11 +377,23 @@ private void InitializeComponent() toolStripStatusLabel6.Text = "0"; toolStripStatusLabel6.TextAlign = ContentAlignment.MiddleRight; // + // toolStripDropDownButton1 + // + toolStripDropDownButton1.DisplayStyle = ToolStripItemDisplayStyle.Text; + toolStripDropDownButton1.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + toolStripDropDownButton1.Image = (Image)resources.GetObject("toolStripDropDownButton1.Image"); + toolStripDropDownButton1.ImageTransparentColor = Color.Magenta; + toolStripDropDownButton1.Name = "toolStripDropDownButton1"; + toolStripDropDownButton1.Size = new Size(153, 33); + toolStripDropDownButton1.Text = "Sampling Rate"; + toolStripDropDownButton1.TextImageRelation = TextImageRelation.Overlay; + // // toolStripStatusLabel7 // + toolStripStatusLabel7.BorderSides = ToolStripStatusLabelBorderSides.Left; toolStripStatusLabel7.Font = new Font("Segoe UI", 9F, FontStyle.Bold); toolStripStatusLabel7.Name = "toolStripStatusLabel7"; - toolStripStatusLabel7.Size = new Size(167, 29); + toolStripStatusLabel7.Size = new Size(171, 29); toolStripStatusLabel7.Text = "Connection Status"; // // toolStripStatusLabel8 @@ -446,5 +460,6 @@ private void InitializeComponent() private ToolStripStatusLabel toolStripStatusLabel7; private ToolStripStatusLabel toolStripStatusLabel8; private CheckBox checkBox5; + private ToolStripDropDownButton toolStripDropDownButton1; } } diff --git a/Form1.cs b/Form1.cs index a511366..b7c2fdb 100644 --- a/Form1.cs +++ b/Form1.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; using SaleaeDeviceSdkDotNet; +using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace CGATest @@ -34,7 +35,7 @@ public partial class Form1 : Form public volatile StreamReader vIn; public volatile ConcurrentQueue bufferedData = new ConcurrentQueue(); - + static int maxBuffer = 100000000; bool endofstream = false; @@ -99,15 +100,16 @@ private void TShowInfo(object myObject, EventArgs myEventArgs) toolStripStatusLabel4.Text = TB1.ToString(); toolStripStatusLabel5.Text = TB2.ToString(); toolStripStatusLabel6.Text = screens.ToString(); + if (screens < 2) reset(); screens = 0; } - + private async void TShowPic(object? obj) { Bitmap? resized = null; CancellationToken ct = (CancellationToken)obj; - + await Task.Run(() => { while (true && !ct.IsCancellationRequested) @@ -121,25 +123,24 @@ await Task.Run(() => else // or do we scale up { resized = new Bitmap((Bitmap)newframe, new Size(xResize, yResize)); + pictureBox1.Image = (Bitmap)resized.Clone(); resized.Dispose(); } + + newframe.Dispose(); newframeisready = false; - } + } // Wait for a refresh - Thread.Sleep(1); + Thread.Sleep(10); } } ); } - - - - - + -// Read input stream to buffer -private async void TBufferInput(object? o) + // Read input stream to buffer + private async void TBufferInput(object? o) { int buffSize = 32; bool loop = true; @@ -152,9 +153,7 @@ private async void TBufferInput(object? o) while (loop && vIn != null && !ct.IsCancellationRequested) { readchar = await vIn.ReadAsync(c, 0, buffSize); - TB3 = bufferedData.Count; int i = 0; - // if (TB3 { if (restartRequired) { - mLogic.ReadStart(); - toolStripStatusLabel8.Text = "Connected to Logic with " + mSampleRateHz + "Hz"; + mLogic.ReadStart(); + toolStripStatusLabel8.Text = "Connected to Logic with " + mLogic.SampleRateHz + "Hz"; } restartRequired = false; Thread.Sleep(10); @@ -201,7 +200,6 @@ private async void Form1_Shown(object sender, EventArgs e) CancellationTokenSource CTSTSaleaeWatchdog = new CancellationTokenSource(); CancellationToken CTTSaleaeWatchdog = CTSTSaleaeWatchdog.Token; - Thread Handler_TShowPic = null; CancellationTokenSource CTSshowpic = new CancellationTokenSource(); CancellationToken CTShowPic = CTSshowpic.Token; @@ -246,6 +244,22 @@ await Task.Run(() => } }); + List sample_rates = new List(); + if (mLogic != null) + sample_rates = mLogic.GetSupportedSampleRates(); + if (mLogic16 != null) + sample_rates = mLogic16.GetSupportedSampleRates(); + + + //Sample Rates + for (int i = 0; i < sample_rates.Count; ++i) + { + uint newSampleRate = sample_rates[i]; + ToolStripItem item = toolStripDropDownButton1.DropDownItems.Add(string.Format(sample_rates[i].ToString(), newSampleRate ), null, new EventHandler(SetSamplingRate)); + item.Tag = newSampleRate; + } + + toolStripStatusLabel8.ForeColor = Color.Green; toolStripStatusLabel8.Text = "Connected to Logic with " + mSampleRateHz + "Hz"; @@ -270,7 +284,7 @@ await Task.Run(() => // If finished, clean up threads if (Handler_TBufferInput != null) CTSTBufferInput.Cancel(); if (Handler_TSaleaeWatchdog != null) CTSTSaleaeWatchdog.Cancel(); - if (Handler_TShowPic != null) CTSshowpic.Cancel(); + //if (Handler_TShowPic != null) CTSshowpic.Cancel(); } //Saleae @@ -352,14 +366,17 @@ public async Task Main(object sender, EventArgs e) await Task.Run(async () => { newpic = await CP; - CP.Dispose(); }); + if (xposmax >= width) xposmax = width; + if (yposmax >= height) yposmax = height; + if (newpic != null) // Valid picture received, extract only the area which has data in it { RectangleF cloneRect = new RectangleF(0, 0, xposmax_b, yposmax_b); - if (newpic.Height > 5) newframe = (Bitmap)newpic.Clone(cloneRect, PixelFormat.DontCare); + //if (newpic.Height > 5) newframe = (Bitmap)newpic.Clone(cloneRect, PixelFormat.DontCare); + newframe = (Bitmap)newpic.Clone(); newpic.Dispose(); newframeisready = true; @@ -381,8 +398,8 @@ await Task.Run(async () => private async Task CreatePicture(object sender, EventArgs e) { - Bitmap bmp = new Bitmap((xposmax_b > 10 ? xposmax : 10), (yposmax_b > 10 ? yposmax_b : 10)); - + Bitmap bmp = new Bitmap((xposmax_b > 10 ? xposmax : 10), (yposmax_b > 10 ? yposmax_b : 10)); + int readchar, readFail; int rawdata = 0; bool hsync_raw = false, vsync_raw = false; @@ -404,7 +421,7 @@ private async Task CreatePicture(object sender, EventArgs e) bool loop = true; bool vcompositeflag = false, armed = false; - + //experiment BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = data.Stride; @@ -412,7 +429,7 @@ private async Task CreatePicture(object sender, EventArgs e) await Task.Run(() => { - while (loop && !endofstream) + while (loop && !endofstream) { // A timeout in case no data is added to the queue. Multibyte read-async can get stuck then readFail = 0; @@ -427,7 +444,7 @@ await Task.Run(() => // Give it some time Thread.Sleep(1); } - + // Catch standard case of file end if (readchar == -1) { @@ -582,10 +599,10 @@ await Task.Run(() => if (!hsync) // Outside hsync cyle { - int xoffset = 0 ; + int xoffset = 0; if (hsyncc) // Just coming from a hsync signal, new line { - + // expectation setting and limiter xposmax = xpos; // new line and reset horizontal @@ -598,30 +615,30 @@ await Task.Run(() => // Find the shortest hsync pulse if (hsync_p < hduration) hduration = hsync_p; // If there is jitter, skip pixels - xoffset = (hsync_p-hduration); + xoffset = (hsync_p - hduration); xpos = xoffset; hsync_p = 0; } else // No sync and no recent changes: Set horizontal pixels { - if (xpos>0 && xpos < width && xpos < xposmax_b && ypos < yposmax_b) // Within defined bitmap ? + if (xpos > 0 && xpos < width && xpos < xposmax_b && ypos < yposmax_b ) // Within defined bitmap ? { byte setblue = blue; byte setgreen = green; byte setred = red; - + unsafe { byte* ptr = (byte*)data.Scan0; if (smoothing) { - if (!(blue == bline[xpos, ypos])) setblue = bline[xpos-xoffset, ypos]; - if (!(green == gline[xpos, ypos])) setgreen = gline[xpos-xoffset, ypos]; - if (!(red == rline[xpos, ypos])) setred = rline[xpos-xoffset, ypos]; + if (!(blue == bline[xpos, ypos])) setblue = bline[xpos - xoffset, ypos]; + if (!(green == gline[xpos, ypos])) setgreen = gline[xpos - xoffset, ypos]; + if (!(red == rline[xpos, ypos])) setred = rline[xpos - xoffset, ypos]; } - + ptr[(xpos * 3) + ypos * stride] = setblue; ptr[(xpos * 3) + ypos * stride + 1] = setgreen; ptr[(xpos * 3) + ypos * stride + 2] = setred; @@ -629,14 +646,14 @@ await Task.Run(() => if (smoothing) { - bline[xpos, ypos] = (byte)((setblue*2 + blue) / 3); - gline[xpos, ypos] = (byte)((setgreen *2+ green) / 3); - rline[xpos, ypos] = (byte)((setred *2 + red) / 3); + bline[xpos, ypos] = (byte)((setblue * 2 + blue) / 3); + gline[xpos, ypos] = (byte)((setgreen * 2 + green) / 3); + rline[xpos, ypos] = (byte)((setred * 2 + red) / 3); } xpos++; } else xpos++; // If no pixel are set, we are still interested in the high value - } + } } else hsync_p++; } @@ -651,20 +668,21 @@ await Task.Run(() => // Visualize parameters TB1 = xposmax_b; TB2 = yposmax_b; - + if (xposmax_b < 10 || yposmax_b < 10 || endofstream) return null; // received frame is too small or stream stopped, discard else { //experiment bmp.UnlockBits(data); //experiment - + return bmp; } + } - private void reset() + private void reset() { // Reset syncpulses = 0; sync_long = 0; @@ -681,7 +699,6 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e) Console.WriteLine("Sorry, the device is not currently streaming."); else mLogic.Stop(); - } @@ -782,8 +799,18 @@ private void button1_Click(object sender, EventArgs e) private void checkBox5_CheckedChanged(object sender, EventArgs e) { smoothing = !smoothing; - checkBox5.Checked= smoothing; + checkBox5.Checked = smoothing; } - } + + private void SetSamplingRate(object sender, EventArgs e) + { + ToolStripItem item = (ToolStripItem)sender; + uint newRate = (uint)item.Tag; + mLogic.Stop(); + Thread.Sleep(100); + mLogic.SampleRateHz = newRate; + restartRequired = true; + } +} } diff --git a/Form1.resx b/Form1.resx index ef8ebc5..304d602 100644 --- a/Form1.resx +++ b/Form1.resx @@ -123,6 +123,18 @@ 135, 17 + + + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAEKSURBVEhL3ZG9DsFQHMXvczDZvIOtXsHObuhqkViI3Quw + 6CYmNoMYJJ0NBiFFIoIytOuf0+TeXP3yde+iyS+3OcP53Z4y3/dJJ4HAsiwyTVMp6BQCBIZhKAWdEcHV + vSlBmeB82NFy1KLluEWOPRC5MoHdMWhazwi4RJlALgf4EuT6BI+5kCsTrGddUY658E+QvyXYHq9UnRyC + U87f4aUApcXhnrI9Jzg/laQKFntXlHM+lSQK5psL5fvbp/JvJLGCQqmSWM5JkiCT84igXGtSrruKLQ0T + luAdmZxHBG37FFuWBC/j5XKOmX8WAH7rcI6ZMffPgjQwN2bXJgDo/COBTpjneQ2dML0PY3cISreGe8HM + qgAAAABJRU5ErkJggg== + + 25