diff --git a/GUIs/skyscraper8.UI.ImGui/Echo/UserInterface/Backend/ImGuiDevice.cs b/GUIs/skyscraper8.UI.ImGui/Echo/UserInterface/Backend/ImGuiDevice.cs index c97cb29..fbc2fd4 100644 --- a/GUIs/skyscraper8.UI.ImGui/Echo/UserInterface/Backend/ImGuiDevice.cs +++ b/GUIs/skyscraper8.UI.ImGui/Echo/UserInterface/Backend/ImGuiDevice.cs @@ -1,12 +1,13 @@ -using System; +using Echo.Core.Common.Packed; +using ImGuiNET; +using SDL2; +using SDL2Demo.SdlWrapper; +using skyscraper8.Skyscraper.Plugins; +using System; using System.Numerics; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using Echo.Core.Common.Packed; -using ImGuiNET; -using SDL2; -using SDL2Demo.SdlWrapper; using testdrid.SdlWrapper; namespace Echo.UserInterface.Backend; @@ -20,7 +21,8 @@ using static SDL; /// public sealed unsafe class ImGuiDevice : IDisposable, IEventConsumer { - public ImGuiDevice(IntPtr window, IntPtr renderer) + private static PluginLogger logger = PluginLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + public ImGuiDevice(IntPtr window, IntPtr renderer) { this.window = window; this.renderer = renderer; @@ -483,6 +485,7 @@ public sealed unsafe class ImGuiDevice : IDisposable, IEventConsumer else _ = SDL_ShowCursor((int)SDL_bool.SDL_FALSE); } + private uint numErrors; void ExecuteCommandList(ImDrawListPtr list, in Float4 clipOffset, in Float4 clipSize) { ImPtrVector buffer = list.CmdBuffer; @@ -523,7 +526,10 @@ public sealed unsafe class ImGuiDevice : IDisposable, IEventConsumer (int)command.ElemCount, sizeof(ushort) ) != 0) { - throw SdlException.GenerateException(); + numErrors++; + SdlException sdlException = SdlException.GenerateException(); + //We can tolerate the Geometry Renderer going sideways a few times + logger.Log(PluginLogLevel.Error, String.Format("{0}, ({1}x)",sdlException.ToString(),numErrors)); } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/BlindscanProgressWindow.cs b/GUIs/skyscraper8.UI.ImGui/Forms/BlindscanProgressWindow.cs index 8715bf0..ab30d57 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/BlindscanProgressWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/BlindscanProgressWindow.cs @@ -36,7 +36,8 @@ namespace SDL2Demo.Forms ImGui.Text("Progress: "); ImGui.SameLine(); ImGui.SetNextItemWidth(100); - ImGui.ProgressBar(Convert.ToSingle(frac) / 100.0f, Vector2.Zero, String.Format("{0:0.##}%", frac)); + float progressBarFrac = Convert.ToSingle(frac) / 100.0f; + ImGui.ProgressBar(progressBarFrac, Vector2.Zero, String.Format("{0:0.##}%", frac)); ImGui.Text(String.Format("Estimated Time Remaining: {0}", remainTime.ToString())); ImGui.Text(String.Format("Starting Frequency: {0} kHz", Start)); diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/IqWindow.cs b/GUIs/skyscraper8.UI.ImGui/Forms/IqWindow.cs index ef7d107..db45361 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/IqWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/IqWindow.cs @@ -10,118 +10,93 @@ using Echo.Core.Common.Packed; using Echo.UserInterface.Backend; using ImGuiNET; using SDL2; +using skyscraper8.Skyscraper.Drawing; using testdrid.SdlWrapper; namespace SDL2Demo.Forms { - internal class IqWindow : IRenderable + internal class IqWindow : IRenderable, IDisposable { private readonly Renderer _renderer; private readonly Texture _texture; private readonly bool imgui; private readonly Vector2 _imguiVector; - private bool noDraw; - public void ResetIqGraphic() + private readonly IqChartData _iqPlot; + + public IqWindow(Renderer renderer, IqChartData iqPlot) { - noDraw = true; - iqData = new byte[256][]; - for (int i = 0; i < iqData.Length; i++) - { - iqData[i] = new byte[256]; - } - noDraw = false; - } - - public IqWindow(Renderer renderer) - { - ResetIqGraphic(); _renderer = renderer; _texture = Texture.Create(_renderer, SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, 256, 256); _texture.SetDrawBlendMode(SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); + _iqPlot = iqPlot; imgui = false; } - public IqWindow(ImGuiDevice imGuiDevice) + public IqWindow(ImGuiDevice imGuiDevice, IqChartData iqPlot) { - ResetIqGraphic(); IntPtr textureIntPtr = imGuiDevice.CreateTexture(new Int2(256, 256), true, !BitConverter.IsLittleEndian); _texture = Texture.FromIntPointer(textureIntPtr); _renderer = null; _imguiVector = new Vector2(256, 256); - imgui = true; + _iqPlot = iqPlot; + imgui = true; } - - private byte[][] iqData; - private ulong iqErrors; + public Point RenderOffset { get; set; } - public void PushIqSample(byte i, byte q) - { - if (iqData[i][q] == byte.MaxValue) - return; - - iqData[i][q]++; - } - private void RenderInternal() { - if (noDraw) - return; - byte b = 0; - try - { - for (int y = 0; y < iqData.Length; y++) - { - if (noDraw) - return; - for (int x = 0; x < iqData[y].Length; x++) - { - if (noDraw) - return; - b = iqData[y][x]; - if (b != 0) - _texture.SetPixel(x, y, 255, (byte)(255 - b), 0, 0); - else - _texture.SetPixel(x, y, 0, 0, 0, 0); - } - } - } - catch (NullReferenceException e) - { - iqErrors++; - } + byte b = 0; + byte[][] iq = _iqPlot.IQ; + for (int y = 0; y < 256; y++) + { + + for (int x = 0; x < 256; x++) + { + + b = iq[x][y]; + if (b != 0) + _texture.SetPixel(x, y, 255, (byte)(255 - b), 0, 0); + else + _texture.SetPixel(x, y, 0, 0, 0, 0); + } + } } public void Render() { - _texture.Lock(); - RenderInternal(); - _texture.Unlock(); + lock (_iqPlot) + { + _texture.Lock(); + RenderInternal(); + _texture.Unlock(); - if (imgui) - { - ImGui.PushStyleVar(ImGuiStyleVar.WindowMinSize, 256); - ImGui.Begin("IQ", ImGuiWindowFlags.NoResize); - ImGui.Image(_texture.Pointer, _imguiVector); - ImGui.End(); - } - else - { - _renderer.Copy(_texture, RenderOffset); - } + if (imgui) + { + ImGui.PushStyleVar(ImGuiStyleVar.WindowMinSize, new Vector2(272, 256)); + ImGui.Begin("IQ", ImGuiWindowFlags.NoResize); + ImGui.ProgressBar(_iqPlot.ProgressFraction, Vector2.Zero, String.Format("{0}% (Z={1})", _iqPlot.ProgressHumanReadable, _iqPlot.ZAxis)); + ImGui.Image(_texture.Pointer, _imguiVector); + ImGui.End(); + ImGui.PopStyleVar(); + } + else + { + _renderer.Copy(_texture, RenderOffset); + } + } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PushIqSamples(sbyte[] iqBuffer) + private bool disposing; + public void Dispose() { - byte i, q; - for (int idx = 0; idx < iqBuffer.Length; idx += 2) - { - i = (byte)(int)(iqBuffer[idx + 0] + sbyte.MaxValue); - q = (byte)(int)(iqBuffer[idx + 1] + sbyte.MaxValue); - PushIqSample(i, q); - } + lock (_iqPlot) + { + disposing = true; + } + + _texture.Dispose(); } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs index 70db551..d7049bc 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs @@ -353,6 +353,27 @@ namespace SDL2Demo.Jobs public SearchResult2 sr2; public bool Satellite { get; private set; } + + public string FrequencyAndPolarityToString() + { + if (Satellite) + { + char polarity; + switch (sr1.Pol) + { + case 0: polarity = 'H'; break; + case 1: polarity = 'V'; break; + case 2: polarity = 'L'; break; + case 3: polarity = 'R'; break; + default: polarity = 'W'; break; //W for WTF? + } + return String.Format("{0}_{1}", sr1.Freq, polarity); + } + else + { + return String.Format("{0}", sr2.Freq); + } + } } public bool RunBlindscan() diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs index 04a337b..81411d3 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs @@ -1,27 +1,30 @@ -using skyscraper5.Skyscraper.Equipment; -using skyscraper5.Skyscraper; -using skyscraper5.src.Skyscraper.FrequencyListGenerator; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using skyscraper5.Skyscraper.IO.CrazycatStreamReader; -using System.IO; -using ImGuiNET; +using ImGuiNET; using SDL2Demo.Forms; -using skyscraper5.Skyscraper.IO; -using static SDL2Demo.Jobs.Blindscan; -using System.Drawing; -using System.Runtime.InteropServices; using SDL2Demo.SdlWrapper; +using skyscraper5.Skyscraper; +using skyscraper5.Skyscraper.Equipment; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper5.Skyscraper.Scraper; using skyscraper5.src.Mpeg2.PacketFilter; +using skyscraper5.src.Skyscraper.FrequencyListGenerator; +using skyscraper8.Skyscraper.Plugins; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using skyscraper8.Skyscraper.Drawing; +using static SDL2Demo.Jobs.Blindscan; namespace SDL2Demo.Jobs { class CoopBlindscan : IRenderable, IJob { + private static PluginLogger logger = PluginLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private IDbBlindscanJobStorage jobStorage; private List tunerMetadataList; private JobContext jobContext; @@ -67,13 +70,15 @@ namespace SDL2Demo.Jobs private bool settingsWindowCaptureFile; private int settingsWindowDiseqc; private int settingsWindowSatellite; + private bool settingsWindowCollectIqGraphs; + public void Render() { if (ImGui.Begin("Blindscan", ref settingsWindowOpen, ImGuiWindowFlags.AlwaysAutoResize)) { if (tunerMetadataList.Count < 2) { - ImGui.Text("You need at least to DVB-S Tuners for the cooperative blindscan."); + ImGui.Text("You need at least two DVB-S Tuners for the cooperative blindscan."); ImGui.End(); return; } @@ -130,6 +135,7 @@ namespace SDL2Demo.Jobs ImGui.Checkbox("Scan High Horizontal Region", ref settingsWindowScanHorizontalHigh); ImGui.Checkbox("Scan Low Vertical Region", ref settingsWindowScanVerticalLow); ImGui.Checkbox("Scan High Vertical Region", ref settingsWindowScanVerticalHigh); + ImGui.Checkbox("Collect IQ Graphs", ref settingsWindowCollectIqGraphs); ImGui.PushID("diseqc"); ImGui.Text("DiSEqC"); @@ -682,6 +688,50 @@ namespace SDL2Demo.Jobs JobContext.Puppets[2].AutoMoveToHome(); JobContext.Puppets[3].AutoMoveToHome(); } + + private IqChartData GatherIQGraphCable() + { + throw new NotImplementedException(); + } + private IqChartData GatherIqGraph() + { + Caps caps = streamReader.GetCaps(); + if (caps.HasFlag(Caps.SR_IQSCAN2)) + { + return GatherIQGraphCable(); + + } + else if (!caps.HasFlag(Caps.SR_IQSCAN)) + { + logger.Log(PluginLogLevel.Error, "Couldn't figure out whether to use IQScan or IQScan2!"); + return null; + } + + IqChartData result = IqChartData.Create(); + IqWindow iqWindow = new IqWindow(JobContext.ImgUiDevice, result); + JobContext.Renderables.Add(iqWindow); + sbyte[] buffer = new sbyte[200]; + while (!result.IsComplete) + { + bool iqScan = streamReader.IQScan(0, buffer, 100); + if (!iqScan) + { + result = null; + logger.Log(PluginLogLevel.Error, "IQScan failed"); + break; + } + result.PushPacket(buffer); + } + + lock (jobContext.Renderables) + { + JobContext.Renderables.Remove(iqWindow); + iqWindow.Dispose(); + iqWindow = null; + } + + return result; + } private void RunSkyscraper(BlindscanResult result) { @@ -789,6 +839,18 @@ namespace SDL2Demo.Jobs throw new NotImplementedException("Couldn't figure out what signal info to use."); } + if (settingsWindowCollectIqGraphs) + { + result.State = BlindscanResultState.IqCollecting; + IqChartData plot = GatherIqGraph(); + result.State = BlindscanResultState.IqSaving; + string fname = String.Format("{0}_{1}.bin", jobInDb.JobGuid.ToString("D"), result.FrequencyAndPolarityToString()); + FileStream fileStream = File.OpenWrite(fname); + plot.SaveTo(fileStream); + fileStream.Flush(); + fileStream.Close(); + } + for (int mis = 0; mis < misCounter; mis++) { if (misMode) diff --git a/GUIs/skyscraper8.UI.ImGui/SdlWrapper/Texture.cs b/GUIs/skyscraper8.UI.ImGui/SdlWrapper/Texture.cs index 7901bb4..60d2a6b 100644 --- a/GUIs/skyscraper8.UI.ImGui/SdlWrapper/Texture.cs +++ b/GUIs/skyscraper8.UI.ImGui/SdlWrapper/Texture.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; @@ -87,6 +88,27 @@ namespace testdrid.SdlWrapper } } + public void Fill(byte a, byte r, byte g, byte b) + { + SDL.SDL_Rect rekt = new SDL.SDL_Rect(); + rekt.h = GetHeight(); + rekt.w = GetWidth(); + rekt.x = 0; + rekt.y = 0; + + uint color = (uint)(a << 24); + color += (uint)(r << 16); + color += (uint)(g << 8); + color += b; + + int sdlFillRect = SDL.SDL_FillRect(Pointer, ref rekt, color); + if (sdlFillRect != 0) + { + throw SdlException.GenerateException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetPixel(int x, int y, byte a, byte r, byte g, byte b) { if (y < 0) diff --git a/skyscraper8/Skyscraper/Drawing/IqChartData.cs b/skyscraper8/Skyscraper/Drawing/IqChartData.cs index 69073cf..2675d4f 100644 --- a/skyscraper8/Skyscraper/Drawing/IqChartData.cs +++ b/skyscraper8/Skyscraper/Drawing/IqChartData.cs @@ -1,16 +1,21 @@ -using System; +using skyscraper5.Skyscraper.IO; +using skyscraper8.Skyscraper.Plugins; +using System; +using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -using skyscraper5.Skyscraper.IO; namespace skyscraper8.Skyscraper.Drawing { public class IqChartData { public const int DESIRABLE_AMOUNT_OF_POINTS = 100000; + private static PluginLogger logger = PluginLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private IqChartData() { IQ = new byte[256][]; @@ -74,7 +79,7 @@ namespace skyscraper8.Skyscraper.Drawing if (IQ[i][q] > progress) { progress = IQ[i][q]; - Console.WriteLine(progress); + logger.Log(PluginLogLevel.Debug, "IQ Z-Axis now at {0}", progress); } } } @@ -120,5 +125,27 @@ namespace skyscraper8.Skyscraper.Drawing scaled = true; } + + public float ProgressFraction + { + get + { + float l = totalSamples; + float r = DESIRABLE_AMOUNT_OF_POINTS; + float x = l / r; + return x; + } + } + + public double ProgressHumanReadable + { + get + { + double frac = ((double)(totalSamples) * 100.0) / (double)(DESIRABLE_AMOUNT_OF_POINTS); + return frac; + } + } + + public byte ZAxis => progress; } } diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanResult.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanResult.cs index 51a2015..b3ee564 100644 --- a/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanResult.cs +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanResult.cs @@ -25,6 +25,8 @@ namespace skyscraper5.src.Skyscraper.FrequencyListGenerator ModFailure = 106, PlsFailure = 107, BlScanFailure = 108, - DataSaving = 4 + DataSaving = 4, + IqCollecting = 5, + IqSaving = 6 } }