Proof-of-concept of IQ gathering.
This commit is contained in:
parent
c7188b56c5
commit
c618e87a4a
@ -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;
|
||||
/// </summary>
|
||||
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<ImDrawCmdPtr> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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<TunerMetadata> 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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,8 @@ namespace skyscraper5.src.Skyscraper.FrequencyListGenerator
|
||||
ModFailure = 106,
|
||||
PlsFailure = 107,
|
||||
BlScanFailure = 108,
|
||||
DataSaving = 4
|
||||
DataSaving = 4,
|
||||
IqCollecting = 5,
|
||||
IqSaving = 6
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user