diff --git a/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs b/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs index 8a3ccb6..aed5720 100644 --- a/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs +++ b/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs @@ -11,6 +11,7 @@ using skyscraper8.Skyscraper.Scraper.Storage; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Net; using System.Runtime.InteropServices; @@ -314,5 +315,20 @@ namespace skyscraper5.Data WriteObject(fullName, ms); } + + public void StoreRfSpectrum(Guid jobGuid, RfSpectrumData rfSpectrum) + { + if (definetlyKnownFiles == null) + definetlyKnownFiles = new HashSet(); + if (definetlyMissingFiles == null) + definetlyMissingFiles = new HashSet(); + + string fullName = String.Format("/rf/{0}.rf", jobGuid.ToString("D")); + MemoryStream ms = new MemoryStream(); + rfSpectrum.SaveTo(ms); + ms.Position = 0; + + WriteObject(fullName, ms); + } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs b/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs index 58fb6e7..3a97ca3 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs @@ -14,9 +14,9 @@ using testdrid.SdlWrapper; namespace skyscraper8.UI.ImGui.Forms { - internal class SdlScottPlotWindow : SdlWindow + internal class SdlScottPlotWindow : SdlWindow, IDisposable { - private readonly Plot _plot; + protected readonly Plot _plot; private readonly SKBitmap _skBitmap; private readonly SKCanvas _skCanvas; @@ -32,6 +32,7 @@ namespace skyscraper8.UI.ImGui.Forms private int dataLength; protected override void RenderInternal(Texture surface) { + BeforeRender(); _plot.Render(_skCanvas, (int)this._size.X, (int)this._size.Y); nint data0 = surface.GetData0(); @@ -47,5 +48,17 @@ namespace skyscraper8.UI.ImGui.Forms Marshal.Copy(tempBuffer, 0, data0, dataLength); } + + protected virtual void BeforeRender() + { + + } + + public void Dispose() + { + _plot.Dispose(); + _skBitmap.Dispose(); + _skCanvas.Dispose(); + } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindowRfSpectrum.cs b/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindowRfSpectrum.cs new file mode 100644 index 0000000..5e34160 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindowRfSpectrum.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Echo.UserInterface.Backend; +using ScottPlot; +using ScottPlot.Plottables; +using skyscraper5.Dvb.Descriptors; +using skyscraper5.src.InteractionChannel.Model; +using Color = System.Drawing.Color; + +namespace skyscraper8.UI.ImGui.Forms +{ + internal class SdlScottPlotWindowRfSpectrum : SdlScottPlotWindow + { + private DataLogger[] loggers; + + private Color[] colors = new Color[] + { + System.Drawing.Color.FromArgb(52, 152, 152), + System.Drawing.Color.FromArgb(252, 52, 52), + System.Drawing.Color.FromArgb(152, 52, 152), + System.Drawing.Color.FromArgb(52, 52, 252), + }; + + public SdlScottPlotWindowRfSpectrum(ImGuiDevice imGuiDevice) + : base(imGuiDevice, new Plot(), 1000, 200, "RF Spectrum") + { + locakable = new object(); + } + + protected override void BeforeRender() + { + if (_queuedSamples == null) + return; + + lock (locakable) + { + while (_queuedSamples.Count > 0) + { + Tuple value = _queuedSamples.Dequeue(); + if (loggers == null) + loggers = new DataLogger[4]; + if (loggers[(int)value.Item1] == null) + { + loggers[(int)value.Item1] = _plot.Add.DataLogger(); + loggers[(int)value.Item1].LegendText = value.Item1.ToString(); + loggers[(int)value.Item1].Color = ScottPlot.Color.FromColor(colors[(int)value.Item1]); + } + + loggers[(int)value.Item1].Add(value.Item2, value.Item3); + } + } + } + + private Queue> _queuedSamples; + private object locakable; + public void EnqueueSample(SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, int frequency, double sample) + { + if (_queuedSamples == null) + _queuedSamples = new Queue>(); + + lock (locakable) + { + _queuedSamples.Enqueue(new Tuple(polarization, frequency, sample)); + } + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs index de501ce..83fb13e 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/CoopBlindscan.cs @@ -1,6 +1,7 @@ using ImGuiNET; using SDL2Demo.Forms; using SDL2Demo.SdlWrapper; +using skyscraper5.Dvb.Descriptors; using skyscraper5.Skyscraper; using skyscraper5.Skyscraper.Equipment; using skyscraper5.Skyscraper.IO; @@ -8,7 +9,9 @@ using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper5.Skyscraper.Scraper; using skyscraper5.src.Mpeg2.PacketFilter; using skyscraper5.src.Skyscraper.FrequencyListGenerator; +using skyscraper8.Skyscraper.Drawing; using skyscraper8.Skyscraper.Plugins; +using skyscraper8.UI.ImGui.Forms; using System; using System.Collections.Generic; using System.Drawing; @@ -17,7 +20,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -using skyscraper8.Skyscraper.Drawing; +using testdrid.SdlWrapper; using static SDL2Demo.Jobs.Blindscan; namespace SDL2Demo.Jobs @@ -71,6 +74,7 @@ namespace SDL2Demo.Jobs private int settingsWindowDiseqc; private int settingsWindowSatellite; private bool settingsWindowCollectIqGraphs; + private bool settingsWindowCollectRfSpectrum; public void Render() { @@ -136,6 +140,7 @@ namespace SDL2Demo.Jobs ImGui.Checkbox("Scan Low Vertical Region", ref settingsWindowScanVerticalLow); ImGui.Checkbox("Scan High Vertical Region", ref settingsWindowScanVerticalHigh); ImGui.Checkbox("Collect IQ Graphs", ref settingsWindowCollectIqGraphs); + ImGui.Checkbox("Collect RF Spectrum", ref settingsWindowCollectRfSpectrum); ImGui.PushID("diseqc"); ImGui.Text("DiSEqC"); @@ -264,6 +269,15 @@ namespace SDL2Demo.Jobs { Caps caps = Configuration.TunerA.Caps; + if (settingsWindowCollectRfSpectrum) + { + SetTuner(1); + RfSpectrumData rfSpectrum = GatherRfSpectrum(); + if (rfSpectrum != null) + { + jobContext.ObjectStorage.StoreRfSpectrum(jobInDb.JobGuid, rfSpectrum); + } + } if (caps.HasFlag(Caps.SR_BLSCAN2)) { SearchResult sr1 = default; @@ -513,7 +527,7 @@ namespace SDL2Demo.Jobs throw new NotImplementedException("Don't know how to blindscan with this tuner."); } } - + private bool somethingStarted; private int lastTuner; private bool SetTuner(int mode) @@ -689,10 +703,102 @@ namespace SDL2Demo.Jobs JobContext.Puppets[3].AutoMoveToHome(); } - private IqChartData GatherIQGraphCable() + + + private RfSpectrumData GatherRfSpectrum() + { + Caps caps = streamReader.GetCaps(); + if (caps.HasFlag(Caps.SR_RFSCAN2)) + { + return GatherRfSpectrumCable(); + } + else if (!caps.HasFlag(Caps.SR_RFSCAN)) + { + logger.Log(PluginLogLevel.Error, "Couldn't figure out whether to use RFScan or RFScan2!"); + return null; + } + + SdlScottPlotWindowRfSpectrum window = new SdlScottPlotWindowRfSpectrum(jobContext.ImgUiDevice); + jobContext.Renderables.Add(window); + + int lof1 = Configuration.LnbType.Lof1 * 1000; + int lof2 = Configuration.LnbType.Lof2 * 1000; + int lofSw = Configuration.LnbType.LofSw * 1000; + int startFreq = Configuration.LnbType.MinimumFrequency * 1000; + int endFreq = Configuration.LnbType.MaximumFrequency * 1000; + + RfSpectrumData spectrumData = RfSpectrumData.Create(); + + void RunRfScan(RfSpectrumData spectrum, int startFreq, int endFreq, SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, DiSEqC_Opcode diseqcCmd, int lof1, int lof2, int lofSw) + { + const int STEP = 1000; + streamReader.SendDiSEqC(2, diseqcCmd); + RfSpectrumDataBlock block = spectrumData.CreateBlock(startFreq, endFreq, STEP, polarization); + for (int i = startFreq; i <= endFreq; i += STEP) + { + double rf = Double.NaN; + streamReader.RFScan(i, diseqcCmd.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL) ? 0 : 1, lof1, lof2, lofSw, out rf); + Console.WriteLine("{0} {1}, {2}", i, polarization.ToString().Substring(0, 1), rf); + block.Push(i, rf); + window.EnqueueSample(polarization, i, rf); + } + } + + foreach (DiSEqC_Opcode opcode in GetIqGraphDiseqcOpcodes()) + { + RunRfScan(spectrumData, startFreq, endFreq, + opcode.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL) ? SatelliteDeliverySystemDescriptor.PolarizationEnum.HorizontalLinear : SatelliteDeliverySystemDescriptor.PolarizationEnum.VerticalLinear, + opcode, lof1, lof2, lofSw); + } + + lock (jobContext.Renderables) + { + JobContext.Renderables.Remove(window); + window.Dispose(); + window = null; + } + + return spectrumData; + } + + private RfSpectrumData GatherRfSpectrumCable() { throw new NotImplementedException(); } + + private IEnumerable GetIqGraphDiseqcOpcodes() + { + DiSEqC_Opcode baseDiseqc = DiSEqC_Opcode.DISEQC_HIGH_NIBBLE; + + int parameter = Configuration.Diseqc; + switch (parameter) + { + case 1: + baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_A; + baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_A; + break; + case 2: + baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_A; + baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_B; + break; + case 3: + baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_B; + baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_A; + break; + case 4: + baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_B; + baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_B; + break; + default: + throw new ArgumentOutOfRangeException("DiSEqC Switch Position"); + } + + if (settingsWindowScanHorizontalLow || settingsWindowScanHorizontalHigh) + yield return baseDiseqc | DiSEqC_Opcode.DISEQC_HORIZONTAL | DiSEqC_Opcode.DISEQC_LOW_BAND; + if (settingsWindowScanVerticalLow || settingsWindowScanVerticalHigh) + yield return baseDiseqc | DiSEqC_Opcode.DISEQC_VERTICAL | DiSEqC_Opcode.DISEQC_LOW_BAND; + yield break; + } private IqChartData GatherIqGraph() { Caps caps = streamReader.GetCaps(); @@ -707,13 +813,17 @@ namespace SDL2Demo.Jobs return null; } + /* + * + */ IqChartData result = IqChartData.Create(); IqWindow iqWindow = new IqWindow(JobContext.ImgUiDevice, result); JobContext.Renderables.Add(iqWindow); - sbyte[] buffer = new sbyte[200]; + sbyte[] buffer = new sbyte[400]; + DateTime started = DateTime.Now; while (!result.IsComplete) { - bool iqScan = streamReader.IQScan(0, buffer, 100); + bool iqScan = streamReader.IQScan(0, buffer, (uint)(buffer.Length / 2)); if (!iqScan) { result = null; @@ -722,6 +832,8 @@ namespace SDL2Demo.Jobs } result.PushPacket(buffer); } + TimeSpan finished = DateTime.Now - started; + logger.Log(PluginLogLevel.Debug, "Finished IQ acquisiton in {0} ({1} samples per call)", finished.ToString(), buffer.Length / 2); lock (jobContext.Renderables) { @@ -732,6 +844,10 @@ namespace SDL2Demo.Jobs return result; } + private IqChartData GatherIQGraphCable() + { + throw new NotImplementedException(); + } private void RunSkyscraper(BlindscanResult result) { diff --git a/GUIs/skyscraper8.UI.ImGui/Program.cs b/GUIs/skyscraper8.UI.ImGui/Program.cs index 2160649..68c6712 100644 --- a/GUIs/skyscraper8.UI.ImGui/Program.cs +++ b/GUIs/skyscraper8.UI.ImGui/Program.cs @@ -777,7 +777,7 @@ namespace SkyscraperUI ImGui.Render(); } - + private void TestdridClass_Quit(SDL.SDL_QuitEvent qe) { quit = true; diff --git a/skyscraper8/DvbI/DvbIUtils.cs b/skyscraper8/DvbI/DvbIUtils.cs index fd044dd..e0285cf 100644 --- a/skyscraper8/DvbI/DvbIUtils.cs +++ b/skyscraper8/DvbI/DvbIUtils.cs @@ -39,6 +39,10 @@ namespace skyscraper8.DvbI string s = Encoding.UTF8.GetString(buffer); s = s.Replace("", ""); s = s.Replace("", ""); + if (s.Contains("urn:dvb:metadata:servicediscovery:2025")) + { + s = s.Replace("urn:dvb:metadata:servicediscovery:2025", "urn:dvb:metadata:servicediscovery:2024"); + } object slWrapped = serviceListSerializer.Deserialize(new StringReader(s)); ServiceListType slt = (ServiceListType)slWrapped; @@ -270,6 +274,10 @@ namespace skyscraper8.DvbI if (serviceListEntryPointSerializer == null) serviceListEntryPointSerializer = new XmlSerializer(typeof(ServiceListEntryPoints)); + if (rawSlepString.Contains("urn:dvb:metadata:servicelistdiscovery:2025")) + { + rawSlepString = rawSlepString.Replace("urn:dvb:metadata:servicelistdiscovery:2025", "urn:dvb:metadata:servicelistdiscovery:2024"); + } StringReader stringReader = new StringReader(rawSlepString); object slepWrapped = serviceListEntryPointSerializer.Deserialize(stringReader); ServiceListEntryPoints serviceListEntryPoint = (ServiceListEntryPoints)slepWrapped; diff --git a/skyscraper8/DvbNip/DvbNipReceiver.cs b/skyscraper8/DvbNip/DvbNipReceiver.cs index 82313da..346dc3c 100644 --- a/skyscraper8/DvbNip/DvbNipReceiver.cs +++ b/skyscraper8/DvbNip/DvbNipReceiver.cs @@ -103,7 +103,10 @@ namespace skyscraper8.DvbNip if (isValidXml) { FDTInstanceType fdtAnnouncement = FluteUtilities.UnpackFluteFdt(fluteStream); - SetFileAssociations(fluteListener, fdtAnnouncement); + if (fdtAnnouncement != null) + { + SetFileAssociations(fluteListener, fdtAnnouncement); + } } fluteStream.Close(); fluteStream.Dispose(); diff --git a/skyscraper8/Ietf/FLUTE/FluteUtilities.cs b/skyscraper8/Ietf/FLUTE/FluteUtilities.cs index b20cc98..e16c9cf 100644 --- a/skyscraper8/Ietf/FLUTE/FluteUtilities.cs +++ b/skyscraper8/Ietf/FLUTE/FluteUtilities.cs @@ -26,8 +26,17 @@ namespace skyscraper8.Ietf.FLUTE if (fdtSerializer == null) fdtSerializer = new XmlSerializer(typeof(FDTInstanceType)); - FDTInstanceType result = (FDTInstanceType)fdtSerializer.Deserialize(ms); - return result; + try + { + + FDTInstanceType result = (FDTInstanceType)fdtSerializer.Deserialize(ms); + return result; + } + catch (InvalidOperationException e) + { + Console.WriteLine(e); + return null; + } } public static bool IsXmlWellFormed(Stream xmlStream) diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index e15357d..cd0d871 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "\"Z:\\Freebies\\Datasets\\SkyscraperLibrarian\\DVB-S Juli 2025\\movistar-000000.ts\"", + "commandLineArgs": "\"Z:\\TelephoneExchange\\11141_h_20250805_2233.ts\"", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/Skyscraper/Drawing/RfFrequencyChartData.cs b/skyscraper8/Skyscraper/Drawing/RfFrequencyChartData.cs index 8489af4..2aa4c07 100644 --- a/skyscraper8/Skyscraper/Drawing/RfFrequencyChartData.cs +++ b/skyscraper8/Skyscraper/Drawing/RfFrequencyChartData.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using skyscraper5.Dvb.Descriptors; using skyscraper5.Skyscraper.IO; +using skyscraper5.src.Sophtainer; namespace skyscraper8.Skyscraper.Drawing { @@ -31,8 +32,11 @@ namespace skyscraper8.Skyscraper.Drawing return child; } - public void SaveTo(Stream stream) + public void SaveTo(Stream outerStream) { + Sophtainer sophtainer = Sophtainer.CreateSophtainer(outerStream, 538986066u, new Version(1, 0, 0, 0)); + OffsetStream stream = sophtainer.GetStream(); + foreach (RfSpectrumDataBlock block in blocks) { stream.WriteUInt8(0x58); @@ -47,6 +51,7 @@ namespace skyscraper8.Skyscraper.Drawing } stream.WriteUInt8(0x4f); + } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs index 065ebe5..e696612 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs @@ -1460,6 +1460,11 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem throw new NotImplementedException(); } + public void StoreRfSpectrum(Guid jobGuid, RfSpectrumData rfSpectrum) + { + throw new NotImplementedException(); + } + public bool DvbNipPrivateDataSpecifier(NipActualCarrierInformation currentCarrierInformation, DateTime versionUpdate, uint privateDataSpecifier, List privateDataSessions) { diff --git a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs index feae0ab..13ac51c 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs @@ -1493,14 +1493,21 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory _nipMulticastGatewayConfigurationTransportSessions.Add(key, multicastGatewayConfigurationTransportSession); } + private HashSet _nipActualCarriers; public bool DvbNipTestForCarrier(NipActualCarrierInformation currentCarrierInformation) { - throw new NotImplementedException(); + if (_nipActualCarriers == null) + return false; + + return _nipActualCarriers.Contains(currentCarrierInformation); } public void DvbNipInsertCarrier(NipActualCarrierInformation currentCarrierInformation) { - throw new NotImplementedException(); + if (_nipActualCarriers == null) + _nipActualCarriers = new HashSet(); + + _nipActualCarriers.Add(currentCarrierInformation); } public void InsertDvbiServiceListEntryPoint(long sourceHash) diff --git a/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs index 27ac8f3..5771f11 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs @@ -83,5 +83,10 @@ namespace skyscraper8.Skyscraper.Scraper.Storage { throw new NotImplementedException(); } + + public void StoreRfSpectrum(Guid jobGuid, RfSpectrumData rfSpectrum) + { + throw new NotImplementedException(); + } } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs index 8b69aa7..45e9b1b 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs @@ -27,5 +27,6 @@ namespace skyscraper8.Skyscraper.Scraper.Storage bool DvbNipTestForFile(string announcedFileContentLocation); void DvbNipFileArrival(NipActualCarrierInformation carrier, FluteListener listener); void StoreIqGraph(Guid jobGuid, long frequency, char polarity, IqChartData plot); + void StoreRfSpectrum(Guid jobGuid, RfSpectrumData rfSpectrum); } }