diff --git a/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs b/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs index b56c9ae..787c578 100644 --- a/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs +++ b/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs @@ -168,7 +168,62 @@ namespace skyscraper5.Data.PostgreSql return new object[] { pluginToken }; } - + public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, + bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, + bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, + bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, + bool settingsWindowScanVerticalHigh) + { + using (NpgsqlConnection connection = new NpgsqlConnection(connectionStringBuilder.ToString())) + { + connection.Open(); + NpgsqlCommand command = connection.CreateCommand(); + command.CommandText = + "INSERT INTO ui_blindscan_setting_history VALUES (DEFAULT,@bstselection,@ustfsfilter,@sftselection,@diseqc,@cigraphs,@crspectrum,@cfilters,@satellite,@lnb,@dish,@hl,@hh,@vl,@vh);"; + command.Parameters.AddWithValue("@bstselection", NpgsqlDbType.Integer, settingsWindowBlScanTunerSelection); + command.Parameters.AddWithValue("@ustfsfilter", NpgsqlDbType.Boolean, settingsWindowUseDifferentTunerForSetFilter); + command.Parameters.AddWithValue("@sftselection", NpgsqlDbType.Integer, settingsWindowSetFilterTunerSelection); + command.Parameters.AddWithValue("@diseqc", NpgsqlDbType.Integer, settingsWindowDiseqc); + command.Parameters.AddWithValue("@cigraphs", NpgsqlDbType.Boolean, settingsWindowCollectIqGraphs); + command.Parameters.AddWithValue("@crspectrum", NpgsqlDbType.Boolean, settingsWindowCollectRfSpectrum); + command.Parameters.AddWithValue("@cfilters", NpgsqlDbType.Boolean, settingsWindowCaptureFile); + command.Parameters.AddWithValue("@satellite", NpgsqlDbType.Integer, settingsWindowSatellite); + command.Parameters.AddWithValue("@lnb", NpgsqlDbType.Integer, settingsWindowLnb); + command.Parameters.AddWithValue("@dish", NpgsqlDbType.Integer, dish); + command.Parameters.AddWithValue("@hl", NpgsqlDbType.Boolean, settingsWindowScanHorizontalLow); + command.Parameters.AddWithValue("@hh", NpgsqlDbType.Boolean, settingsWindowScanHorizontalHigh); + command.Parameters.AddWithValue("@vl", NpgsqlDbType.Boolean, settingsWindowScanVerticalLow); + command.Parameters.AddWithValue("@vh", NpgsqlDbType.Boolean, settingsWindowScanVerticalHigh); + command.ExecuteNonQuery(); + connection.Close(); + } + } + + public object[] GetLastUiBlindscanSettings() + { + using (NpgsqlConnection connection = new NpgsqlConnection(connectionStringBuilder.ToString())) + { + connection.Open(); + NpgsqlCommand command = connection.CreateCommand(); + command.CommandText = "SELECT * FROM ui_blindscan_setting_history WHERE dateadded = (SELECT MAX(dateadded) FROM ui_blindscan_setting_history)"; + NpgsqlDataReader dataReader = command.ExecuteReader(); + object[] result = null; + if (dataReader.Read()) + { + int fields = dataReader.FieldCount; + result = new object[fields]; + for (int i = 0; i < fields; i++) + { + result[i] = dataReader.GetValue(i); + } + } + dataReader.Close(); + command.Dispose(); + connection.Close(); + return result; + } + } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow.cs b/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow.cs index 0c4e159..f6643f1 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using SDL2Demo.Jobs; +using skyscraper8.Skyscraper.FrequencyListGenerator; using static SDL2Demo.Jobs.Blindscan; namespace SDL2Demo.Forms @@ -98,6 +100,19 @@ namespace SDL2Demo.Forms ImGui.End(); } } + + public void Add(BlindscanSearchResult searchResult, int polarityIndex, int lnbTypeMinimumFrequency, int i) + { + if (searchResult.IsSatellite()) + _blindscanResults.Add(new Blindscan.BlindscanResult(searchResult.SearchResult, lnbTypeMinimumFrequency, i)); + else + _blindscanResults.Add(new BlindscanResult(searchResult.SearchResult2, lnbTypeMinimumFrequency, i)); + } + + public void Clear() + { + _blindscanResults.Clear(); + } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow2.cs b/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow2.cs new file mode 100644 index 0000000..3b22fb4 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui/Forms/FoundFrequenciesWindow2.cs @@ -0,0 +1,93 @@ +using SDL2Demo; +using skyscraper8.Skyscraper.FrequencyListGenerator; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ImGuiNET; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; + +namespace SDL2Demo +{ + internal class FoundFrequenciesWindow2 : IRenderable + { + private readonly List _foundFrequencies; + public bool doNotAutoZap; + public bool allowZapNow; + public bool zapNowRequested; + private string tableUuid; + public long statusPacketsInTotal; + public long statusPacketsInQueue; + + public FoundFrequenciesWindow2(List foundFrequencies) + { + _foundFrequencies = foundFrequencies; + tableUuid = Guid.NewGuid().ToString(); + } + + public void Render() + { + if (_foundFrequencies.Count == 0) + return; + + if (ImGui.Begin("Blind-Scan Results")) + { + ImGui.Checkbox("Do not Auto-Zap", ref doNotAutoZap); + ImGui.SameLine(); + ImGui.BeginDisabled(!allowZapNow); + if (ImGui.Button("Zap now")) + { + zapNowRequested = true; + } + ImGui.EndDisabled(); + + if (allowZapNow) + { + ImGui.Text(String.Format("{0} packets received in total, {1} queued.", statusPacketsInTotal, statusPacketsInQueue)); + } + + if (ImGui.BeginTable(tableUuid, 5, + ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + for (int i = 0; i < _foundFrequencies.Count; i++) + { + BlindscanSearchResult blindscanResult = _foundFrequencies[i]; + ImGui.TableNextRow(); + if (blindscanResult.IsSatellite()) + { + ImGui.TableSetColumnIndex(0); + ImGui.Text(String.Format("{0} {1} ", blindscanResult.SearchResult.Freq / 1000, + blindscanResult.SearchResult.Pol == 0 ? "H" : "V")); + + ImGui.TableSetColumnIndex(1); + ImGui.Text((blindscanResult.SearchResult.SR / 1000).ToString()); + + ImGui.TableSetColumnIndex(2); + ImGui.Text(((MOD_TYPE)blindscanResult.SearchResult.ModType).ToString()); + + ImGui.TableSetColumnIndex(3); + ImGui.Text((blindscanResult.SearchResult.MIS + 1).ToString()); + } + else + { + ImGui.TableSetColumnIndex(0); + ImGui.Text((blindscanResult.SearchResult.Freq / 1000).ToString()); + + ImGui.TableSetColumnIndex(1); + ImGui.Text((blindscanResult.SearchResult.SR / 10).ToString()); + + ImGui.TableSetColumnIndex(2); + ImGui.Text(((MOD_TYPE)blindscanResult.SearchResult.ModType).ToString()); + } + + ImGui.TableSetColumnIndex(4); + ImGui.Text(blindscanResult.State.ToString()); + } + ImGui.EndTable(); + } + ImGui.End(); + } + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/JobDisplay.cs b/GUIs/skyscraper8.UI.ImGui/Forms/JobDisplay.cs index 16a23be..a6a4e69 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/JobDisplay.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/JobDisplay.cs @@ -21,10 +21,14 @@ using skyscraper5.Mpeg2; using skyscraper5.Mpeg2.Descriptors; using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Scte35; +using skyscraper5.Skyscraper.Equipment; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper5.Skyscraper.Net; using skyscraper5.Skyscraper.Scraper; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.Teletext.Wss; +using skyscraper8.Skyscraper.Drawing; +using skyscraper8.Skyscraper.FrequencyListGenerator; using testdrid.SdlWrapper; namespace SDL2Demo.Forms @@ -2060,6 +2064,126 @@ namespace SDL2Demo.Forms } } + #endregion + + public void OnBlindscanOpenFoundFrquenciesWindow(List foundFrequencies, STD_TYPE tunerMetadataType) + { + throw new NotImplementedException(); + } + + public void OnBlindscanJobDone(bool success) + { + throw new NotImplementedException(); + } + + public void OnBlindscanErrorMessage(string blindscanningLowHorizontalAreaFailed) + { + throw new NotImplementedException(); + } + + public void OnBlindscanBandComplete() + { + throw new NotImplementedException(); + } + + public void OnBlindscanBeforeBLScan(int minimum, int currentProgress, int maximum) + { + throw new NotImplementedException(); + } + + public void OnBlindscanAfterBLScan() + { + throw new NotImplementedException(); + } + + public void OnBlindscanSearchResult1Callback(BlindscanSearchResult searchResult, int polarityIndex, + int lnbTypeMinimumFrequency, int lnbTypeMaximumFrequency) + { + throw new NotImplementedException(); + } + + public void OnBlindscanBeforeSetChannel(BlindscanSearchResult blindscanResult,LnbType lnbType) + { + throw new NotImplementedException(); + } + + public void OnScrapeBandComplete() + { + throw new NotImplementedException(); + } + + public void OnBlindscanScrapeTransponderComplete(BlindscanSearchResult blindscanResult) + { + throw new NotImplementedException(); + } + + public void OnBlindscanBeginRfSpectrum() + { + throw new NotImplementedException(); + } + + public void OnBlindscanRfSpectrumEnqueueSample(SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, int frequency, double rf) + { + throw new NotImplementedException(); + } + + public void OnBlindscanEndRfSpectrum() + { + throw new NotImplementedException(); + } + + public void OnBlindscanBeginIqSpectrum(IqChartData result) + { + throw new NotImplementedException(); + } + + public void OnBlindscanEndIq() + { + throw new NotImplementedException(); + } + + public void OnBlindscanLockFail(SearchResult satelliteSr, BlindscanResultState resultState) + { + throw new NotImplementedException(); + } + + public void OnBlindscanFilterSetUp() + { + throw new NotImplementedException(); + } + + public void OnBlindscanScrapeStopCondition() + { + throw new NotImplementedException(); + } + + public void OnBlindscanAfterPacketDrain() + { + throw new NotImplementedException(); + } + + public void OnBlindscanPacketError(int errorCount, int length) + { + throw new NotImplementedException(); + } + + public void OnBlindscanPacketOk(int numPackets, int packetsQueueCount) + { + throw new NotImplementedException(); + } + + public bool IsZapNowRequested() + { + throw new NotImplementedException(); + } + + public bool MayAutoZap() + { + throw new NotImplementedException(); + } + + public TaskQueue Tasks { get; set; } + private ushort? ResolveCaId(ProgramMapping patValuePmt, SdtCoordinate sdt) { if (patValuePmt != null) @@ -2082,8 +2206,6 @@ namespace SDL2Demo.Forms return null; } - - #endregion - + } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/PictureWindow.cs b/GUIs/skyscraper8.UI.ImGui/Forms/PictureWindow.cs index 9edaae1..733f8cb 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/PictureWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/PictureWindow.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Echo.UserInterface.Backend; using ImGuiNET; using SDL2; +using skyscraper8.Skyscraper.FrequencyListGenerator; using testdrid.SdlWrapper; namespace SDL2Demo.Forms @@ -60,12 +61,22 @@ namespace SDL2Demo.Forms ImGui.End(); ImGui.PopStyleVar(); } - + + private bool disposed; public void Dispose() { - _texture.Dispose(); - _surface.Dispose(); + if (disposed) + return; + + tasks.EnqueueTask(() => + { + renderables.Remove(this); + _texture.Dispose(); + _surface.Dispose(); + }); + + disposed = true; } internal static Renderer Renderer { get; set; } @@ -75,5 +86,13 @@ namespace SDL2Demo.Forms position.X = x; position.Y = y; } + + private TaskQueue tasks; + private List renderables; + public void SetTaskQueue(TaskQueue tasks, List jobContextRenderables) + { + this.tasks = tasks; + this.renderables = jobContextRenderables; + } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs b/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs index 3a97ca3..a57c80c 100644 --- a/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Forms/SdlScottPlotWindow.cs @@ -59,6 +59,7 @@ namespace skyscraper8.UI.ImGui.Forms _plot.Dispose(); _skBitmap.Dispose(); _skCanvas.Dispose(); + _texture.Dispose(); } } } diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs index 33b6c68..98b3aa1 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/Blindscan.cs @@ -314,7 +314,7 @@ namespace SDL2Demo.Jobs public BlindscanResult(SearchResult searchResult, int satPositionMinFreq, int satPositionMaxFreq) { int x = 0, y = 0; - + if (searchResult.Pol == 0) { //Horizontal diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs new file mode 100644 index 0000000..b37a0d8 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs @@ -0,0 +1,247 @@ +using ImGuiNET; +using skyscraper5.Skyscraper; +using skyscraper5.Skyscraper.Equipment; +using skyscraper5.Skyscraper.Gps; +using skyscraper5.Skyscraper.IO; +using skyscraper8.Skyscraper.FrequencyListGenerator; +using skyscraper8.Skyscraper.Scraper.Storage; +using skyscraper8.UI.SDL2.Jobs; + +namespace SDL2Demo.Jobs +{ + internal class InheritedBlindscanConfigWindow : IRenderable + { + private bool windowOpen; + private List tuners; + private List satellites; + private List lnbs; + private List dishes; + private readonly TaskQueue _taskQueue; + + public int settingsWindowBLScanTunerSelection; + public bool settingsWindowUseDifferentTunerForSetFilter; + public int settingsWindowSetFilterTunerSelection; + public int settingsWindowDiseqc; + public bool settingsWindowCollectIqGraphs; + public bool settingsWindowCollectRfSpectrum; + public bool settingsWindowCaptureFile; + public int settingsWindowSatellite; + public int settingsWindowLNB; + public int settingsWindowDish; + + public bool settingsWindowScanHorizontalLow; + public bool settingsWindowScanHorizontalHigh; + public bool settingsWindowScanVerticalLow; + public bool settingsWindowScanVerticalHigh; + + private DataStorage dataStorage; + private ObjectStorage objectStorage; + private IGpsReceiver gpsReceiver; + private Ini ini; + private IStreamReader streamReader; + + private void StoreSettings() + { + dataStorage.InsertUiBlindscanSettingHistory(settingsWindowBLScanTunerSelection, + settingsWindowUseDifferentTunerForSetFilter, settingsWindowSetFilterTunerSelection, + settingsWindowDiseqc, settingsWindowCollectIqGraphs, + settingsWindowCollectRfSpectrum, settingsWindowCaptureFile, settingsWindowSatellite, settingsWindowLNB, + settingsWindowDish, settingsWindowScanHorizontalLow, settingsWindowScanHorizontalHigh, + settingsWindowScanVerticalLow, settingsWindowScanVerticalHigh); + } + public InheritedBlindscanConfigWindow(List tunerMetadatas, + List satellitePositions, List lnbTypes, List dishTypes, + DataStorage dataStorage, ObjectStorage objectStorage, IGpsReceiver gps, Ini ini, IStreamReader streamReader, + TaskQueue taskQueue) + { + tuners = tunerMetadatas; + satellites = satellitePositions; + lnbs = lnbTypes; + dishes = dishTypes; + windowOpen = true; + settingsWindowDiseqc = 1; + this.dataStorage = dataStorage; + this.objectStorage = objectStorage; + this.gpsReceiver = gps; + this.ini = ini; + this.streamReader = streamReader; + _taskQueue = taskQueue; + + object[] previousSettings = dataStorage.GetLastUiBlindscanSettings(); + if (previousSettings != null) + { + settingsWindowBLScanTunerSelection = (int)previousSettings[1]; + settingsWindowUseDifferentTunerForSetFilter = (bool)previousSettings[2]; + settingsWindowSetFilterTunerSelection = (int)previousSettings[3]; + settingsWindowDiseqc = (int)previousSettings[4]; + settingsWindowCollectIqGraphs = (bool)previousSettings[5]; + settingsWindowCollectRfSpectrum = (bool)previousSettings[6]; + settingsWindowCaptureFile = (bool)previousSettings[7]; + settingsWindowSatellite = (int)previousSettings[8]; + settingsWindowLNB = (int)previousSettings[9]; + settingsWindowDish = (int)previousSettings[10]; + + settingsWindowScanHorizontalLow = (bool)previousSettings[11]; + settingsWindowScanHorizontalHigh = (bool)previousSettings[12]; + settingsWindowScanVerticalLow = (bool)previousSettings[13]; + settingsWindowScanVerticalHigh = (bool)previousSettings[14]; + } + } + public bool IsWindowOpen() + { + return windowOpen; + } + public BlindscanJobConfiguration GetConfiguration() + { + if (!okButtonClicked) + return null; + + BlindscanJobConfiguration bjc = new BlindscanJobConfiguration(); + bjc.DataStorage = dataStorage; + bjc.DiseqcIndex = settingsWindowDiseqc; + bjc.DoHorizontalLow = settingsWindowScanHorizontalLow; + bjc.DoHorizontalHigh = settingsWindowScanHorizontalHigh; + bjc.DoVerticalLow = settingsWindowScanVerticalLow; + bjc.DoVerticalHigh = settingsWindowScanHorizontalHigh; + bjc.DoCollectIqGraphs = settingsWindowCollectIqGraphs; + bjc.DoCollectRfSpectrum = settingsWindowCollectRfSpectrum; + bjc.DoRecordTs = settingsWindowCaptureFile; + bjc.Gps = gpsReceiver; + bjc.Ini = ini; + bjc.LnbType = lnbs[settingsWindowLNB]; + bjc.ObjectStorage = objectStorage; + bjc.SatellitePosition = satellites[settingsWindowSatellite]; + + if (settingsWindowUseDifferentTunerForSetFilter) + bjc.StreamReader = new CoopBlindscanStreamReader(streamReader, settingsWindowBLScanTunerSelection, settingsWindowSetFilterTunerSelection); + else + bjc.StreamReader = streamReader; + + bjc.TunerMetadata = tuners[settingsWindowBLScanTunerSelection]; + bjc.Ui = new InheritedBlindscanUiJunction(); + bjc.Ui.Tasks = _taskQueue; + return bjc; + } + + private bool okButtonClicked; + public void Render() + { + if (ImGui.Begin("Blindscan", ref windowOpen, ImGuiWindowFlags.AlwaysAutoResize)) + { + ImGui.PushID("tunerA"); + if (ImGui.BeginCombo("Tuner for BLScanEx and RFScan", tuners[settingsWindowBLScanTunerSelection].Name)) + { + for (int i = 0; i < tuners.Count; i++) + { + bool isSelected = settingsWindowBLScanTunerSelection == i; + if (ImGui.Selectable(tuners[i].Name, isSelected)) + { + settingsWindowBLScanTunerSelection = i; + } + } + ImGui.EndCombo(); + } + ImGui.PopID(); + + if (tuners[settingsWindowBLScanTunerSelection].IsSatellite()) + { + ImGui.Checkbox("Use different Tuner for IQScan and SetFilter", ref settingsWindowUseDifferentTunerForSetFilter); + + if (settingsWindowUseDifferentTunerForSetFilter) + { + ImGui.Text("This assumes that both tuners are connected to the same antenna set-up, using e.g. a splitter."); + + ImGui.PushID("tunerB"); + if (ImGui.BeginCombo("Tuner for BLScanEx and RFScan", tuners[settingsWindowSetFilterTunerSelection].Name)) + { + for (int i = 0; i < tuners.Count; i++) + { + bool isSelected = settingsWindowSetFilterTunerSelection == i; + if (ImGui.Selectable(tuners[i].Name, isSelected)) + { + settingsWindowSetFilterTunerSelection = i; + } + } + ImGui.EndCombo(); + } + ImGui.PopID(); + } + + ImGui.Text("DiSEqC"); + ImGui.SameLine(); + ImGui.RadioButton("A", ref settingsWindowDiseqc, 1); + ImGui.SameLine(); + ImGui.RadioButton("B", ref settingsWindowDiseqc, 2); + ImGui.SameLine(); + ImGui.RadioButton("C", ref settingsWindowDiseqc, 3); + ImGui.SameLine(); + ImGui.RadioButton("D", ref settingsWindowDiseqc, 4); + + + if (ImGui.BeginCombo("Target Satellite", satellites[settingsWindowSatellite].name)) + { + for (int i = 0; i < satellites.Count; i++) + { + bool isSelected = settingsWindowSatellite == i; + if (ImGui.Selectable(satellites[i].name, isSelected)) + { + settingsWindowSatellite = i; + } + } + ImGui.EndCombo(); + } + + if (ImGui.BeginCombo("LNB", lnbs[settingsWindowLNB].Name)) + { + for (int i = 0; i < lnbs.Count; i++) + { + bool isSelected = settingsWindowLNB == i; + if (ImGui.Selectable(lnbs[i].Name, isSelected)) + { + settingsWindowLNB = i; + } + } + ImGui.EndCombo(); + } + + if (ImGui.BeginCombo("Dish", dishes[settingsWindowDish].Name)) + { + for (int i = 0; i < dishes.Count; i++) + { + bool isSelected = settingsWindowDish == i; + if (ImGui.Selectable(dishes[i].Name, isSelected)) + { + settingsWindowDish = i; + } + } + ImGui.EndCombo(); + } + + if (lnbs[settingsWindowLNB].LofSw != 0) + { + ImGui.Checkbox("Scan Horizontal Low Band", ref settingsWindowScanHorizontalLow); + ImGui.Checkbox("Scan Horizontal High Band", ref settingsWindowScanHorizontalHigh); + ImGui.Checkbox("Scan Vertical Low Band", ref settingsWindowScanVerticalLow); + ImGui.Checkbox("Scan Vertical High Band", ref settingsWindowScanVerticalHigh); + } + else + { + ImGui.Checkbox("Scan Left circular Band", ref settingsWindowScanHorizontalLow); + ImGui.Checkbox("Scan Right circular Band", ref settingsWindowScanVerticalLow); + } + } + + ImGui.Checkbox("Capture Packets to files", ref settingsWindowCaptureFile); + ImGui.Checkbox("Collect IQ Graphs", ref settingsWindowCollectIqGraphs); + ImGui.Checkbox("Collect RF Spectrum", ref settingsWindowCollectRfSpectrum); + + if (ImGui.Button("OK")) + { + windowOpen = false; + okButtonClicked = true; + StoreSettings(); + } + } + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanJob.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanJob.cs new file mode 100644 index 0000000..a4214a0 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanJob.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SDL2Demo; +using SDL2Demo.Jobs; +using skyscraper8.Skyscraper.FrequencyListGenerator; + +namespace skyscraper8.UI.SDL2.Jobs +{ + internal class InheritedBlindscanJob : IJob + { + private readonly BlindscanJobConfiguration _jobConfiguration; + + public InheritedBlindscanJob(BlindscanJobConfiguration jobConfiguration) + { + _jobConfiguration = jobConfiguration; + } + + private BaseBlindscanJob baseBlindscanJob; + public void Run() + { + if (JobContext == null) + { + throw new NullReferenceException(nameof(JobContext)); + } + + InheritedBlindscanUiJunction inherited = (InheritedBlindscanUiJunction)_jobConfiguration.Ui; + inherited.jobContext = JobContext; + + baseBlindscanJob = new BaseBlindscanJob(_jobConfiguration); + baseBlindscanJob.Run(); + } + + public void Cancel() + { + throw new NotImplementedException(); + } + + public JobContext JobContext { get; set; } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs new file mode 100644 index 0000000..60f6c35 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs @@ -0,0 +1,1786 @@ +using ImGuiNET; +using SDL2Demo; +using SDL2Demo.Forms; +using SDL2Demo.Jobs; +using SDL2Demo.Net; +using SDL2Demo.SdlWrapper; +using skyscraper5.Docsis; +using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs; +using skyscraper5.Dvb.Descriptors; +using skyscraper5.Dvb.Psi.Model; +using skyscraper5.Mhp.Descriptors; +using skyscraper5.Mhp.Si; +using skyscraper5.Mhp.Si.Model; +using skyscraper5.Mpeg2.Descriptors; +using skyscraper5.Mpeg2.Psi.Model; +using skyscraper5.Scte35; +using skyscraper5.Skyscraper.Equipment; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; +using skyscraper5.Skyscraper.Net; +using skyscraper5.Skyscraper.Scraper; +using skyscraper5.src.Skyscraper.FrequencyListGenerator; +using skyscraper5.Teletext.Wss; +using skyscraper8.Skyscraper.Drawing; +using skyscraper8.Skyscraper.FrequencyListGenerator; +using skyscraper8.UI.ImGui.Forms; +using SkyscraperUI; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; +using testdrid.SdlWrapper; +using static SDL2Demo.Jobs.Blindscan; + +namespace SDL2Demo.Jobs +{ + internal class InheritedBlindscanUiJunction : ISkyscraperUiJunction, IRenderable + { + + #region During TS scraping + + DateTime prev, next; + private bool secondTick; + public void Render() + { + prev = next; + next = DateTime.Now; + secondTick = prev.Second != next.Second; + + RenderPat(); + RenderSdt(); + RenderNit(); + RenderCat(); + RenderPmt(); + RenderTdt(); + RenderEit(); + RenderAit(); + RenderTot(); + RenderBat(); + RenderObjectCarousels(); + RenderMpe(); + RenderDataCarousels(); + } + + private void ResetWindows() + { + HasSdt = false; + sdtDisplay = null; + sdtTableUuid = null; + HasPat = false; + TsType = 0; + patDisplay = null; + patTableUuid = null; + HasPmt = false; + pmtTabBarUuid = null; + nitDisplay = null; + nitTableUuid = null; + HasNit = false; + streamTypes = null; + caTableUuid = null; + caDisplay = null; + HasCat = false; + tdtDisplay = null; + HasTdt = false; + eitDisplay = null; + aitDisplay = null; + aitTableUuid = null; + HasAit = false; + totTime = null; + totDescriptor = null; + totDisplayUuid = null; + HasTot = false; + batDisplay = null; + HasBat = false; + displayObjectCarouselRoots = null; + HasDsmCc = false; + trafficInfoComparer = null; + mpeTableUuid = null; + mpeDisplays = null; + trafficInfoComparer = null; + mpeTableUuid = null; + mpeDisplays = null; + HasMpe = false; + dsmCcDisplay = null; + objectCarouselTableUuid = null; + if (framegrabWindows != null) + { + while (framegrabWindows.Count > 0) + { + PictureWindow pictureWindow = framegrabWindows.Dequeue(); + pictureWindow.Dispose(); + } + } + } + + private void SafeText(string s) + { + if (string.IsNullOrEmpty(s)) + { + ImGui.Text(""); + return; + } + + if (string.IsNullOrWhiteSpace(s)) + { + ImGui.Text("[null]"); + return; + } + + if (s.Contains("% ")) + s = s.Replace("% ", "%% "); + + ImGui.Text(s); + } + + #region EIT + private struct EitEventCoordinate + { + public DateTime StartTime; + public ushort NetworkId; + public ushort ServiceId; + } + + private struct EitDay + { + public DateTime Date; + public bool Visible; + public Guid tableGuid; + } + + private class EitDayComparer : IComparer + { + public int Compare(EitDay x, EitDay y) + { + return x.Date.CompareTo(y.Date); + } + } + + private class EitEventCoordinateComparer : IComparer + { + public int Compare(EitEventCoordinate x, EitEventCoordinate y) + { + return x.StartTime.Ticks.CompareTo(y.StartTime.Ticks); + } + } + + private bool HasEit; + private SortedList> eitDisplay; + private void RenderEit() + { + if (eitDisplay == null) + return; + + if (ImGui.Begin("Event Information Table")) + { + lock (eitDisplay) + { + foreach (KeyValuePair> keyValuePair in eitDisplay) + { + EitDay day = keyValuePair.Key; + if (ImGui.CollapsingHeader(keyValuePair.Key.Date.ToLongDateString(), ref day.Visible)) + { + if (day.tableGuid == Guid.Empty) + day.tableGuid = Guid.NewGuid(); + ImGui.BeginTable(day.ToString(), 3, + ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoSavedSettings); + foreach (KeyValuePair valuePair in keyValuePair.Value) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(valuePair.Key.StartTime.ToShortTimeString()); + ImGui.TableSetColumnIndex(1); + string sName = ResolveServiceDisplayName(valuePair.Key.ServiceId); + SafeText(sName); + ImGui.TableSetColumnIndex(2); + SafeText(valuePair.Value); + } + + ImGui.EndTable(); + } + } + } + + ImGui.End(); + } + } + + public void NotifyEvent(EitEvent eitEvent) + { + if (eitDisplay == null) + eitDisplay = new SortedList>(new EitDayComparer()); + + TsType = 1; + HasEit = true; + + EitDay date = new EitDay(); + date.Date = eitEvent.StartTime.Date; + date.Visible = true; + lock (eitDisplay) + { + if (!eitDisplay.ContainsKey(date)) + { + eitDisplay[date] = new SortedList(new EitEventCoordinateComparer()); + } + + SortedList sortedList = eitDisplay[date]; + + EitEventCoordinate coordinate = new EitEventCoordinate(); + coordinate.StartTime = eitEvent.StartTime; + coordinate.NetworkId = eitEvent.OriginalNetworkId; + coordinate.ServiceId = eitEvent.ServiceId; + if (!sortedList.ContainsKey(coordinate)) + { + sortedList.Add(coordinate, eitEvent.EventName); + } + } + } + + #endregion EIT + + + #region SDT + + private bool HasSdt; + + private string ResolveServiceDisplayName(ushort serviceId) + { + if (sdtDisplay == null) + return String.Format("0x{0:X4}", serviceId); + + lock (sdtDisplay) + { + if (sdtDisplay.ContainsKey(serviceId)) + { + string v = sdtDisplay[serviceId].ServiceName; + if (string.IsNullOrEmpty(v)) + return "???"; + else + return v; + } + } + + return String.Format("0x{0:X4}", serviceId); + } + + private SdtCoordinate ResolveService(ushort serviceId) + { + if (sdtDisplay == null) + return new SdtCoordinate(); + + lock (sdtDisplay) + { + if (sdtDisplay.ContainsKey(serviceId)) + { + return sdtDisplay[serviceId]; + } + } + + return new SdtCoordinate(); + } + + private struct SdtCoordinate + { + public string ProviderName; + public string ServiceName; + public bool FreeCaMode; + public ushort[] CaIdentifiers; + public ServiceDescriptor.ServiceTypeCoding? ServiceType; + } + + private SortedList sdtDisplay; + private string sdtTableUuid; + private void RenderSdt() + { + if (sdtDisplay == null) + return; + + if (string.IsNullOrEmpty(sdtTableUuid)) + sdtTableUuid = Guid.NewGuid().ToString(); + + + ImGui.Begin("Service Description Table"); + if (ImGui.BeginTable(sdtTableUuid, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + ImGui.TableSetupColumn("Service ID"); + ImGui.TableSetupColumn("Name"); + ImGui.TableSetupColumn("Provider"); + ImGui.TableSetupColumn("CA"); + ImGui.TableHeadersRow(); + + lock (sdtDisplay) + { + foreach (KeyValuePair keyValuePair in sdtDisplay) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(String.Format("{0:X4}", keyValuePair.Key)); + + ImGui.TableSetColumnIndex(1); + SafeText(keyValuePair.Value.ServiceName); + + ImGui.TableSetColumnIndex(2); + SafeText(keyValuePair.Value.ProviderName); + + ImGui.TableSetColumnIndex(3); + bool ca = keyValuePair.Value.FreeCaMode; + ImGui.BeginDisabled(true); + ImGui.Checkbox("", ref ca); + ImGui.EndDisabled(); + } + } + + ImGui.EndTable(); + ImGui.End(); + } + } + + public void NotifySdtService(SdtService sdtService) + { + TsType = 1; + HasSdt = true; + if (sdtDisplay == null) + sdtDisplay = new SortedList(); + + if (sdtDisplay.ContainsKey(sdtService.ServiceId)) + return; + + SdtCoordinate child = new SdtCoordinate(); + child.ProviderName = sdtService.ServiceProviderName; + child.ServiceName = sdtService.ServiceName; + child.FreeCaMode = sdtService.FreeCaMode; + child.CaIdentifiers = sdtService.CaIdentifiers; + child.ServiceType = sdtService.ServiceType; + + lock (sdtDisplay) + { + sdtDisplay.Add(sdtService.ServiceId, child); + } + } + + #endregion + + #region PAT + private class PatEntry + { + public ushort programId; + public ProgramMapping pmt; + public string PmtViewUuid; + } + + private bool HasPat; + private int TsType; + private SortedList patDisplay; + public void NotifyPatProgram(int pmtPid, ushort programId) + { + HasPat = true; + TsType = 1; + + if (patDisplay == null) + patDisplay = new SortedList(); + + if (patDisplay.ContainsKey(pmtPid)) + return; + + PatEntry patEntry = new PatEntry(); + patEntry.programId = programId; + lock (patDisplay) + { + patDisplay.Add(pmtPid, patEntry); + } + } + + private string patTableUuid; + public void RenderPat() + { + if (patDisplay == null) + return; + + if (string.IsNullOrEmpty(patTableUuid)) + patTableUuid = Guid.NewGuid().ToString(); + if (ImGui.Begin("Program Allocation Table")) + { + if (ImGui.BeginTable(patTableUuid, 2, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + ImGui.TableSetupColumn("PMT PID"); + ImGui.TableSetupColumn("Service"); + ImGui.TableHeadersRow(); + + lock (patDisplay) + { + foreach (KeyValuePair keyValuePair in patDisplay) + { + string k = String.Format("0x{0:X4}", keyValuePair.Key); + string v = ResolveServiceDisplayName(keyValuePair.Value.programId); + if (v == null) + v = "???"; + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(k); + + ImGui.TableSetColumnIndex(1); + SafeText(v); + } + } + ImGui.EndTable(); + } + ImGui.End(); + } + } + #endregion + + #region PMT + + private bool HasPmt; + public void NotifyPmtProgram(ProgramMapping result, int pmtPid) + { + HasPmt = true; + TsType = 1; + + if (!patDisplay.ContainsKey(pmtPid)) + return; + + PatEntry patEntry = patDisplay[pmtPid]; + if (patEntry.pmt != null) + return; + + patEntry.pmt = result; + } + + + private string pmtTabBarUuid; + public void RenderPmt() + { + if (!HasPmt) + return; + + if (string.IsNullOrEmpty(pmtTabBarUuid)) + pmtTabBarUuid = Guid.NewGuid().ToString(); + + if (ImGui.Begin("Program Map Table")) + { + if (ImGui.BeginTabBar(pmtTabBarUuid, ImGuiTabBarFlags.FittingPolicyScroll | ImGuiTabBarFlags.TabListPopupButton)) + { + lock (patDisplay) + { + foreach (KeyValuePair keyValuePair in patDisplay) + { + if (ImGui.BeginTabItem(ResolveServiceDisplayName(keyValuePair.Value.programId))) + { + if (string.IsNullOrEmpty(keyValuePair.Value.PmtViewUuid)) + keyValuePair.Value.PmtViewUuid = Guid.NewGuid().ToString(); + + if (keyValuePair.Value.pmt == null) + continue; + + ProgramMapping pmt = keyValuePair.Value.pmt; + + SafeText(String.Format("Service ID: 0x{0:X4}", pmt.ProgramNumber)); + + ImGui.BeginTable(keyValuePair.Value.PmtViewUuid, 2, ImGuiTableFlags.NoSavedSettings); + ImGui.TableSetupColumn("PID"); + ImGui.TableSetupColumn("Type"); + ImGui.TableHeadersRow(); + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(String.Format("0x{0:X4}", keyValuePair.Key)); + + ImGui.TableSetColumnIndex(1); + SafeText("PMT"); + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(String.Format("0x{0:X4}", keyValuePair.Value.pmt.PcrPid)); + + ImGui.TableSetColumnIndex(1); + SafeText("PCR"); + + foreach (ProgramMappingStream programMappingStream in pmt.Streams) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(String.Format("0x{0:X4}", programMappingStream.ElementaryPid)); + + ImGui.TableSetColumnIndex(1); + SafeText(StreamTypeAsString(programMappingStream, pmt.RegistrationFormatIdentifier)); + } + + ImGui.EndTable(); + ImGui.EndTabItem(); + } + } + } + ImGui.EndTabBar(); + } + ImGui.End(); + } + } + + private string StreamTypeAsString(ProgramMappingStream stream, uint? parentRegistrationFormatIdentifier) + { + if (streamTypes != null) + { + if (streamTypes.ContainsKey(stream.ElementaryPid)) + { + return streamTypes[stream.ElementaryPid]; + } + } + if (stream.StreamType == PmtStreamType.H262) + return "MPEG-2 Video"; + if (stream.AvcStillPresent.HasValue) + return "MPEG-4 Video (still frame)"; + if (stream.AudioType.HasValue) + { + switch (stream.AudioType) + { + case AudioType.CleanEffects: return "Audio (no effects)"; + case AudioType.HearingImpaired: return "Audio (for hearing impaired)"; + case AudioType.VisualImpairedCommentary: return "Audio (for visually impaired)"; + } + } + + if (stream.StreamType == PmtStreamType.AvcVideoStream) + { + return "MPEG-4 Video"; + } + + if (stream.StreamType == PmtStreamType.Iso11172Audio) + { + return "Audio"; + } + + if (stream.StreamType == PmtStreamType.Iso13818_3Audio) + return "MPEG-2 Audio"; + if (stream.StreamType == PmtStreamType.Iso13818_7AudioADTS) + return "AAC Audio"; + if (stream.StreamType == PmtStreamType.HevcVideoStream) + return "H.265 Video"; + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Ac4ChannelMode.HasValue) + return "Dolby AC-4 Audio"; + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.BSID.HasValue) + return "Dolby AC-3 Audio"; + if (stream.StreamType == PmtStreamType.Iso14496_3Audio && stream.AacProfileAndLevel.HasValue) + return "AAC Audio"; + if ((int)stream.StreamType == 0x81 && stream.ComponentType.HasValue) + return "Dolby AC-3 Audio"; + if (stream.Teletexts != null) + return "Teletext"; + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Subtitlings != null && stream.Subtitlings.Length > 0) + return "Subtitle"; + if (stream.DataBroadcastId == 0x0007) + return "Object Carousel"; + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.VbiData != null) + return "Teletext"; + if ((byte)stream.StreamType == 0x89 && stream.AncillaryDataDescriptor != null && stream.AncillaryDataDescriptor.RdsOnly) + return "Radio Data Service"; + if (stream.DataBroadcastId.HasValue && stream.DataBroadcastId.Value == 0x0005 /*&& stream.StreamType == PmtStreamType.Iso13818_6TypeD*/) + return "Multiprotocol Encapsulation"; + if (stream.DataBroadcastId == 0x0106) + return "MHEG-5"; + if (stream.DataBroadcastId == 0x000b) + return "IP/MAC Notification"; + + if (stream.RelatedContentDescriptorPresent.HasValue) + if (stream.RelatedContentDescriptorPresent.Value && stream.StreamType == PmtStreamType.Iso13818_1PrivateSections) + return "Related Content Table Information"; + + if (stream.NumT2MiStreams.HasValue && stream.StreamType == PmtStreamType.Iso13818_1PesPackets) + return "T2-MI"; + + return String.Format("??? (Type 0x{0:X2})", (int)stream.StreamType); + } + + #endregion + + #region NIT + + private class NitNetworkMeta + { + public ushort ONID; + public string DisplayUUID; + + public override string ToString() + { + return String.Format("Network 0x{0:X4}", ONID); + } + + public bool Equals(NitNetworkMeta other) + { + return ONID == other.ONID; + } + + public override bool Equals(object? obj) + { + return obj is NitNetworkMeta other && Equals(other); + } + + public override int GetHashCode() + { + return ONID.GetHashCode(); + } + } + + private class NitCoordinateComparer : IComparer + { + public int Compare(NitNetworkMeta x, NitNetworkMeta y) + { + return x.ONID.CompareTo(y.ONID); + } + } + + private SortedList> nitDisplay; + private string nitTableUuid; + private bool HasNit; + + public void NotifyNit(NitTransportStream transportStream) + { + TsType = 1; + HasNit = true; + + if (nitDisplay == null) + nitDisplay = new SortedList>(new NitCoordinateComparer()); + + NitNetworkMeta nnm = new NitNetworkMeta(); + nnm.ONID = transportStream.OriginalNetworkId; + if (!nitDisplay.ContainsKey(nnm)) + { + lock (nitDisplay) + { + nitDisplay.Add(nnm, new SortedList()); + } + } + + SortedList nitTransportStreams = nitDisplay[nnm]; + if (nitTransportStreams.ContainsKey(transportStream.TransportStreamId)) + return; + + lock (nitTransportStreams) + { + nitTransportStreams.Add(transportStream.TransportStreamId, transportStream); + } + } + + private string GetFrequencyString(NitTransportStream nts) + { + if (nts.Frequency.HasValue && nts.Polarization.HasValue) + return String.Format("{0} Mhz, {1}", nts.Frequency.Value / 100, nts.Polarization.ToString().Substring(0, 1)); + + return "???"; + } + + private void RenderNit() + { + if (nitDisplay == null) + return; + + if (string.IsNullOrWhiteSpace(nitTableUuid)) + nitTableUuid = Guid.NewGuid().ToString(); + + if (ImGui.Begin("Network Information Table")) + { + lock (nitDisplay) + { + foreach (KeyValuePair> keyValuePair in nitDisplay) + { + if (ImGui.CollapsingHeader(keyValuePair.Key.ToString())) + { + if (string.IsNullOrEmpty(keyValuePair.Key.DisplayUUID)) + keyValuePair.Key.DisplayUUID = Guid.NewGuid().ToString(); + if (ImGui.BeginTable(keyValuePair.Key.DisplayUUID, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + lock (keyValuePair.Value) + { + foreach (KeyValuePair nitTransportStream in keyValuePair + .Value) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(nitTransportStream.Value.DeliveryMethod.ToString().Replace('_', '_')); + + ImGui.TableSetColumnIndex(1); + if (nitTransportStream.Value.OrbitalPosition.HasValue && + nitTransportStream.Value.East.HasValue) + { + SafeText(String.Format("{0:F1} °{1}", + nitTransportStream.Value.OrbitalPosition.Value, + nitTransportStream.Value.East.Value ? "E" : "W")); + } + + ImGui.TableSetColumnIndex(2); + SafeText(GetFrequencyString(nitTransportStream.Value)); + + ImGui.TableSetColumnIndex(3); + if (nitTransportStream.Value.SymbolRate.HasValue) + SafeText(String.Format("{0} ksym/s", + nitTransportStream.Value.SymbolRate / 10)); + } + } + } + ImGui.EndTable(); + } + } + } + ImGui.End(); + } + } + + #endregion + + #region MPE + + private IpTrafficInfoComparer trafficInfoComparer; + private string mpeTableUuid; + private List> mpeDisplays; + private bool HasMpe; + + public void NotifyMpeTraffic(IpTrafficInfo iti, int ipv4PacketLength) + { + if (trafficInfoComparer == null) + trafficInfoComparer = new IpTrafficInfoComparer(); + HasMpe = true; + if (mpeDisplays == null) + mpeDisplays = new List>(); + + lock (mpeDisplays) + { + foreach (KeyValuePair line in mpeDisplays) + { + if (line.Key.Equals(iti)) + { + line.Value.CountPacket(ipv4PacketLength); + return; + } + } + + KeyValuePair newChild = new KeyValuePair(iti, new IpPerformanceInfo()); + newChild.Value.CountPacket(ipv4PacketLength); + mpeDisplays.Add(newChild); + } + } + + + + private void RenderMpe() + { + if (mpeDisplays == null) + return; + + if (secondTick) + { + lock (mpeDisplays) + { + foreach (KeyValuePair line in mpeDisplays) + { + line.Value.UpdatePerSeconds(); + } + } + } + + string windowName = String.Format("{0} Encapsulation", TsType == 1 ? "Multiprotocol" : "Generic Stream"); + if (ImGui.Begin(windowName)) + { + if (mpeDisplays != null) + { + if (mpeDisplays.Count > 0) + { + SafeText(String.Format("Communication parties: {0}", mpeDisplays.Count)); + } + } + if (string.IsNullOrEmpty(mpeTableUuid)) + mpeTableUuid = Guid.NewGuid().ToString(); + if (ImGui.BeginTable(mpeTableUuid, 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoSavedSettings)) + { + ImGui.TableSetupColumn("Protocol"); + ImGui.TableSetupColumn("Source IP"); + ImGui.TableSetupColumn("Destination IP"); + ImGui.TableSetupColumn("Packets"); + ImGui.TableSetupColumn("Traffic"); + ImGui.TableHeadersRow(); + + lock (mpeDisplays) + { + mpeDisplays.Sort(trafficInfoComparer); + foreach (KeyValuePair ipPerformanceInfo in mpeDisplays) + { + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(IpTrafficInfo.GetProtocolName(ipPerformanceInfo.Key.Protocol)); + + ImGui.TableSetColumnIndex(1); + SafeText(RenderIp(ipPerformanceInfo, false)); + + ImGui.TableSetColumnIndex(2); + SafeText(RenderIp(ipPerformanceInfo, true)); + + ImGui.TableSetColumnIndex(3); + SafeText(ipPerformanceInfo.Value.TotalPackets.ToString()); + + ImGui.TableSetColumnIndex(4); + SafeText(String.Format("{0:F1} kb/s", + (double)ipPerformanceInfo.Value.BytesPerSecond / 1000.0)); + } + } + + ImGui.EndTable(); + } + ImGui.End(); + } + } + + private string RenderIp(KeyValuePair ipPerformanceInfo, bool destination) + { + if (!destination) + { + if (string.IsNullOrEmpty(ipPerformanceInfo.Key.SourceName)) + return ipPerformanceInfo.Key.Source.ToString(); + else + return ipPerformanceInfo.Key.SourceName; + } + else + { + if (string.IsNullOrEmpty(ipPerformanceInfo.Key.TargetName)) + return ipPerformanceInfo.Key.Target.ToString(); + else + return ipPerformanceInfo.Key.TargetName; + } + } + + #endregion + + #region AIT + + private SortedList aitDisplay; + private string aitTableUuid; + private bool HasAit; + public void NotifyAit(AitApplication aitApplication) + { + TsType = 1; + HasAit = true; + + if (aitDisplay == null) + aitDisplay = new SortedList(new ApplicationIdentifierComparer()); + + lock (aitDisplay) + { + if (!aitDisplay.ContainsKey(aitApplication.ApplicationIdentifier)) + { + aitDisplay.Add(aitApplication.ApplicationIdentifier, aitApplication); + } + } + } + + private void RenderAit() + { + if (aitDisplay == null) + return; + + if (ImGui.Begin("Application Identification Table")) + { + if (string.IsNullOrEmpty(aitTableUuid)) + aitTableUuid = Guid.NewGuid().ToString(); + + if (ImGui.BeginTable(aitTableUuid, 2, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + ImGui.TableSetupColumn("Application Name"); + ImGui.TableSetupColumn("Transport"); + ImGui.TableHeadersRow(); + + lock (aitDisplay) + { + foreach (KeyValuePair keyValuePair in aitDisplay) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(keyValuePair.Value.TryGetName()); + + ImGui.TableSetColumnIndex(1); + foreach (TransportProtocolDescriptor transportProtocolDescriptor in keyValuePair.Value.TransportProtocols) + { + SafeText(transportProtocolDescriptor.Selector.ToString()); + } + } + } + + ImGui.EndTable(); + } + ImGui.End(); + } + } + #endregion + + #region DSM-CC Modules + + private struct DsmCcModuleIdentifier + { + public int pid; + public ushort moduleId; + public byte moduleVersion; + + } + + private sealed class DsmCcModuleIdentifierComparer : IComparer + { + public int Compare(DsmCcModuleIdentifier x, DsmCcModuleIdentifier y) + { + var pidComparison = x.pid.CompareTo(y.pid); + if (pidComparison != 0) return pidComparison; + var moduleIdComparison = x.moduleId.CompareTo(y.moduleId); + if (moduleIdComparison != 0) return moduleIdComparison; + return x.moduleVersion.CompareTo(y.moduleVersion); + } + } + + + private SortedList dsmCcDisplay; + private string objectCarouselTableUuid; + + public void DsmCcModuleAdd(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion) + { + TsType = 1; + HasDsmCc = true; + + if (dsmCcDisplay == null) + dsmCcDisplay = new SortedList(new DsmCcModuleIdentifierComparer()); + + DsmCcModuleIdentifier id = new DsmCcModuleIdentifier(); + id.pid = elementaryPid; + id.moduleId = moduleInfoModuleId; + id.moduleVersion = moduleInfoModuleVersion; + lock (dsmCcDisplay) + { + dsmCcDisplay.Add(id, 0); + } + } + + public void DsmCcModuleProgress(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion, + double moduleInfoDownloadProgress) + { + TsType = 1; + HasDsmCc = true; + + if (dsmCcDisplay == null) + return; + + DsmCcModuleIdentifier id = new DsmCcModuleIdentifier(); + id.pid = elementaryPid; + id.moduleId = moduleInfoModuleId; + id.moduleVersion = moduleInfoModuleVersion; + if (!dsmCcDisplay.ContainsKey(id)) + return; + lock (dsmCcDisplay) + { + dsmCcDisplay[id] = moduleInfoDownloadProgress; + } + } + + public void DsmCcModuleComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion) + { + throw new NotImplementedException(); + } + + + private void RenderDataCarousels() + { + if (dsmCcDisplay == null) + return; + if (dsmCcDisplay.Count == 0) + return; + + if (ImGui.Begin("Digital Storage Media Command & Control, Data Carousels")) + { + if (string.IsNullOrEmpty(objectCarouselTableUuid)) + { + objectCarouselTableUuid = Guid.NewGuid().ToString(); + } + + if (ImGui.BeginTable(objectCarouselTableUuid, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + ImGui.TableSetupColumn("PID"); + ImGui.TableSetupColumn("Module ID"); + ImGui.TableSetupColumn("Version"); + ImGui.TableSetupColumn("Progress"); + ImGui.TableHeadersRow(); + + lock (dsmCcDisplay) + { + foreach (KeyValuePair keyValuePair in dsmCcDisplay) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(String.Format("{0}", keyValuePair.Key.pid)); + + ImGui.TableSetColumnIndex(1); + SafeText(String.Format("{0}", keyValuePair.Key.moduleId)); + + ImGui.TableSetColumnIndex(2); + SafeText(String.Format("{0}", keyValuePair.Key.moduleVersion)); + + ImGui.TableSetColumnIndex(3); + ImGui.SetNextItemWidth(100); + ImGui.ProgressBar(Convert.ToSingle(keyValuePair.Value) / 100.0f, Vector2.Zero, String.Format("{0}%", keyValuePair.Value)); + } + } + ImGui.EndTable(); + } + ImGui.End(); + } + + } + + #endregion + + public void NotifyWss(ushort programNumber, WssDataBlock wssDataBlock) + { + throw new NotImplementedException(); + } + + #region Stream Type Autodetection + + private Dictionary streamTypes; + + public void NotifyStreamTypeDetection(string contestantTag, int pid) + { + if (streamTypes == null) + streamTypes = new Dictionary(); + streamTypes[pid] = contestantTag; + } + + #endregion + + #region BAT + private struct DisplayableBat + { + public string Name; + public List Linkages; + public string TableUuid; + public HashSet TransportStreams; + } + + private SortedList batDisplay; + private bool HasBat; + + public void NotifyBat(BatBouquet batBouquet) + { + TsType = 1; + HasBat = true; + + if (batDisplay == null) + batDisplay = new SortedList(); + + if (batDisplay.ContainsKey(batBouquet.BouquetId)) + return; + + DisplayableBat child = new DisplayableBat(); + child.Name = batBouquet.TryGetName(); + child.Linkages = batBouquet.Linkages; + child.TableUuid = Guid.NewGuid().ToString(); + child.TransportStreams = new HashSet(); + + lock (batDisplay) + { + batDisplay[batBouquet.BouquetId] = child; + } + } + + + public void NotifyBatTs(ushort batBouquetBouquetId, BatTransportStream child) + { + TsType = 1; + HasBat = true; + + if (batDisplay == null) + return; + if (!batDisplay.ContainsKey(batBouquetBouquetId)) + return; + + batDisplay[batBouquetBouquetId].TransportStreams.Add(child); + } + + private void RenderBat() + { + if (batDisplay == null) + return; + + if (batDisplay.Count == 0) + return; + + if (ImGui.Begin("Bouquet Association Table")) + { + lock (batDisplay) + { + foreach (KeyValuePair keyValuePair in batDisplay) + { + if (ImGui.CollapsingHeader(String.Format("Bouquet #{0} - {1}", keyValuePair.Key, keyValuePair.Value.Name))) + { + if (ImGui.BeginTable(keyValuePair.Value.TableUuid, 5, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + ImGui.TableSetupColumn("L/TS"); + ImGui.TableSetupColumn("ONID"); + ImGui.TableSetupColumn("TSID"); + ImGui.TableSetupColumn("Service"); + ImGui.TableSetupColumn(""); + ImGui.TableHeadersRow(); + + lock (keyValuePair.Value.Linkages) + { + foreach (LinkageDescriptor linkageDescriptor in keyValuePair.Value.Linkages) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText("Link"); + + ImGui.TableSetColumnIndex(1); + SafeText(String.Format("{0:X4}", linkageDescriptor.OriginalNetworkId)); + + ImGui.TableSetColumnIndex(2); + SafeText(String.Format("{0:X4}", linkageDescriptor.TransportStreamId)); + + ImGui.TableSetColumnIndex(3); + SafeText(ResolveServiceDisplayName(linkageDescriptor.ServiceId)); + + ImGui.TableSetColumnIndex(4); + SafeText(linkageDescriptor.LinkageType.ToString()); + } + } + + lock (keyValuePair.Value.TransportStreams) + { + foreach (BatTransportStream valueTransportStream in keyValuePair.Value.TransportStreams) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText("TS"); + + ImGui.TableSetColumnIndex(1); + SafeText(String.Format("{0:X4}", valueTransportStream.OriginalNetworkId)); + + ImGui.TableSetColumnIndex(2); + SafeText(String.Format("{0:X4}", valueTransportStream.TransportStreamId)); + + if (valueTransportStream.ServiceList != null) + { + foreach (ServiceListDescriptor.Service service in valueTransportStream.ServiceList) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText("Service"); + + ImGui.TableSetColumnIndex(3); + SafeText(ResolveServiceDisplayName(service.ServiceId)); + + ImGui.TableSetColumnIndex(4); + SafeText(service.ServiceType.ToString()); + } + } + } + } + ImGui.EndTable(); + } + } + } + } + ImGui.End(); + } + } + + #endregion + + #region DSM-CC Object Carousel + private SortedList displayObjectCarouselRoots; + private bool HasDsmCc; + + private string GetServiceNameFromPid(int pid) + { + lock (patDisplay) + { + foreach (KeyValuePair keyValuePair in patDisplay) + { + PatEntry patEntry = keyValuePair.Value; + if (patEntry.pmt == null) + continue; + + foreach (ProgramMappingStream programMappingStream in patEntry.pmt.Streams) + { + if (programMappingStream.ElementaryPid == pid) + { + return ResolveServiceDisplayName(patEntry.programId); + } + } + } + } + + return "???"; + } + + public void DsmCcVfs(VfsFile vfsFile) + { + TsType = 1; + HasDsmCc = true; + if (displayObjectCarouselRoots == null) + displayObjectCarouselRoots = new SortedList(); + if (displayObjectCarouselRoots.ContainsKey(vfsFile.SourcePid)) + return; + + VfsDirectory masterDirectory = vfsFile.ParentDirectory; + while (masterDirectory.ParentDirectory != null) + masterDirectory = masterDirectory.ParentDirectory; + + lock (displayObjectCarouselRoots) + { + displayObjectCarouselRoots.Add(vfsFile.SourcePid, masterDirectory); + } + } + + private void RenderObjectCarousels() + { + if (displayObjectCarouselRoots == null) + return; + + if (ImGui.Begin("Digital Storage Media - Command & Control, Object Carousels")) + { + lock (displayObjectCarouselRoots) + { + foreach (KeyValuePair displayObjectCarouselRoot in displayObjectCarouselRoots) + { + string name = String.Format("Object Carousel in PID 0x{1:X4} (Service: {0})", GetServiceNameFromPid(displayObjectCarouselRoot.Key), displayObjectCarouselRoot.Key); + if (ImGui.CollapsingHeader(name)) + { + RenderDirectoryNode(displayObjectCarouselRoot.Value); + } + } + } + } + } + + private void RenderDirectoryNode(VfsDirectory directory) + { + if (!directory.SkyscrpaerUiData.ContainsKey("UUID")) + directory.SkyscrpaerUiData.Add("UUID", Guid.NewGuid().ToString()); + + string dname = directory.Name; + if (string.IsNullOrEmpty(dname) && directory.ParentDirectory == null) + dname = ""; + + if (ImGui.TreeNode(directory.SkyscrpaerUiData["UUID"].ToString(), dname)) + { + foreach (VfsDirectory subdirectory in directory.subdirectories) + { + RenderDirectoryNode(subdirectory); + } + + foreach (VfsFile directoryFile in directory.files) + { + SafeText(directoryFile.Name); + } + + foreach (VfsEvent directoryEvent in directory.events) + { + SafeText(directoryEvent.Name); + } + ImGui.TreePop(); + } + } + #endregion + + #region TOT + + private DateTime? totTime; + private LocalTimeOffsetDescriptor totDescriptor; + private string totDisplayUuid; + private bool HasTot; + + public void NotifyTot(DateTime utcTime, LocalTimeOffsetDescriptor ltod) + { + TsType = 1; + HasTot = true; + + totTime = utcTime; + totDescriptor = ltod; + } + + private void RenderTot() + { + if (!totTime.HasValue) + return; + + if (ImGui.Begin("Time Offset Table")) + { + SafeText(totTime.ToString()); + + if (totDescriptor != null) + { + if (totDescriptor.Valid) + { + if (string.IsNullOrEmpty(totDisplayUuid)) + totDisplayUuid = Guid.NewGuid().ToString(); + + if (ImGui.BeginTable(totDisplayUuid, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoSavedSettings)) + { + ImGui.TableSetupColumn("Region"); + ImGui.TableSetupColumn("Polarity"); + ImGui.TableSetupColumn("Offset"); + ImGui.TableHeadersRow(); + + foreach (LocalTimeOffsetDescriptor.LocalTime totDescriptorLocalTimeOffset in totDescriptor.LocalTimeOffsets) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(totDescriptorLocalTimeOffset.CountryCode); + + ImGui.TableSetColumnIndex(1); + bool b = totDescriptorLocalTimeOffset.LocalTimeOffsetPolarity; + ImGui.BeginDisabled(true); + ImGui.Checkbox("", ref b); + ImGui.EndDisabled(); + + ImGui.TableSetColumnIndex(2); + SafeText(totDescriptorLocalTimeOffset.LocalTimeOffset.ToString()); + } + ImGui.EndTable(); + } + } + } + ImGui.End(); + } + } + #endregion + + #region TDT + private DateTime? tdtDisplay; + private bool HasTdt; + public void NotifyTdt(DateTime utcTime) + { + TsType = 1; + HasTdt = true; + tdtDisplay = utcTime; + } + + private void RenderTdt() + { + if (tdtDisplay.HasValue) + { + if (ImGui.Begin("Time and Date Table")) + { + SafeText(tdtDisplay.Value.ToString()); + ImGui.End(); + } + } + } + #endregion + + #region CAT + private string caTableUuid; + private HashSet caDisplay; + private bool HasCat; + public void NotifyCat(CaDescriptor caDescriptor) + { + TsType = 1; + HasCat = true; + + if (caDisplay == null) + caDisplay = new HashSet(); + + lock (caDisplay) + { + caDisplay.Add(caDescriptor); + } + } + + private void RenderCat() + { + if (caDisplay == null) + return; + + if (ImGui.Begin("Conditional Access Table")) + { + if (string.IsNullOrEmpty(caTableUuid)) + caTableUuid = Guid.NewGuid().ToString(); + + if (ImGui.BeginTable(caTableUuid, 3, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit)) + { + ImGui.TableSetupColumn("CA System"); + ImGui.TableSetupColumn("ECM/EMM PID"); + ImGui.TableSetupColumn("Private Data"); + ImGui.TableHeadersRow(); + lock (caDisplay) + { + foreach (CaDescriptor caDescriptor in caDisplay) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + SafeText(CaSystemNames.GetHumanReadableName(caDescriptor.CaSystemId)); + + ImGui.TableSetColumnIndex(1); + SafeText(String.Format("{0:X4}", caDescriptor.CaPid)); + + ImGui.TableSetColumnIndex(2); + if (caDescriptor.PrivateData != null) + { + if (caDescriptor.PrivateData.Length != 0) + SafeText(BitConverter.ToString(caDescriptor.PrivateData)); + } + } + } + ImGui.EndTable(); + } + ImGui.End(); + } + } + #endregion + + public void NotifyScte35(ushort programNumber, SpliceInsert spliceInsert) + { + throw new NotImplementedException(); + } + + public void NotifyScte35(ushort programNumber, TimeSignal spliceInsert) + { + throw new NotImplementedException(); + } + + public void SetMemorySaverMode(bool saveMemory) + { + throw new NotImplementedException(); + } + + public void NotifyDocsisCarrier(DocsisEnvironment docsisEnvironment) + { + throw new NotImplementedException(); + } + + public void NotifyDocsisFrequency(uint? frequency, bool isUpstream, object mmm) + { + throw new NotImplementedException(); + } + + public void SetGseMode() + { + throw new NotImplementedException(); + } + + #region Framegrabs + + private Queue framegrabWindows; + private int windowSpawnX = 100; + public void ShowFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, + int mappingStreamElementaryPid, byte[] imageData) + { + if (framegrabWindows == null) + framegrabWindows = new Queue(); + + Tasks.EnqueueTask(() => + { + string resolveServiceDisplayName = ResolveServiceDisplayName(mappingProgramNumber); + if (string.IsNullOrEmpty(resolveServiceDisplayName)) + resolveServiceDisplayName = String.Format("Framegrab of Service #{0:X4}"); + else + resolveServiceDisplayName = String.Format("Framegrab of \"{0}\"", resolveServiceDisplayName); + + if (PictureWindow.Renderer == null) + return; + + Renderer renderer = PictureWindow.Renderer; + string displayName = resolveServiceDisplayName; + + PictureWindow child = new PictureWindow(renderer, displayName, imageData); + child.SetPosition(windowSpawnX, windowSpawnX); + child.SetTaskQueue(Tasks, jobContext.Renderables); + + jobContext.Renderables.Add(child); + framegrabWindows.Enqueue(child); + }); + } + #endregion + + public void NotifyBlockstreamCarrier() + { + throw new NotImplementedException(); + } + + #region Database Callbacks + public IEnumerable GetServices() + { + if (HasPmt) + { + foreach (var (pmtPid, patValue) in patDisplay) + { + ushort serviceId = patValue.programId; + SdtCoordinate sdt = ResolveService(serviceId); + string providerName = sdt.ProviderName; + string serviceName = sdt.ServiceName; + ushort? caId = ResolveCaId(patValue.pmt, sdt); + ServiceDescriptor.ServiceTypeCoding? serviceType = sdt.ServiceType; + yield return new HumanReadableService(serviceId, providerName, serviceName, caId, serviceType.GetValueOrDefault()); + } + } + } + + private ushort? ResolveCaId(ProgramMapping patValuePmt, SdtCoordinate sdt) + { + if (patValuePmt != null) + { + if (patValuePmt.CaSystemId.HasValue) + return patValuePmt.CaSystemId.Value; + + foreach (ProgramMappingStream stream in patValuePmt.Streams) + { + if (stream.CaSystemId.HasValue) + return stream.CaSystemId; + } + } + + if (sdt.CaIdentifiers != null) + { + if (sdt.CaIdentifiers.Length > 0) + return sdt.CaIdentifiers[0]; + } + + return null; + } + #endregion + #endregion + + + #region During Blindscan + private FoundFrequenciesWindow2 foundFrequenciesWindow; + public void OnBlindscanOpenFoundFrquenciesWindow(List foundFrequencies, STD_TYPE tunerMetadataType) + { + foundFrequenciesWindow = new FoundFrequenciesWindow2(foundFrequencies); + jobContext.Renderables.Add(foundFrequenciesWindow); + } + + public void OnBlindscanJobDone(bool success) + { + jobContext.Puppets[0].AutoMoveToHome(); + jobContext.Puppets[1].AutoMoveToHome(); + jobContext.Puppets[2].AutoMoveTo(new Point(0, 720 / 2)); + jobContext.Puppets[3].AutoMoveTo(new Point(1280 / 2, 0)); + + jobContext.ReadyForNextJob = true; + } + + public void OnBlindscanErrorMessage(string blindscanningLowHorizontalAreaFailed) + { + throw new NotImplementedException(); + } + + public void OnBlindscanBandComplete() + { + foreach (CharSet jobContextPuppet in jobContext.Puppets) + jobContextPuppet.AutoMoveToHome(); + } + + private BlindscanProgressWindow _blindscanProgressWindow; + public void OnBlindscanBeforeBLScan(int minimum, int currentProgress, int maximum) + { + _blindscanProgressWindow = new BlindscanProgressWindow(); + _blindscanProgressWindow.Start = minimum; + _blindscanProgressWindow.Progress = minimum; + _blindscanProgressWindow.End = maximum; + jobContext.Renderables.Add(_blindscanProgressWindow); + } + + public void OnBlindscanAfterBLScan() + { + jobContext.Renderables.Remove(_blindscanProgressWindow); + _blindscanProgressWindow = null; + } + + public void OnBlindscanSearchResult1Callback(BlindscanSearchResult searchResult, int polarityIndex, + int lnbTypeMinimumFrequency, int lnbTypeMaximumFrequency) + { + Blindscan.BlindscanResult blindscanResult = new Blindscan.BlindscanResult(searchResult.SearchResult, lnbTypeMinimumFrequency, lnbTypeMaximumFrequency); + jobContext.Puppets[blindscanResult.sr1.Pol].AutoMoveTo(blindscanResult.Position); + lock (jobContext.PressurePlates) + { + jobContext.PressurePlates.Add(blindscanResult); + } + + _blindscanProgressWindow.Progress = searchResult.SearchResult.Freq; + + SoundPlayer.PlaySoundFile("lock.wav"); + } + + private Point GetFrequencyPosition(SearchResult searchResult, int satPositionMinFreq, int satPositionMaxFreq) + { + int x = 0, y = 0; + + if (searchResult.Pol == 0) + { + //Horizontal + int w = (searchResult.Freq / 1000) - satPositionMinFreq; + int hundert = 1280; + int g = (satPositionMaxFreq - satPositionMinFreq); + + x = w * hundert / g; + y = 720 / 2; + } + else + { + //Vertical + int w = (searchResult.Freq / 1000) - satPositionMinFreq; + int hundert = 720; + int g = (satPositionMaxFreq - satPositionMinFreq); + + x = 1280 / 2; + y = w * hundert / g; + } + + Point position = new Point(x, y); + return position; + } + + public void OnBlindscanBeforeSetChannel(BlindscanSearchResult blindscanResult, LnbType lnb) + { + Point point = GetFrequencyPosition(blindscanResult.SearchResult, lnb.MinimumFrequency, lnb.MaximumFrequency); + jobContext.Puppets[2 + blindscanResult.SearchResult.Pol].AutoMoveTo(point); + } + + public void OnScrapeBandComplete() + { + jobContext.Puppets[0].AutoMoveToHome(); + jobContext.Puppets[1].AutoMoveToHome(); + jobContext.Puppets[2].AutoMoveToHome(); + jobContext.Puppets[3].AutoMoveToHome(); + + } + + public void OnBlindscanScrapeTransponderComplete(BlindscanSearchResult blindscanResult) + { + lock (jobContext.PressurePlates) + { + foreach (IPressurePlate pressurePlate in jobContext.PressurePlates) + { + Blindscan.BlindscanResult result = pressurePlate as Blindscan.BlindscanResult; + if (result.Satellite) + { + if (result.GetFrequency() == blindscanResult.GetFrequency()) + { + jobContext.PressurePlates.Remove(result); + break; + } + } + else + { + throw new NotImplementedException("non satellite pressure plate."); + } + } + } + } + + private SdlScottPlotWindowRfSpectrum rfSpectrumWindow; + public void OnBlindscanBeginRfSpectrum() + { + Tasks.EnqueueTask(() => + { + rfSpectrumWindow = new SdlScottPlotWindowRfSpectrum(jobContext.ImgUiDevice); + jobContext.Renderables.Add(rfSpectrumWindow); + }); + } + + public void OnBlindscanRfSpectrumEnqueueSample(SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, int frequency, double rf) + { + Tasks.EnqueueTask(() => + { + rfSpectrumWindow.EnqueueSample(polarization, frequency, rf); + }); + } + + public void OnBlindscanEndRfSpectrum() + { + Tasks.EnqueueTask(() => + { + jobContext.Renderables.Remove(rfSpectrumWindow); + rfSpectrumWindow.Dispose(); + rfSpectrumWindow = null; + }); + } + + private IqWindow iqWindow; + public void OnBlindscanBeginIqSpectrum(IqChartData result) + { + Tasks.EnqueueTask(() => + { + iqWindow = new IqWindow(jobContext.ImgUiDevice, result); + jobContext.Renderables.Add(iqWindow); + }); + } + + public void OnBlindscanEndIq() + { + Tasks.EnqueueTask(() => + { + jobContext.Renderables.Remove(iqWindow); + iqWindow.Dispose(); + iqWindow = null; + }); + } + + public void OnBlindscanLockFail(SearchResult satelliteSr, BlindscanResultState resultState) + { + SoundPlayer.PlaySoundFile("fail.wav"); + } + + public void OnBlindscanFilterSetUp() + { + Tasks.EnqueueTask(() => + { + jobContext.Renderables.Add(this); + }); + foundFrequenciesWindow.allowZapNow = true; + } + + public void OnBlindscanScrapeStopCondition() + { + foundFrequenciesWindow.allowZapNow = false; + } + + public void OnBlindscanAfterPacketDrain() + { + Tasks.EnqueueTask(() => + { + jobContext.Renderables.Remove(this); + ResetWindows(); + }); + } + + public void OnBlindscanPacketError(int errorCount, int length) + { + throw new NotImplementedException(); + } + + public void OnBlindscanPacketOk(int numPackets, int packetsQueueCount) + { + foundFrequenciesWindow.statusPacketsInTotal += (uint)numPackets; + foundFrequenciesWindow.statusPacketsInQueue = packetsQueueCount; + } + + public bool IsZapNowRequested() + { + if (foundFrequenciesWindow.zapNowRequested) + { + foundFrequenciesWindow.zapNowRequested = false; + return true; + } + + return false; + } + + public bool MayAutoZap() + { + return !foundFrequenciesWindow.doNotAutoZap; + } + + public TaskQueue Tasks { get; set; } + + internal JobContext jobContext; + #endregion + } +} diff --git a/GUIs/skyscraper8.UI.ImGui/Program.cs b/GUIs/skyscraper8.UI.ImGui/Program.cs index 60405ed..5c30abe 100644 --- a/GUIs/skyscraper8.UI.ImGui/Program.cs +++ b/GUIs/skyscraper8.UI.ImGui/Program.cs @@ -23,9 +23,11 @@ using skyscraper5.Skyscraper.Scraper.Storage; using skyscraper5.Skyscraper.Scraper.Storage.Filesystem; using skyscraper5.Skyscraper.Scraper.Storage.InMemory; using skyscraper5.src.Skyscraper; +using skyscraper8.Skyscraper.FrequencyListGenerator; using skyscraper8.Skyscraper.Plugins; using skyscraper8.Skyscraper.Scraper.Storage; using skyscraper8.UI.ImGui.Forms; +using skyscraper8.UI.SDL2.Jobs; using Color = ScottPlot.Color; using Exception = System.Exception; using Version = System.Version; @@ -201,6 +203,7 @@ namespace SkyscraperUI private DataStorage dataStorage; private ObjectStorage objectStorage; private IGpsReceiver gps; + private TaskQueue tasks; private List messageWindows; @@ -223,6 +226,7 @@ namespace SkyscraperUI private ConfigureGpsWindow configureGpsWindow; private GpsDisplay gpsDisplayWindow; private BlindscanJobDeleter jobDeleter; + private InheritedBlindscanConfigWindow inheritedBlindscanWindow; private ScreenHack[] allScreenHacks; private ScreenHack currentScreenHack; @@ -243,7 +247,11 @@ namespace SkyscraperUI private void BeforeRenderFrame() - { + { + if (tasks == null) + tasks = new TaskQueue(); + tasks.ProcessTasks(); + if (jobContext != null) { if (jobContext.MessageQueue.Count != 0) @@ -473,6 +481,8 @@ namespace SkyscraperUI blindscanWindow = new Blindscan(tuners, satellitePositions, lnbTypes, dataStorage); if (ImGui.MenuItem("Perform Cooperative Blindscan", CanPerformBlindscan())) coopBlindscanWindow = new CoopBlindscan(tuners, satellitePositions, lnbTypes, dataStorage); + if (ImGui.MenuItem("Perform inherited Blindscan", CanPerformBlindscan())) + inheritedBlindscanWindow = new InheritedBlindscanConfigWindow(tuners, satellitePositions, lnbTypes, dishTypes, dataStorage, objectStorage, gps, ini, streamReader, tasks); if (ImGui.MenuItem("Cancel current job", CanCancelJob())) jobContext.Job.Cancel(); if (ImGui.MenuItem("Quit")) @@ -722,15 +732,32 @@ namespace SkyscraperUI if (coopBlindscanWindow != null) { - coopBlindscanWindow.Render(); - if (!coopBlindscanWindow.WindowOpen) + coopBlindscanWindow.Render(); + if (!coopBlindscanWindow.WindowOpen) + { + if (coopBlindscanWindow.Configuration != null) + { + EnrollJob(coopBlindscanWindow); + } + + coopBlindscanWindow = null; + } + } + + if (inheritedBlindscanWindow != null) + { + inheritedBlindscanWindow.Render(); + if (!inheritedBlindscanWindow.IsWindowOpen()) { - if (coopBlindscanWindow.Configuration != null) - { - EnrollJob(coopBlindscanWindow); - } - coopBlindscanWindow = null; + BlindscanJobConfiguration jobConfiguration = inheritedBlindscanWindow.GetConfiguration(); + if (jobConfiguration != null) + { + InheritedBlindscanJob inheritedBlindscanJob = new InheritedBlindscanJob(jobConfiguration); + EnrollJob(inheritedBlindscanJob); + inheritedBlindscanWindow = null; + } } + } if (aboutWindow != null) diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index c134800..18d98af 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -38,6 +38,7 @@ namespace skyscraper5 private static void IntegrationTest() { RtspClient rtspClient = new RtspClient("172.20.20.121", 554); + rtspClient.AutoReconnect = true; RtspOptionsResponse options = rtspClient.GetOptions("/"); string url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11954, true, 27500); RtspDescribeResponse describe = rtspClient.GetDescribe(url); @@ -59,6 +60,31 @@ namespace skyscraper5 rtspClient.GetTeardown(setup); Console.WriteLine("{0} RTCPs",rtcps); Console.WriteLine("{0} RTPs",rtps); + + Thread.Sleep(1000); + + url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_VERTICAL, 10758, true, 22000); + describe = rtspClient.GetDescribe(url); + sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); + + rtcps = 0; + rtps = 0; + + setup = rtspClient.GetSetup(url); + setup.OnRtcpPacket += ((data, length) => + rtcps++); + setup.OnRtpPacket += (data, length) => + rtps++; + + play = rtspClient.GetPlay(setup); + + Thread.Sleep(5000); + + rtspClient.AutoReconnect = false; + rtspClient.GetTeardown(setup); + Console.WriteLine("{0} RTCPs", rtcps); + Console.WriteLine("{0} RTPs", rtps); + rtspClient.Dispose(); } static void Main(string[] args) @@ -212,13 +238,7 @@ namespace skyscraper5 GpsManager.GpsTest(); return; } - - if (args[0].ToLowerInvariant().Equals("mk-cable-csv")) - { - new CableFrequencyListGenerator().Run(); - return; - } - + if (args[0].ToLowerInvariant().Equals("what-can-i-receive")) { WhatCanIReceive.StandaloneProgram(); @@ -247,27 +267,7 @@ namespace skyscraper5 } passing.Run(); } - - private static void StreamReaderTest(IStreamReader streamReader) - { - List streamReaderTuners = StreamReaderScanController.GetTuners(streamReader); - if (streamReaderTuners.Count == 0) - { - Console.WriteLine("No tuners, lmao."); - return; - } - - //FileInfo fi = new FileInfo("blindscan.json"); - StreamReaderScanController srsc = new StreamReaderScanController(streamReader, streamReaderTuners[0]); - //srsc.SetDefaultDvbCParameters(); - srsc.SetDefaultKuBandParameters(); - srsc.SetParameter(StreamReaderScanController.StreamReaderParameter.ScanDiseqcType, 2); - srsc.SetParameter(StreamReaderScanController.StreamReaderParameter.DiseqcSwitchPosition, 1); - srsc.RunBlindscan(); - srsc.Dispose(); - return; - } - + private static void ProcessDirectory(DirectoryInfo di) { DataStorage dataStorage = new InMemoryScraperStorage(); diff --git a/skyscraper8/Skyscraper/CableFrequencyListGenerator.cs b/skyscraper8/Skyscraper/CableFrequencyListGenerator.cs deleted file mode 100644 index ae7e3a6..0000000 --- a/skyscraper8/Skyscraper/CableFrequencyListGenerator.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using skyscraper5.Dvb.Psi.Model; -using skyscraper5.Mpeg2.Psi.Model; -using skyscraper5.Skyscraper.IO; -using skyscraper5.Skyscraper.IO.CrazycatStreamReader; -using skyscraper5.Skyscraper.IO.TunerInterface; -using skyscraper5.Skyscraper.Plugins; -using skyscraper5.Skyscraper.Scraper; -using skyscraper5.Skyscraper.Scraper.Storage; -using skyscraper5.Skyscraper.Scraper.Storage.InMemory; -using skyscraper8.Skyscraper.Scraper.Storage; -using Console = System.Console; - -namespace skyscraper5.Skyscraper -{ - internal class CableFrequencyListGenerator - { - public CableFrequencyListGenerator() - { - - } - - public void Run() - { - Ini ini = PluginManager.GetInstance().Ini; - TunerFactoryConnectionManager tunerFactoryConnectionManager = TunerFactoryConnectionManager.GetInstance(); - ITunerFactory tunerFactory = tunerFactoryConnectionManager.AutoGetConfiguredTunerFactory(); - IStreamReader streamReader = tunerFactory.CreateStreamReader(); - int usableTuner = -1; - if (!streamReader.CheckForDVBExEx((x, y, z) => - { - if (usableTuner == -1 && z == STD_TYPE.STD_DVBC) - usableTuner = x; - })) - { - Console.WriteLine("Failed to check for tuners."); - return; - } - if (usableTuner == -1) - { - Console.WriteLine("no dvb-c tuner present, quitting."); - return; - } - - if (!streamReader.StartDvbEx(usableTuner)) - { - Console.WriteLine("Failed to start the tuner."); - streamReader.StopDVB(); - if (!streamReader.StartDvbEx(usableTuner)) - { - Console.WriteLine("Giving up..."); - return; - } - } - - IntPtr pSearchResult = Marshal.AllocHGlobal(ushort.MaxValue); - int tpNum = 0; - SearchResult2 sr2 = default; - if (!streamReader.AirScan(48000, 1000000, 3000, 8000, (int)STD_TYPE.STD_DVBC, pSearchResult, ref tpNum, (ref SearchResult2 searchResult) => SearchResult2Callback(searchResult))) - { - Console.WriteLine("Failed to run AirScan..."); - return; - } - - string filename = String.Format("dvb-c_{0}.csv", DateTime.Now.ToUnixTime()); - FileStream fileStream = File.OpenWrite(filename); - StreamWriter streamWriter = new StreamWriter(fileStream); - - foreach (SearchResult2 searchResult2 in searchResults) - { - double outFreq = searchResult2.Freq; - outFreq = Math.Round((double)outFreq / (double)1000.0, 0) * 1000; - outFreq /= 1000; - - Console.WriteLine("Tuning to {0} Mhz", outFreq); - if (!streamReader.SetChannel2((uint)searchResult2.Freq, (uint)searchResult2.BW)) - { - Console.WriteLine("Failed to tune."); - continue; - } - - SearchResult2 recheck = default; - if (!streamReader.SignalInfo2(ref recheck)) - { - Console.WriteLine("Failed to get signal info."); - continue; - } - - if (!recheck.Lock) - { - Console.WriteLine("No lock."); - continue; - } - - double outSymRate = searchResult2.SR; - outSymRate = Math.Round((double)outSymRate / (double)10000.0, 0) * 10000; - outSymRate /= 1000; - string outModType = ((MOD_TYPE)searchResult2.ModType).ToString(); - string outLine = String.Format("{0} Mhz;{1} kSym/s;{2}", outFreq, outSymRate, outModType); - streamWriter.WriteLine(outLine); - - StreamReaderScraperController scraper = new StreamReaderScraperController(streamReader); - scraper.DataStorage = new InMemoryScraperStorage(); - scraper.Recording = false; - Console.Write("Running PSI acquisition..."); - scraper.Run(); - Console.WriteLine(".DONE"); - - DataStorage data = scraper.DataStorage; - IEnumerable> pmtEntries = data.SelectAllPmt().ToList(); - List> tuples = data.SelectAllSdt().ToList(); - foreach (var (tsId, networkId, programMapping) in pmtEntries) - { - SdtService sdt = data.SelectSdtById(networkId, tsId, programMapping.ProgramNumber); - if (sdt == null) - { - continue; - } - outLine = String.Format("{0};{1};{2};{3};{4}", programMapping.ProgramNumber,sdt.ServiceProviderName,sdt.ServiceName,GetCaSystemName(programMapping,sdt),sdt.ServiceType); - streamWriter.WriteLine(outLine); - streamWriter.Flush(); - } - streamWriter.WriteLine(""); - - } - - if (!streamReader.StopDVB()) - { - Console.WriteLine("Failed to properly close the tuner!"); - return; - } - streamWriter.Flush(); - streamWriter.Close(); - } - - private string GetCaSystemName(ProgramMapping pmt, SdtService sdt) - { - if (pmt.CaSystemId.HasValue) - { - return CaSystemNames.GetHumanReadableName(pmt.CaSystemId.Value); - } - - if (sdt.CaIdentifiers != null) - { - if (sdt.CaIdentifiers.Length > 0) - { - return CaSystemNames.GetHumanReadableName(sdt.CaIdentifiers[0]); - } - } - - return ""; - } - - private List searchResults; - private void SearchResult2Callback(SearchResult2 searchResult) - { - if (searchResults == null) - searchResults = new List(); - searchResults.Add(searchResult); - Console.WriteLine("Heard something at {0}", searchResult.Freq / 1000); - } - - } -} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/BaseBlindscanJob.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/BaseBlindscanJob.cs new file mode 100644 index 0000000..bb44f19 --- /dev/null +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/BaseBlindscanJob.cs @@ -0,0 +1,904 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.src.Skyscraper.FrequencyListGenerator; +using skyscraper8.Skyscraper.Plugins; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; +using skyscraper8.Skyscraper.Drawing; +using skyscraper5.Dvb.Descriptors; +using skyscraper5.src.Mpeg2.PacketFilter; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.Scraper; +using System.Runtime.InteropServices; +using skyscraper5.Skyscraper.Equipment; + +namespace skyscraper8.Skyscraper.FrequencyListGenerator +{ + public class BaseBlindscanJob + { + private static PluginLogger logger = PluginLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + public BaseBlindscanJob(BlindscanJobConfiguration config) + { + if (config == null) + { + throw new ArgumentNullException(nameof(config)); + } + + this.config = config; + } + + private BlindscanJobConfiguration config; + private DbBlindscanJob jobInDb; + private List foundFrequencies; + + public void Run() + { + if (config == null) + throw new NullReferenceException("No config? Dude, what?"); + if (config.StreamReader == null) + throw new NullReferenceException("No StreamReader available"); + + + jobInDb = new DbBlindscanJob(Guid.NewGuid(), config.TunerMetadata.MacAddress, config.TunerMetadata.Type, config.DiseqcIndex, config.Gps, config.SatellitePosition); + jobInDb.HorizontalHighState = config.DoHorizontalHigh ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; + jobInDb.HorizontalLowState = config.DoHorizontalLow ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; + jobInDb.VerticalLowState = config.DoVerticalLow ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; + jobInDb.VerticalHighState = config.DoVerticalHigh ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; + config.DataStorage.InsertBlindscanJob(jobInDb); + + foundFrequencies = new List(); + config.Ui.OnBlindscanOpenFoundFrquenciesWindow(foundFrequencies, config.TunerMetadata.Type); + + if (!config.StreamReader.StartDvbEx(config.TunerMetadata.Index)) + { + throw new Exception("Failed to start DVB"); + } + if (!RunBlindscan()) + { + config.StreamReader.StopDVB(); + config.Ui.OnBlindscanJobDone(false); + return; + } + + config.Ui.OnBlindscanJobDone(true); + logger.Log(PluginLogLevel.Info,"Blindscan Job done!"); + return; + } + + public bool RunBlindscan() + { + Caps caps = config.TunerMetadata.Caps; + + if (config.DoCollectRfSpectrum) + { + RfSpectrumData rfSpectrum = GatherRfSpectrum(); + if (rfSpectrum != null) + { + config.ObjectStorage.StoreRfSpectrum(jobInDb.JobGuid, rfSpectrum); + } + } + if (caps.HasFlag(Caps.SR_BLSCAN2)) + { + SearchResult sr1 = default; + int tpNum = default; + + int lof1 = config.LnbType.Lof1 * 1000; + int lof2 = config.LnbType.Lof2 * 1000; + int lofSw = config.LnbType.LofSw * 1000; + int diseqc = config.TunerMetadata.DiseqcType; + int startFreq = config.LnbType.MinimumFrequency * 1000; + int endFreq = config.LnbType.MaximumFrequency * 1000; + bool anythingSuceeded = false; + nint allocHGlobal = Marshal.AllocHGlobal(ushort.MaxValue); + + if (lofSw != 0) + { + if (config.DoHorizontalLow) + { + if (SendDiseqcCommand(false, true)) + { + logger.Log(PluginLogLevel.Info,"Scanning low horizontal band..."); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; + config.DataStorage.UpdateJobState(jobInDb); + bool hLower = BlScan2Wrap(startFreq, lofSw, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult sr1) => SearchResult1Callback(sr1, 1)); + config.Ui.OnBlindscanBandComplete(); + if (!hLower) + { + config.Ui.OnBlindscanErrorMessage("Blindscanning low horizontal area failed."); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; + config.DataStorage.UpdateJobState(jobInDb); + } + else + { + anythingSuceeded = true; + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; + config.DataStorage.UpdateJobState(jobInDb); + SendDiseqcCommand(false, true); + RunScrape(); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + foundFrequencies.Clear(); + } + } + else + { + config.Ui.OnBlindscanErrorMessage("DiSEqC Switch to low horizontal area failed."); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; + config.DataStorage.UpdateJobState(jobInDb); + } + } + + if (config.DoHorizontalHigh) + { + if (SendDiseqcCommand(true, true)) + { + logger.Log(PluginLogLevel.Info,"Scanning high horizontal band..."); + jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; + config.DataStorage.UpdateJobState(jobInDb); + bool hUpper = BlScan2Wrap(lofSw, endFreq, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult sr1) => SearchResult1Callback(sr1, 2)); + config.Ui.OnBlindscanBandComplete(); + if (!hUpper) + { + config.Ui.OnBlindscanErrorMessage("Blindscanning high horizontal area failed."); + jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; + config.DataStorage.UpdateJobState(jobInDb); + } + else + { + anythingSuceeded = true; + jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; + config.DataStorage.UpdateJobState(jobInDb); + SendDiseqcCommand(true, true); + RunScrape(); + jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + foundFrequencies.Clear(); + } + } + else + { + config.Ui.OnBlindscanErrorMessage("DiSEqC Switch to high horizontal area failed."); + jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; + config.DataStorage.UpdateJobState(jobInDb); + } + } + + if (config.DoVerticalLow) + { + if (SendDiseqcCommand(false, false)) + { + logger.Log(PluginLogLevel.Info,"Scanning low vertical band..."); + jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; + config.DataStorage.UpdateJobState(jobInDb); + bool vLower = BlScan2Wrap(startFreq, lofSw, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult sr1) => SearchResult1Callback(sr1, 3)); + config.Ui.OnBlindscanBandComplete(); + if (!vLower) + { + config.Ui.OnBlindscanErrorMessage("Blindscanning low vertical area failed."); + jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; + config.DataStorage.UpdateJobState(jobInDb); + } + else + { + anythingSuceeded = true; + jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; + config.DataStorage.UpdateJobState(jobInDb); + SendDiseqcCommand(false, false); + RunScrape(); + jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + foundFrequencies.Clear(); + } + } + else + { + config.Ui.OnBlindscanErrorMessage("DiSEqC Switch to low vertical area failed."); + jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; + config.DataStorage.UpdateJobState(jobInDb); + } + } + + if (config.DoVerticalHigh) + { + if (SendDiseqcCommand(true, false)) + { + logger.Log(PluginLogLevel.Info,"Scanning high vertical band..."); + jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; + config.DataStorage.UpdateJobState(jobInDb); + bool vUpper = BlScan2Wrap(lofSw, endFreq, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult sr1) => SearchResult1Callback(sr1, 4)); + config.Ui.OnBlindscanBandComplete(); + if (!vUpper) + { + config.Ui.OnBlindscanErrorMessage("Blindscanning high vertical area failed."); + jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; + config.DataStorage.UpdateJobState(jobInDb); + } + else + { + anythingSuceeded = true; + jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; + config.DataStorage.UpdateJobState(jobInDb); + SendDiseqcCommand(true, false); + RunScrape(); + jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + foundFrequencies.Clear(); + } + } + else + { + config.Ui.OnBlindscanErrorMessage("DiSEqC Switch to high vertical area failed."); + jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; + config.DataStorage.UpdateJobState(jobInDb); + } + } + } + else + { + if (SendDiseqcCommand(false, true)) + { + logger.Log(PluginLogLevel.Info, string.Format("Scanning left circular band...")); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; + config.DataStorage.UpdateJobState(jobInDb); + bool lCirc = BlScan2Wrap(startFreq, endFreq, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult sr1) => SearchResult1Callback(sr1, 1)); + config.Ui.OnBlindscanBandComplete(); + if (!lCirc) + { + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; + config.DataStorage.UpdateJobState(jobInDb); + config.Ui.OnBlindscanErrorMessage("Blindscanning left circular area failed."); + } + else + { + anythingSuceeded = true; + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; + config.DataStorage.UpdateJobState(jobInDb); + SendDiseqcCommand(false, true); + RunScrape(); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + foundFrequencies.Clear(); + } + } + else + { + config.Ui.OnBlindscanErrorMessage("DiSEqC Switch to left circulation failed."); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; + config.DataStorage.UpdateJobState(jobInDb); + } + if (SendDiseqcCommand(false, false)) + { + logger.Log(PluginLogLevel.Info, string.Format("Scanning right circular band...")); + jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; + config.DataStorage.UpdateJobState(jobInDb); + bool rCirc = BlScan2Wrap(startFreq, endFreq, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult sr1) => SearchResult1Callback(sr1, 3)); + config.Ui.OnBlindscanBandComplete(); + if (!rCirc) + { + config.Ui.OnBlindscanErrorMessage("Blindscanning right circular area failed."); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; + config.DataStorage.UpdateJobState(jobInDb); + } + else + { + anythingSuceeded = true; + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; + config.DataStorage.UpdateJobState(jobInDb); + SendDiseqcCommand(false, false); + RunScrape(); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + foundFrequencies.Clear(); + } + } + else + { + config.Ui.OnBlindscanErrorMessage("DiSEqC Switch to right circulation failed."); + jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; + config.DataStorage.UpdateJobState(jobInDb); + } + } + + Marshal.FreeHGlobal(allocHGlobal); + return anythingSuceeded; + } + else + { + throw new NotImplementedException("Don't know how to blindscan with this tuner."); + } + } + + + private bool BlScan2Wrap(int freq_start, int freq_stop, int pol, int lof1, int lof2, int lofSw, nint pSearchResult, ref int pTpNum, BlScanCallback lpFunc) + { + config.Ui.OnBlindscanBeforeBLScan(freq_start, freq_start, freq_stop); + + bool result = config.StreamReader.BLScan2(freq_start, freq_stop, pol, lof1, lof2, lofSw, pSearchResult, ref pTpNum, lpFunc); + + config.Ui.OnBlindscanAfterBLScan(); + + return result; + } + + private bool SendDiseqcCommand(bool highBand, bool horizontal) + { + DiSEqC_Opcode myOpcode = DiSEqC_Opcode.DISEQC_HIGH_NIBBLE; + if (highBand) + myOpcode |= DiSEqC_Opcode.DISEQC_HIGH_BAND; + else + myOpcode |= DiSEqC_Opcode.DISEQC_LOW_BAND; + + if (horizontal) + myOpcode |= DiSEqC_Opcode.DISEQC_HORIZONTAL; + else + myOpcode |= DiSEqC_Opcode.DISEQC_VERTICAL; + + int parameter = config.DiseqcIndex; + switch (parameter) + { + case 1: + myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_A; + myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_A; + break; + case 2: + myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_A; + myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_B; + break; + case 3: + myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_B; + myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_A; + break; + case 4: + myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_B; + myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_B; + break; + default: + throw new ArgumentOutOfRangeException("DiSEqC Switch Position"); + } + + logger.Log(PluginLogLevel.Info, string.Format("Send DiSEqC Command {0:X2}", (byte)myOpcode), 8); + + DateTime started = DateTime.Now; + bool result = config.StreamReader.SendDiSEqC(2, myOpcode); + TimeSpan timeTaken = DateTime.Now - started; + logger.Log(PluginLogLevel.Debug, string.Format("DiSEqC Comannd sent in {0:F1} seconds.", timeTaken.TotalSeconds)); + if (timeTaken.TotalSeconds > 10) + { + logger.Log(PluginLogLevel.Warn, string.Format("Something went wrong while performing the DiSEqC operation, trying again..."), 8); + Thread.Sleep(1000); + return SendDiseqcCommand(highBand, horizontal); + } + + return result; + } + + private void SearchResult1Callback(SearchResult searchResult, int polarityIndex) + { + BlindscanSearchResult blindscanSearchResult = new BlindscanSearchResult(); + blindscanSearchResult.SearchResult = searchResult; + blindscanSearchResult.Standard = (STD_TYPE)searchResult.StdType; + logger.Log(PluginLogLevel.Info, string.Format("Found frequency: {0}, {1}", searchResult.Freq / 1000, searchResult.Pol == 0 ? "H" : "V")); + lock (foundFrequencies) + { + foundFrequencies.Add(blindscanSearchResult); + } + config.DataStorage.InsertSearchResult(jobInDb, true, searchResult, polarityIndex, new SearchResult2()); + config.Ui.OnBlindscanSearchResult1Callback(blindscanSearchResult, polarityIndex, config.LnbType.MinimumFrequency, config.LnbType.MaximumFrequency); + } + + + public void RunScrape() + { + int lof1 = config.LnbType.Lof1 * 1000; + int lof2 = config.LnbType.Lof2 * 1000; + int lofSw = config.LnbType.LofSw * 1000; + + + foreach (BlindscanSearchResult blindscanResult in foundFrequencies) + { + DateTime now = DateTime.Now; + + blindscanResult.State = BlindscanResultState.Tuning; + config.DataStorage.UpdateTransponderState(jobInDb, blindscanResult.IsSatellite(), blindscanResult.SearchResult, blindscanResult.State, blindscanResult.SearchResult2); + config.Ui.OnBlindscanBeforeSetChannel(blindscanResult, config.LnbType); + bool channel = config.StreamReader.SetChannel(blindscanResult.SearchResult.Freq, blindscanResult.SearchResult.SR, blindscanResult.SearchResult.Pol, blindscanResult.SearchResult.FEC, lof1, lof2, lofSw); + if (!channel) + { + blindscanResult.State = BlindscanResultState.TuningFailed; + config.DataStorage.UpdateTransponderState(jobInDb, blindscanResult.IsSatellite(), blindscanResult.SearchResult, blindscanResult.State, blindscanResult.SearchResult2); + continue; + } + + RunSkyscraper(blindscanResult); + config.Ui.OnBlindscanScrapeTransponderComplete(blindscanResult); + } + + config.Ui.OnScrapeBandComplete(); + } + + + + private RfSpectrumData GatherRfSpectrum() + { + Caps caps = config.TunerMetadata.Caps; + 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; + } + + config.Ui.OnBlindscanBeginRfSpectrum(); + + int lof1 = config.LnbType.Lof1 * 1000; + int lof2 = config.LnbType.Lof2 * 1000; + int lofSw = config.LnbType.LofSw * 1000; + int startFreq = config.LnbType.MinimumFrequency * 1000; + int endFreq = config.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; + config.StreamReader.SendDiSEqC(2, diseqcCmd); + RfSpectrumDataBlock block = spectrumData.CreateBlock(startFreq, endFreq, STEP, polarization); + for (int i = startFreq; i <= endFreq; i += STEP) + { + double rf = double.NaN; + config.StreamReader.RFScan(i, diseqcCmd.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL) ? 0 : 1, lof1, lof2, lofSw, out rf); + logger.Log(PluginLogLevel.Debug,"{0} {1}, {2}", i, polarization.ToString().Substring(0, 1), rf); + block.Push(i, rf); + config.Ui.OnBlindscanRfSpectrumEnqueueSample(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); + } + + config.Ui.OnBlindscanEndRfSpectrum(); + + return spectrumData; + } + + private RfSpectrumData GatherRfSpectrumCable() + { + throw new NotImplementedException(); + } + + private IEnumerable GetIqGraphDiseqcOpcodes() + { + DiSEqC_Opcode baseDiseqc = DiSEqC_Opcode.DISEQC_HIGH_NIBBLE; + + int parameter = config.DiseqcIndex; + 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 (config.DoHorizontalLow || config.DoHorizontalHigh) + yield return baseDiseqc | DiSEqC_Opcode.DISEQC_HORIZONTAL | DiSEqC_Opcode.DISEQC_LOW_BAND; + if (config.DoVerticalLow || config.DoVerticalHigh) + yield return baseDiseqc | DiSEqC_Opcode.DISEQC_VERTICAL | DiSEqC_Opcode.DISEQC_LOW_BAND; + yield break; + } + private IqChartData GatherIqGraph() + { + Caps caps = config.TunerMetadata.Caps; + 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(); + config.Ui.OnBlindscanBeginIqSpectrum(result); + + + sbyte[] buffer = new sbyte[400]; + DateTime started = DateTime.Now; + while (!result.IsComplete) + { + bool iqScan = config.StreamReader.IQScan(0, buffer, (uint)(buffer.Length / 2)); + if (!iqScan) + { + result = null; + logger.Log(PluginLogLevel.Error, "IQScan failed"); + break; + } + 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); + + config.Ui.OnBlindscanEndIq(); + + return result; + } + private IqChartData GatherIQGraphCable() + { + throw new NotImplementedException(); + } + + private void RunSkyscraper(BlindscanSearchResult result) + { + int misCounter = 1; + bool misMode = false; + bool cableTvMode = false; + Caps caps = config.TunerMetadata.Caps; + SearchResult satelliteSr = new SearchResult(); + SearchResult2 cableSr = new SearchResult2(); + + if (caps.HasFlag(Caps.SR_SIGINFO)) + { + logger.Log(PluginLogLevel.Info, string.Format("Trying to BLScanEx..."), 8); + if (!config.StreamReader.BLScanEx(result.SearchResult.Freq, 5000, result.SearchResult.Pol, + config.LnbType.Lof1 * 1000, config.LnbType.Lof2 * 1000, + config.LnbType.LofSw * 1000, 1000000, (STD_TYPE)result.SearchResult.StdType, + ref satelliteSr)) + { + //No blindscan? No problem! Try anyway! + satelliteSr = result.SearchResult; + satelliteSr.Lock = false; + result.State = BlindscanResultState.BlScanFailure; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + } + + if (!satelliteSr.Lock) + { + logger.Log(PluginLogLevel.Info, string.Format("Trying to SetChannel..."), 8); + bool channel = config.StreamReader.SetChannel(result.SearchResult.Freq, result.SearchResult.SR, result.SearchResult.Freq, result.SearchResult.FEC, config.LnbType.Lof1 * 1000, config.LnbType.Lof2 * 1000, config.LnbType.LofSw * 1000); + if (!channel) + { + result.State = BlindscanResultState.TuningFailed; + config.Ui.OnBlindscanLockFail(satelliteSr, result.State); + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + return; + } + else + { + logger.Log(PluginLogLevel.Info, string.Format("Trying to get SignalInfo..."), 8); + bool signalInfo = config.StreamReader.SignalInfo(ref satelliteSr); + if (!signalInfo) + { + result.State = BlindscanResultState.TuningFailed; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(satelliteSr, result.State); + return; + } + + if (!satelliteSr.Lock) + { + result.State = BlindscanResultState.NoLock; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(satelliteSr, result.State); + return; + } + } + } + + if (caps.HasFlag(Caps.SR_MISSEL)) + { + if (satelliteSr.MIS > 16) + satelliteSr.MIS = 1; + + if (satelliteSr.MIS == 0) + satelliteSr.MIS = 1; + + if (satelliteSr.MIS != 1) + misMode = true; + + misCounter = satelliteSr.MIS; + } + } + else if (caps.HasFlag(Caps.SR_SIGINFO2)) + { + logger.Log(PluginLogLevel.Info, string.Format("Trying to SetChannel2..."), 8); + bool channel2 = config.StreamReader.SetChannel2((uint)result.SearchResult2.Freq, (uint)result.SearchResult2.BW); + if (!channel2) + { + result.State = BlindscanResultState.TuningFailed; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(result.SearchResult, result.State); + return; + } + + logger.Log(PluginLogLevel.Info, string.Format("Trying to get SignalInfo2..."), 8); + bool signalInfo2 = config.StreamReader.SignalInfo2(ref cableSr); + if (!signalInfo2) + { + result.State = BlindscanResultState.TuningFailed; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(result.SearchResult, result.State); + return; + } + + if (!cableSr.Lock) + { + result.State = BlindscanResultState.NoLock; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(result.SearchResult, result.State); + return; + } + } + else + { + throw new NotImplementedException("Couldn't figure out what signal info to use."); + } + + if (config.DoCollectIqGraphs) + { + result.State = BlindscanResultState.IqCollecting; + IqChartData plot = GatherIqGraph(); + if (plot != null) + { + result.State = BlindscanResultState.IqSaving; + config.ObjectStorage.StoreIqGraph(jobInDb.JobGuid, result.GetFrequency(), result.GetPolarity(config.LnbType.LofSw), plot); + } + } + + for (int mis = 0; mis < misCounter; mis++) + { + if (misMode) + { + logger.Log(PluginLogLevel.Info, string.Format("Selecting MIS IS {0}", satelliteSr.IS[mis]), 8); + bool misSel = config.StreamReader.MISSel(misMode, satelliteSr.IS[mis], 0xff); + if (!misSel) + { + result.State = BlindscanResultState.MisFailure; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(result.SearchResult, result.State); + return; + } + } + + //Start Filter + TsRecorder tsRecorder = null; + if (config.DoRecordTs) + { + tsRecorder = new TsRecorder(); + tsRecorder.Recording = true; + string outputDirName = config.Ini.ReadValue("recording", "output_dir", "recording_output"); + tsRecorder.RecordingOutputDirectory = new DirectoryInfo(outputDirName); + tsRecorder.RecordingOutputDirectory.EnsureExists(); + if (tsRecorder.PrepareRecording()) + { + DateTime now = DateTime.Now; + string recordingFilename = string.Format( + "skyscraper_{0:D4}{1:D2}{2:D2}_{3:D2}{4:D2}_{8:D4}{9}_{5}_{6}_{7}.ts", + now.Year, now.Month, now.Day, now.Hour, now.Minute, result.GetFrequency() / 1000, + result.GetPolarity(config.LnbType.LofSw), result.GetSymbolRate() / 1000, + (int)(config.SatellitePosition.angle * 10), + config.SatellitePosition.cardinalDirection == 0 ? "E" : "W"); + tsRecorder.SetNextFilename(recordingFilename); + tsRecorder.CreateBufferedStream(); + } + } + + nint filterReference = nint.MaxValue; + logger.Log(PluginLogLevel.Info, string.Format("Set-Up filter..."), 8); + packetsQueue = new Queue(); + + bool filter = config.StreamReader.SetFilter(8192, DvbCallback, 0x02, 2, ref filterReference); + if (!filter) + { + result.State = BlindscanResultState.FilterFailure; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanLockFail(result.SearchResult, result.State); + return; + } + logger.Log(PluginLogLevel.Debug, string.Format("Filter set-up complete!"), 8); + + //Use the Filter + result.State = BlindscanResultState.Scraping; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanFilterSetUp(); + + SkipFilter skipper = new SkipFilter(SkipFilter.CRAZYSCAN_BUFFER * 8); + skyscraperContext = SkyscraperContextFactory.CreateSkyscraper(config.DataStorage, config.ObjectStorage); + skyscraperContext.TcpProxyEnabled = true; + skyscraperContext.UiJunction = config.Ui; + IPacketFilter[] packetFilters = new IPacketFilter[0]; + if (tsRecorder != null) + packetFilters = new IPacketFilter[] { tsRecorder, skipper }; + skyscraperContext.InitalizeFilterChain(packetFilters); + + + byte[] singlePacketBuffer = new byte[188]; + packetsReceivedInTotal = 0; + startedAt = DateTime.Now; + + //The actual scraping happens in this loop + while (!StopConditionMet()) + { + if (!HasPackets()) + { + Thread.Sleep(100); + continue; + } + + byte[] packetBuffer = null; + lock (packetsQueue) + { + packetBuffer = packetsQueue.Dequeue(); + } + + for (int i = 0; i < packetBuffer.Length; i += 188) + { + Array.Copy(packetBuffer, i, singlePacketBuffer, 0, 188); + skyscraperContext.IngestSinglePacket(singlePacketBuffer); + } + } + + config.Ui.OnBlindscanScrapeStopCondition(); + //Stop Filter + logger.Log(PluginLogLevel.Debug, string.Format("Deleting Filter..."), 8); + bool stopped = config.StreamReader.DelFilter(filterReference); + if (!stopped) + { + result.State = BlindscanResultState.DelFilterFailed; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + return; + } + logger.Log(PluginLogLevel.Debug, string.Format("Deleted filter!"), 8); + DrainPackets(); + skyscraperContext.Dispose(); + + if (tsRecorder != null) + tsRecorder.Dispose(); + + result.State = BlindscanResultState.DataSaving; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + + foreach (HumanReadableService humanReadableService in config.Ui.GetServices()) + { + config.DataStorage.InsertTransponderService(jobInDb, result.IsSatellite(), result.SearchResult, result.SearchResult2, humanReadableService); + } + + result.State = BlindscanResultState.Done; + config.DataStorage.UpdateTransponderState(jobInDb, result.IsSatellite(), result.SearchResult, result.State, result.SearchResult2); + config.Ui.OnBlindscanAfterPacketDrain(); + + } + } + + private Queue packetsQueue; + private void DvbCallback(nint data, int length) + { + if (length % 188 == 0) + { + try + { + byte[] buffer = new byte[length]; + Marshal.Copy(data, buffer, 0, length); + + lock (packetsQueue) + { + packetsQueue.Enqueue(buffer); + } + + packetsReceivedInTotal += (uint)(buffer.Length / 188); + config.Ui.OnBlindscanPacketOk(buffer.Length / 188, packetsQueue.Count); + } + catch (OutOfMemoryException e) + { + config.Ui.OnBlindscanPacketError(2, length); + } + } + else + { + logger.Log(PluginLogLevel.Warn, string.Format("odd packet size!"), 8); + config.Ui.OnBlindscanPacketError(1, length); + } + } + + private ISkyscraperContext skyscraperContext; + private ulong packetsReceivedInTotal; + private DateTime startedAt; + private bool StopConditionMet() + { + if (startedAt == DateTime.MinValue) + startedAt = DateTime.Now; + + if (config.Ui.IsZapNowRequested()) + { + return true; + } + + if (!config.Ui.MayAutoZap()) + return false; + + if (packetsReceivedInTotal == 0 && (DateTime.Now - startedAt).TotalSeconds > 5) + return true; + + if (skyscraperContext.GetIpCommunicationParties() > 1000) + return true; + + if (!skyscraperContext.EnableTimeout) + { + skyscraperContext.TimeoutSeconds = 10; + skyscraperContext.EnableTimeout = true; + } + + if (packetsReceivedInTotal > 0 && skyscraperContext.IsAbortConditionMet()) + return true; + + return false; + } + + + private bool HasPackets() + { + lock (packetsQueue) + { + return packetsQueue.Count > 0; + } + } + + private void DrainPackets() + { + if (packetsQueue.Count == 0) + return; + + logger.Log(PluginLogLevel.Warn, string.Format("{0} packets left after switching off the filter.", packetsQueue.Count), 8); + + DateTime startedAt = DateTime.Now; + byte[] singlePacketBuffer = new byte[188]; + byte[] packetBuffer = null; + DateTime drainTickerPrevious = DateTime.Now, drainTickerNow = DateTime.Now; + while (packetsQueue.Count > 0) + { + packetBuffer = packetsQueue.Dequeue(); + if (packetBuffer == null) + continue; + for (int i = 0; i < packetBuffer.Length; i += 188) + { + Array.Copy(packetBuffer, i, singlePacketBuffer, 0, 188); + skyscraperContext.IngestSinglePacket(singlePacketBuffer); + } + + drainTickerPrevious = drainTickerNow; + drainTickerNow = DateTime.Now; + if (drainTickerNow.Second != drainTickerPrevious.Second) + { + logger.Log(PluginLogLevel.Warn, string.Format("{0} packets left ({1}).", packetsQueue.Count, drainTickerNow.ToLongTimeString()), 8); + } + } + + logger.Log(PluginLogLevel.Warn, string.Format("Packets drained in {0} seconds.", (DateTime.Now - startedAt).TotalSeconds), 8); + } + } +} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanJobConfiguration.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanJobConfiguration.cs new file mode 100644 index 0000000..7c2af3e --- /dev/null +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanJobConfiguration.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Skyscraper; +using skyscraper5.Skyscraper.Equipment; +using skyscraper5.Skyscraper.Gps; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.Scraper; +using skyscraper8.Skyscraper.Scraper.Storage; + +namespace skyscraper8.Skyscraper.FrequencyListGenerator +{ + public class BlindscanJobConfiguration + { + public IStreamReader StreamReader { get; set; } + public TunerMetadata TunerMetadata { get; set; } + public int DiseqcIndex { get; set; } + public IGpsReceiver Gps { get; set; } + public SatellitePosition SatellitePosition { get; set; } + + public bool DoHorizontalHigh { get; set; } + public bool DoHorizontalLow { get; set; } + public bool DoVerticalHigh { get; set; } + public bool DoVerticalLow { get; set; } + + public DataStorage DataStorage { get; set; } + public ObjectStorage ObjectStorage { get; set; } + public ISkyscraperUiJunction Ui { get; set; } + public bool DoCollectRfSpectrum { get; set; } + public LnbType LnbType { get; set; } + public bool DoCollectIqGraphs { get; set; } + public bool DoRecordTs { get; set; } + public Ini Ini { get; set; } + } +} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs new file mode 100644 index 0000000..5fcaf46 --- /dev/null +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; +using skyscraper5.src.Skyscraper.FrequencyListGenerator; + +namespace skyscraper8.Skyscraper.FrequencyListGenerator +{ + public class BlindscanSearchResult + { + public SearchResult SearchResult; + public STD_TYPE Standard { get; set; } + public BlindscanResultState State { get; set; } + public SearchResult2 SearchResult2; + + /// + /// If true, the data is in SearchResult. + /// If false, the data is in SearchResult2. + /// + public bool IsSatellite() + { + switch (Standard) + { + case STD_TYPE.STD_DVBS2: return true; + case STD_TYPE.STD_DVBS: return true; + case STD_TYPE.STD_DVBC: return false; + case STD_TYPE.STD_DVBC2: return false; + case STD_TYPE.STD_DVBT: return false; + case STD_TYPE.STD_DVBT2: return false; + default: throw new NotImplementedException(Standard.ToString()); + } + } + + public long GetFrequency() + { + if (IsSatellite()) + return SearchResult.Freq; + else + return SearchResult2.Freq; + } + + public char GetPolarity(int lnbTypeLofSw) + { + if (IsSatellite()) + { + if (lnbTypeLofSw == 0 && SearchResult.Pol == 0) + return 'L'; + else if (lnbTypeLofSw == 0 && SearchResult.Pol == 1) + return 'R'; + else if (lnbTypeLofSw != 0 && SearchResult.Pol == 0) + return 'H'; + else if (lnbTypeLofSw != 0 && SearchResult.Pol == 1) + return 'V'; + else + throw new NotImplementedException("Couldn't figure out signal polarity."); + } + else + { + return 'T'; + } + } + + public int GetSymbolRate() + { + if (IsSatellite()) + return SearchResult.SR; + else + return SearchResult2.SR; + } + } +} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReader.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReader.cs new file mode 100644 index 0000000..306713c --- /dev/null +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReader.cs @@ -0,0 +1,306 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; + +namespace skyscraper8.Skyscraper.FrequencyListGenerator +{ + public class CoopBlindscanStreamReader : IStreamReader + { + private readonly IStreamReader _proxiedStreamReader; + private readonly int _blindScanTuner; + private readonly int _setFilterTuner; + + public CoopBlindscanStreamReader(IStreamReader proxiedStreamReader, int blindScanTuner, int setFilterTuner) + { + _proxiedStreamReader = proxiedStreamReader; + _blindScanTuner = blindScanTuner; + _setFilterTuner = setFilterTuner; + } + + public void Dispose() + { + throw new NotImplementedException(); + } + + public bool CheckForDVB() + { + throw new NotImplementedException(); + } + + public bool CheckForDVBEx(DvbEnumCallback func) + { + throw new NotImplementedException(); + } + + public bool CheckForDVBExEx(DvbEnumCallbackEx func) + { + throw new NotImplementedException(); + } + + public bool StartDVB() + { + throw new NotImplementedException(); + } + + public bool StartDvbEx(int index) + { + throw new NotImplementedException(); + } + + public bool StopDVB() + { + throw new NotImplementedException(); + } + + public bool GetTunerType(ref STD_TYPE type) + { + throw new NotImplementedException(); + } + + public bool SendDiSEqC(uint diseqcType, DiSEqC_Opcode data) + { + throw new NotImplementedException(); + } + + public bool SendDiseqCmd(byte[] buffer, int length) + { + throw new NotImplementedException(); + } + + public bool SendDiseqCmdEx(nint pCmd, int length, nint reply, int replyLength) + { + throw new NotImplementedException(); + } + + public bool SetChannel(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw) + { + throw new NotImplementedException(); + } + + public bool SetChannelEx(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw, MOD_TYPE mod) + { + throw new NotImplementedException(); + } + + public bool SetChannelExEx(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw, MOD_TYPE mod, + int inv, int pilot, ROLLOFF_TYPE rolloff) + { + throw new NotImplementedException(); + } + + public bool SetFilter(int pid, StdcallDvbCallback func, int callbackType, int size, ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool SetFilterEx(int pid, StdcallDvbCallbackEx lpFunc, int callbackType, int size, ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool SetBitFilter(int pid, nint filterData, nint filterMask, byte filterLength, StdcallDvbCallback lpFunc, + ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool SetRemoteControl(int irtype, short devAddr, StdcallDvbCallback func, ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool DelFilter(nint filterNum) + { + throw new NotImplementedException(); + } + + public bool GetSignal(ref int pStrength, ref int pQuality) + { + throw new NotImplementedException(); + } + + public bool GetSignalStrength(ref float pStrength, ref float pQuality) + { + throw new NotImplementedException(); + } + + public bool GetSignalEx(ref float pSNR, ref float pBER) + { + throw new NotImplementedException(); + } + + public bool GetSignalExEx(ref bool pPresent, ref bool pLock, ref int pRFLevel, ref float pSNR, ref float pBER) + { + throw new NotImplementedException(); + } + + public bool Statistic(int[] pStat) + { + throw new NotImplementedException(); + } + + public bool GetMAC(byte[] pMac) + { + throw new NotImplementedException(); + } + + public Caps GetCaps() + { + throw new NotImplementedException(); + } + + public bool RFScan(int freq, int pol, int lof1, int lof2, int lofsw, out double pRFLevel) + { + throw new NotImplementedException(); + } + + public bool FFTInit() + { + throw new NotImplementedException(); + } + + public bool FFTScan(int freq, int pol, int lof1, int lof2, int lofsw, uint range, byte mode, byte nb_acc, nint pTab, + nint pBegin, nint pNum) + { + throw new NotImplementedException(); + } + + public bool BLScan(int freq, int freq_range, int pol, int lof1, int lof2, int lofsw, int minsr, + ref SearchResult pSearchResult) + { + throw new NotImplementedException(); + } + + public bool BLScanEx(int freq, int freq_range, int pol, int lof1, int lof2, int lofsw, int minsr, STD_TYPE std, + ref SearchResult pSearchResult) + { + throw new NotImplementedException(); + } + + public bool BLScan2(int freq_start, int freq_stop, int pol, int lof1, int lof2, int lofsw, nint pSearchResult, ref int pTpNum, + BlScanCallback lpFunc) + { + throw new NotImplementedException(); + } + + public bool SignalInfo(ref SearchResult pSearchResult) + { + throw new NotImplementedException(); + } + + public bool IQScan(uint input, sbyte[] pIQ, uint num) + { + throw new NotImplementedException(); + } + + public bool IQScan2(uint point, short[] pIQ, uint num) + { + throw new NotImplementedException(); + } + + public bool IQScan2Range(byte input, ref ushort pMinPoint, ref ushort pMaxPoint) + { + throw new NotImplementedException(); + } + + public bool CIRScanRange(bool bHiRes, ref ushort pMinCnum, ref ushort pMaxCnum, ref int pMinDelayNs, ref int pMaxDelayNs) + { + throw new NotImplementedException(); + } + + public bool CIRScan(bool bHiRes, int[] pPowers, int[] pDelays) + { + throw new NotImplementedException(); + } + + public bool CarRange(ref ushort pMinCnum, ref ushort pMaxCnum) + { + throw new NotImplementedException(); + } + + public bool CarEsNo(ref ushort cnum, ref double pEsNo) + { + throw new NotImplementedException(); + } + + public bool MISSel(bool bEnable, byte misFilter, byte misFilterMask) + { + throw new NotImplementedException(); + } + + public bool PLSSel(byte plsMode, uint code) + { + throw new NotImplementedException(); + } + + public bool PLSGet(byte pMode, ref uint pCode) + { + throw new NotImplementedException(); + } + + public bool ModSel(ref S2Mode ps2Modes, uint num) + { + throw new NotImplementedException(); + } + + public bool ModInv(uint WaitMs, ref S2Mode pS2Modes, ref uint pNum) + { + throw new NotImplementedException(); + } + + public bool SetChannel2(uint freq, uint bandwidth) + { + throw new NotImplementedException(); + } + + public bool SetChannel2Ex(uint freq, uint bandwidth, STD_TYPE std, int stream) + { + throw new NotImplementedException(); + } + + public bool SetChannel2ExEx(uint freq, uint bandwidth, uint symbrate, STD_TYPE std, int stream) + { + throw new NotImplementedException(); + } + + public bool SignalInfo2(ref SearchResult2 si2) + { + throw new NotImplementedException(); + } + + public bool RFScan2(uint freq, STD_TYPE std, ref double pRFLevel) + { + throw new NotImplementedException(); + } + + public bool AirScan(int freq_start, int freq_stop, uint step, uint bandwidth, int std, nint pSearchResult, ref int pTpNum, + AirScanCallback lpFunc) + { + throw new NotImplementedException(); + } + + public bool GetEEPROM(byte[] buffer, int offset, int len) + { + throw new NotImplementedException(); + } + + public bool SetEEPROM(byte[] buffer, int offset, int len) + { + throw new NotImplementedException(); + } + + public Version GetEngineVersion() + { + throw new NotImplementedException(); + } + + public string GetEngineName() + { + throw new NotImplementedException(); + } + } +} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/FrequencyListeGeneratorJunction.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/FrequencyListeGeneratorJunction.cs deleted file mode 100644 index 0fc8c9c..0000000 --- a/skyscraper8/Skyscraper/FrequencyListGenerator/FrequencyListeGeneratorJunction.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using skyscraper5.Docsis; -using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs; -using skyscraper5.Dvb.Descriptors; -using skyscraper5.Dvb.Psi.Model; -using skyscraper5.Mhp.Si.Model; -using skyscraper5.Mpeg2.Descriptors; -using skyscraper5.Mpeg2.Psi.Model; -using skyscraper5.Scte35; -using skyscraper5.Skyscraper.Net; -using skyscraper5.Skyscraper.Scraper; -using skyscraper5.Teletext.Wss; - -namespace skyscraper5.src.Skyscraper.FrequencyListGenerator -{ - internal class FrequencyListGeneratorJunction : ISkyscraperUiJunction - { - public FrequencyListGeneratorJunction() - { - sdtServices = new Dictionary(); - } - - private Dictionary sdtServices; - private Dictionary programMappings; - - public void NotifyEvent(EitEvent eitEvent) - { - } - - public void NotifySdtService(SdtService sdtService) - { - if (!sdtServices.ContainsKey(sdtService.ServiceId)) - sdtServices.Add(sdtService.ServiceId, sdtService); - } - - public void NotifyPatProgram(int pmtPid, ushort programId) - { - - } - - public void NotifyPmtProgram(ProgramMapping result, int pmtPid) - { - if (!programMappings.ContainsKey(result.ProgramNumber)) - programMappings.Add(result.ProgramNumber, result); - } - - public void NotifyNit(NitTransportStream transportStream) - { - - } - - public void NotifyMpeTraffic(IpTrafficInfo iti, int ipv4PacketLength) - { - - } - - public void NotifyAit(AitApplication aitApplication) - { - - } - - public void DsmCcModuleAdd(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion) - { - - } - - public void DsmCcModuleProgress(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion, - double moduleInfoDownloadProgress) - { - - } - - public void DsmCcModuleComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion) - { - - } - - public void NotifyWss(ushort programNumber, WssDataBlock wssDataBlock) - { - - } - - public void NotifyStreamTypeDetection(string contestantTag, int pid) - { - - } - - public void NotifyBat(BatBouquet batBouquet) - { - - } - - public void NotifyBatTs(ushort batBouquetBouquetId, BatTransportStream child) - { - - } - - public void DsmCcVfs(VfsFile vfsFile) - { - - } - - public void NotifyTot(DateTime utcTime, LocalTimeOffsetDescriptor ltod) - { - - } - - public void NotifyTdt(DateTime utcTime) - { - - } - - public void NotifyCat(CaDescriptor caDescriptor) - { - - } - - public void NotifyScte35(ushort programNumber, SpliceInsert spliceInsert) - { - - } - - public void NotifyScte35(ushort programNumber, TimeSignal spliceInsert) - { - - } - - public void SetMemorySaverMode(bool saveMemory) - { - - } - - public void NotifyDocsisCarrier(DocsisEnvironment docsisEnvironment) - { - - } - - public void NotifyDocsisFrequency(uint? frequency, bool isUpstream, object mmm) - { - - } - - public void SetGseMode() - { - - } - - public void ShowFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, - int mappingStreamElementaryPid, byte[] imageData) - { - - } - - public void NotifyBlockstreamCarrier() - { - - } - - public IEnumerable GetServices() - { - foreach (var (pmtPid, pmt) in programMappings) - { - ushort serviceId = pmt.ProgramNumber; - if (!sdtServices.ContainsKey(serviceId)) - continue; - SdtService service = sdtServices[serviceId]; - string providerName = service.ServiceProviderName; - string serviceName = service.ServiceName; - ushort? caId = GetCaId(pmt, service); - ServiceDescriptor.ServiceTypeCoding serviceType = service.ServiceType.GetValueOrDefault(); - yield return new HumanReadableService(serviceId, providerName, serviceName, caId, serviceType); - } - } - - private ushort? GetCaId(ProgramMapping pmt, SdtService sdt) - { - if (pmt.CaSystemId.HasValue) - { - return pmt.CaSystemId.Value; - } - - foreach (ProgramMappingStream stream in pmt.Streams) - { - if (stream.CaSystemId.HasValue) - return stream.CaSystemId.Value; - } - - if (sdt.CaIdentifiers != null) - { - if (sdt.CaIdentifiers.Length > 0) - { - return sdt.CaIdentifiers[0]; - } - } - - return null; - } - } -} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/TaskQueue.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/TaskQueue.cs new file mode 100644 index 0000000..f53d43b --- /dev/null +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/TaskQueue.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Skyscraper.FrequencyListGenerator +{ + public class TaskQueue + { + public TaskQueue() + { + tasks = new Queue(); + } + + private Queue tasks; + + public void EnqueueTask(Action a) + { + lock (this) + { + tasks.Enqueue(a); + } + } + + public void ProcessTasks() + { + lock (this) + { + while (tasks.Count > 0) + { + Action dequeue = tasks.Dequeue(); + dequeue.Invoke(); + } + } + } + } +} diff --git a/skyscraper8/Skyscraper/IO/StreamReaderScanController.cs b/skyscraper8/Skyscraper/IO/StreamReaderScanController.cs deleted file mode 100644 index fceeadc..0000000 --- a/skyscraper8/Skyscraper/IO/StreamReaderScanController.cs +++ /dev/null @@ -1,469 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.NetworkInformation; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using skyscraper5.Skyscraper.IO.CrazycatStreamReader; -using skyscraper5.Skyscraper.Scraper; -using skyscraper5.Skyscraper.Scraper.Storage.Filesystem; -using skyscraper8.Skyscraper.Scraper.Storage; - -namespace skyscraper5.Skyscraper.IO -{ - internal class StreamReaderScanController : IDisposable - { - private readonly IStreamReader streamReader; - - public static List GetTuners(IStreamReader streamReader) - { - List result = new List(); - bool checkForDvbExEx = streamReader.CheckForDVBExEx((index, name, type) => - { - result.Add(new StreamReaderTuner(index, name, type)); - }); - if (!checkForDvbExEx) - { - return new List(); - } - return result; - } - - public List GetTunersByStandard(STD_TYPE stdType) - { - return GetTuners(streamReader).Where(x => x.Type == stdType).ToList(); - } - - public StreamReaderTuner GetTunerByStandard(STD_TYPE stdType) - { - List streamReaderTuners = GetTunersByStandard(stdType); - if (streamReaderTuners.Count == 0) - return null; - else - return streamReaderTuners[0]; - } - - private bool busy; - private PhysicalAddress physicalAddress; - private STD_TYPE stdType; - private Caps caps; - private StreamReaderTuner tunerMetadata; - private static int instances = 0; - private bool disposed; - - public StreamReaderScanController(IStreamReader streamReader, StreamReaderTuner tuner) - { - this.streamReader = streamReader; - - if (instances > 0) - { - throw new StreamReaderException("Only one StreamReader may be active, dispose the other one first."); - } - - if (tuner != null) - { - tunerMetadata = tuner; - if (!streamReader.StartDvbEx(tuner.Index)) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.StartDvbEx))); - } - } - else - { - if (!streamReader.StartDVB()) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.StartDVB))); - } - } - - caps = streamReader.GetCaps(); - if (!streamReader.GetTunerType(ref stdType)) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.GetTunerType))); - } - - if (caps.HasFlag(Caps.SR_GETMAC)) - { - byte[] macBuffer = new byte[6]; - if (streamReader.GetMAC(macBuffer)) - { - physicalAddress = new PhysicalAddress(macBuffer); - } - } - - string[] strings = Enum.GetNames(typeof(StreamReaderParameter)); - parameters = new uint[strings.Length]; - paramsSet = new bool[strings.Length]; - - if (stdType == STD_TYPE.STD_DVBC) - SetDefaultDvbCParameters(); - } - - private bool[] paramsSet; - private uint[] parameters; - public enum StreamReaderParameter : int - { - ScanStartFreq, - ScanEndFreq, - ScanStep, - ScanBandwidth, - ScanStdType, - ScanLof1, - ScanLofSwitch, - ScanLof2, - ScanDiseqcType, - DiseqcSwitchPosition - } - - public void SetParameter(StreamReaderParameter key, uint value) - { - parameters[(int)key] = value; - paramsSet[(int)key] = true; - } - - public uint GetParameter(StreamReaderParameter key) - { - if (!paramsSet[(int)key]) - { - throw new StreamReaderException(string.Format("{0} was not set.", key.ToString())); - } - return parameters[(int)key]; - } - - public void SetDefaultDvbCParameters() - { - SetParameter(StreamReaderParameter.ScanStartFreq, 48000); - SetParameter(StreamReaderParameter.ScanEndFreq, 1000000); - SetParameter(StreamReaderParameter.ScanStep, 3000); - SetParameter(StreamReaderParameter.ScanBandwidth, 8000); - SetParameter(StreamReaderParameter.ScanStdType, (uint)STD_TYPE.STD_DVBC); - } - - public void SetDefaultKuBandParameters() - { - SetParameter(StreamReaderParameter.ScanLof1, 9750000); - SetParameter(StreamReaderParameter.ScanLofSwitch, 11700000); - SetParameter(StreamReaderParameter.ScanLof2, 10600000); - SetParameter(StreamReaderParameter.ScanStartFreq, 10700000); - SetParameter(StreamReaderParameter.ScanEndFreq, 12750000); - } - - public void Dispose() - { - if (busy) - { - throw new StreamReaderException("TunerMetadata is busy."); - } - - streamReader.StopDVB(); - instances--; - disposed = true; - } - - public class StreamReaderTuner - { - public int Index { get; } - public string Name { get; } - public STD_TYPE Type { get; } - - public StreamReaderTuner(int index, string name, STD_TYPE type) - { - Index = index; - Name = name; - Type = type; - } - } - - public bool Tune(BlindScanResult blindScanResult) - { - switch (stdType) - { - case STD_TYPE.STD_DVBC: - Console.WriteLine("Tuning to {0} Mhz", blindScanResult.SearchResult2.Freq / 1000.0); - bool channel2 = streamReader.SetChannel2((uint)blindScanResult.SearchResult2.Freq, (uint)blindScanResult.SearchResult2.BW); - if (!channel2) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.SetChannel2))); - } - - SearchResult2 sr2 = default; - bool signalInfo2 = streamReader.SignalInfo2(ref sr2); - if (!signalInfo2) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.SetChannel2))); - } - - return sr2.Lock; - case STD_TYPE.STD_DVBS: - Console.WriteLine("Tuning to {0} Mhz", blindScanResult.SearchResult1.Freq / 1000.0); - SearchResult searchResult1 = blindScanResult.SearchResult1; - uint lof1 = GetParameter(StreamReaderParameter.ScanLof1); - uint lof2 = GetParameter(StreamReaderParameter.ScanLof2); - uint lofSw = GetParameter(StreamReaderParameter.ScanLofSwitch); - if (!streamReader.SetChannel(searchResult1.Freq, searchResult1.SR, searchResult1.Pol, searchResult1.FEC, (int)lof1, (int)lof2, (int)lofSw)) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.SetChannel))); - } - - SearchResult cmp = default; - bool signalInfo = streamReader.SignalInfo(ref cmp); - if (!signalInfo) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.SignalInfo))); - } - return cmp.Lock; - default: - throw new NotImplementedException(); - } - } - - private void SearchResult2Callback(BlindScanResults results, SearchResult2 sr2Ptr) - { - BlindScanResult bbsr = new BlindScanResult(); - bbsr.System = stdType; - bbsr.SearchResult2 = sr2Ptr; - results.Transponders.Add(bbsr); - - Console.WriteLine("{0} Mhz, {1} ksyms, {2}", sr2Ptr.Freq / 1000.0, sr2Ptr.SR / 1000, (MOD_TYPE)sr2Ptr.ModType); - } - - private void SearchResult2Callback(BlindScanResults results, SearchResult sr2Ptr) - { - BlindScanResult bbsr = new BlindScanResult(); - bbsr.SearchResult1 = sr2Ptr; - bbsr.System = stdType; - results.Transponders.Add(bbsr); - - Console.WriteLine("{0} Mhz, {1} ksyms, {2}", sr2Ptr.Freq / 1000.0, sr2Ptr.SR / 1000, (MOD_TYPE)sr2Ptr.ModType); - } - - private void SendDiseqcCommand(int diseqcType, bool highBand, bool horizontal) - { - DiSEqC_Opcode myOpcode = DiSEqC_Opcode.DISEQC_HIGH_NIBBLE; - if (highBand) - myOpcode |= DiSEqC_Opcode.DISEQC_HIGH_BAND; - else - myOpcode |= DiSEqC_Opcode.DISEQC_LOW_BAND; - - if (horizontal) - myOpcode |= DiSEqC_Opcode.DISEQC_HORIZONTAL; - else - myOpcode |= DiSEqC_Opcode.DISEQC_VERTICAL; - - if (diseqcType == 2) - { - uint parameter = GetParameter(StreamReaderParameter.DiseqcSwitchPosition); - switch (parameter) - { - case 1: - myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_A; - myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_A; - break; - case 2: - myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_A; - myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_B; - break; - case 3: - myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_B; - myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_A; - break; - case 4: - myOpcode |= DiSEqC_Opcode.DISEQC_OPTION_B; - myOpcode |= DiSEqC_Opcode.DISEQC_POSITION_B; - break; - default: - throw new ArgumentOutOfRangeException(nameof(StreamReaderParameter.DiseqcSwitchPosition)); - } - } - - bool sendDiSEqC = streamReader.SendDiSEqC((uint)diseqcType, myOpcode); - if (!sendDiSEqC) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.SendDiSEqC))); - } - } - - public void RunBlindscan() - { - if (busy) - throw new StreamReaderException("TunerMetadata is busy"); - - int startFreq = (int)GetParameter(StreamReaderParameter.ScanStartFreq); - int endFreq = (int)GetParameter(StreamReaderParameter.ScanEndFreq); - - BlindScanResults result = new BlindScanResults(); - result.Standard = stdType; - switch (stdType) - { - case STD_TYPE.STD_DVBC: - if (caps.HasFlag(Caps.SR_AIRSCAN)) - { - - uint step = GetParameter(StreamReaderParameter.ScanStep); - uint bandwidth = GetParameter(StreamReaderParameter.ScanBandwidth); - STD_TYPE stdType = (STD_TYPE)GetParameter(StreamReaderParameter.ScanStdType); - SearchResult2 sr2 = default; - int tpNum = default; - IntPtr pSearchResult = Marshal.AllocHGlobal(ushort.MaxValue); - busy = true; - bool airScan = streamReader.AirScan(startFreq, endFreq, step, bandwidth, (int)stdType, pSearchResult, ref tpNum, (ref SearchResult2 searchResult) => SearchResult2Callback(result, searchResult)); - if (airScan) - { - Scrape(result); - } - busy = false; - Marshal.FreeHGlobal(pSearchResult); - if (!airScan) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.GetTunerType))); - } - } - else - { - throw new NotImplementedException("Don't know how to blindscan with this tuner."); - } - - break; - case STD_TYPE.STD_DVBS: - if (caps.HasFlag(Caps.SR_BLSCAN2)) - { - SearchResult sr1 = default; - int tpNum = default; - - int lof1 = (int)GetParameter(StreamReaderParameter.ScanLof1); - int lof2 = (int)GetParameter(StreamReaderParameter.ScanLof2); - int lofSw = (int)GetParameter(StreamReaderParameter.ScanLofSwitch); - int diseqc = (int)GetParameter(StreamReaderParameter.ScanDiseqcType); - - IntPtr allocHGlobal = Marshal.AllocHGlobal(ushort.MaxValue); - - if (lofSw != 0) - { - busy = true; - - result.Transponders.Clear(); - SendDiseqcCommand(diseqc, false, true); - bool hLower = streamReader.BLScan2(startFreq, lofSw, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult searchResult) => SearchResult2Callback(result, searchResult)); - if (hLower) - { - Scrape(result); - } - - result.Transponders.Clear(); - SendDiseqcCommand(diseqc, true, true); - bool hUpper = streamReader.BLScan2(lofSw, endFreq, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult searchResult) => SearchResult2Callback(result, searchResult)); - if (hUpper) - { - Scrape(result); - } - - result.Transponders.Clear(); - SendDiseqcCommand(diseqc, false, false); - bool vLower = streamReader.BLScan2(startFreq, lofSw, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult searchResult) => SearchResult2Callback(result, searchResult)); - if (vLower) - { - Scrape(result); - } - - result.Transponders.Clear(); - SendDiseqcCommand(diseqc, true, false); - bool vUpper = streamReader.BLScan2(lofSw, endFreq, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, (ref SearchResult searchResult) => SearchResult2Callback(result, searchResult)); - if (vUpper) - { - Scrape(result); - } - - busy = false; - if (!hLower && !hUpper && !vLower && !vUpper) - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.BLScan2))); - } - else - { - throw new NotImplementedException("non switching lnb"); - } - - Marshal.FreeHGlobal(allocHGlobal); - } - else - { - throw new NotImplementedException("Don't know how to blindscan with this tuner."); - } - break; - default: - throw new NotImplementedException(stdType.ToString()); - } - } - - private StreamReaderScraperController srsc2; - private void Scrape(BlindScanResults blindScanResults) - { - if (srsc2 == null) - { - srsc2 = new StreamReaderScraperController(streamReader); - srsc2.RecordingOutputDirectory = new DirectoryInfo("recordings"); - srsc2.Recording = true; - srsc2.DataStorage = new FilesystemStorage(new DirectoryInfo("srtest_results")); - srsc2.ObjectStorage = (ObjectStorage)srsc2.DataStorage; - } - - foreach (BlindScanResult blindScanResult in blindScanResults.Transponders) - { - if (Tune(blindScanResult)) - { - srsc2.SetNamingHint(blindScanResult); - srsc2.Run(); - } - else - Console.WriteLine("Lock failed."); - } - } - } - - [Serializable] - class StreamReaderException : SkyscraperIOException - { - // - // For guidelines regarding the creation of new exception types, see - // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp - // and - // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp - // - - public StreamReaderException() - { - } - - public StreamReaderException(string message) : base(message) - { - } - - public StreamReaderException(string message, Exception inner) : base(message, inner) - { - } - - protected StreamReaderException( - SerializationInfo info, - StreamingContext context) : base(info, context) - { - } - } - - class BlindScanResults - { - public BlindScanResults() - { - Transponders = new List(); - } - - public List Transponders { get; private set; } - public STD_TYPE Standard { get; set; } - } - - class BlindScanResult - { - public SearchResult2 SearchResult2 { get; set; } - public SearchResult SearchResult1 { get; set; } - public STD_TYPE System { get; set; } - } -} diff --git a/skyscraper8/Skyscraper/IO/StreamReaderScraperController.cs b/skyscraper8/Skyscraper/IO/StreamReaderScraperController.cs deleted file mode 100644 index 5c3a704..0000000 --- a/skyscraper8/Skyscraper/IO/StreamReaderScraperController.cs +++ /dev/null @@ -1,324 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading; -using skyscraper5.Mpeg2; -using skyscraper5.Skyscraper.IO.CrazycatStreamReader; -using skyscraper5.Skyscraper.Scraper; -using skyscraper5.Skyscraper.Scraper.Storage; -using skyscraper8.Skyscraper.Scraper.Storage; - -namespace skyscraper5.Skyscraper.IO -{ - internal class StreamReaderScraperController - { - private readonly IStreamReader streamReader; - - public StreamReaderScraperController(IStreamReader streamReader) - { - this.streamReader = streamReader; - } - - - private const string RECORDING_FILENAME_MASK = "skyscraper_{0}.ts"; - - public DataStorage DataStorage { get; set; } - public ObjectStorage ObjectStorage { get; set; } - - public bool Recording { get; set; } - - public DirectoryInfo RecordingOutputDirectory { get; set; } - - private bool PrepareRecording() - { - if (!Recording) - return false; - - if (RecordingOutputDirectory == null) - return false; - - DirectoryInfo rootDirectory = RecordingOutputDirectory.Root; - DriveInfo driveInfo = new DriveInfo(rootDirectory.FullName); - long driveFreeSpace = driveInfo.TotalFreeSpace; - long driveTotalSize = driveInfo.TotalSize; - long tenPercentOfDriveTotal = driveTotalSize / 10; - if (driveFreeSpace > tenPercentOfDriveTotal) - return true; - - FileInfo[] fileInfos = RecordingOutputDirectory.GetFiles(string.Format(RECORDING_FILENAME_MASK, "*")); - Array.Sort(fileInfos, (x, y) => DateTime.Compare(x.CreationTimeUtc, y.CreationTimeUtc)); - long sizeOfAllKnown = fileInfos.Select(x => x.Length).Sum(); - long driveFreeSpaceAfterDeleting = driveFreeSpace + sizeOfAllKnown; - if (driveFreeSpaceAfterDeleting < tenPercentOfDriveTotal) - return false; - - for (int i = 0; i < fileInfos.Length; i++) - { - fileInfos[i].Delete(); - Console.WriteLine("Deleted for rotation: {0}", fileInfos[i].Name); - fileInfos[i] = null; - driveInfo = new DriveInfo(rootDirectory.FullName); - driveFreeSpace = driveInfo.TotalFreeSpace; - if (driveFreeSpace > tenPercentOfDriveTotal) - return true; - } - driveInfo = new DriveInfo(rootDirectory.FullName); - driveFreeSpace = driveInfo.TotalFreeSpace; - if (driveFreeSpace > tenPercentOfDriveTotal) - return true; - else - return false; - } - - private bool HasLock(bool cableTv) - { - if (cableTv) - { - SearchResult2 sr2 = new SearchResult2(); - if (!streamReader.SignalInfo2(ref sr2)) - return false; - return sr2.Lock; - } - else - { - SearchResult sr = new SearchResult(); - if (!streamReader.SignalInfo(ref sr)) - return false; - return sr.Lock; - } - } - - private ulong packetsReceivedInTotal; - private Queue packetsQueue; - private void DvbCallback(IntPtr data, int length) - { - if (length % 188 == 0) - { - byte[] buffer = new byte[length]; - Marshal.Copy(data, buffer, 0, length); - lock (packetsQueue) - { - packetsQueue.Enqueue(buffer); - } - packetsReceivedInTotal++; - } - else - { - Console.WriteLine("odd packet size!"); - } - } - - private bool HasPackets() - { - lock (packetsQueue) - { - return packetsQueue.Count > 0; - } - } - - private DateTime startedAt; - private bool StopConditionMet() - { - if (startedAt == DateTime.MinValue) - startedAt = DateTime.Now; - - if (packetsReceivedInTotal == 0 && (DateTime.Now - startedAt).TotalSeconds > 5) - return true; - - if (!skyscraperContext.EnableTimeout) - { - skyscraperContext.TimeoutSeconds = 10; - skyscraperContext.EnableTimeout = true; - } - - if (packetsReceivedInTotal > 0 && skyscraperContext.IsAbortConditionMet()) - return true; - - return false; - } - - private void DrainPackets() - { - if (packetsQueue.Count == 0) - return; - - DateTime startedAt = DateTime.Now; - byte[] singlePacketBuffer = new byte[188]; - byte[] packetBuffer = null; - while (packetsQueue.Count > 0) - { - packetBuffer = packetsQueue.Dequeue(); - if (recordingBufferedStream != null) - recordingBufferedStream.Write(packetBuffer, 0, packetBuffer.Length); - for (int i = 0; i < packetBuffer.Length; i += 188) - { - Array.Copy(packetBuffer, i, singlePacketBuffer, 0, 188); - skyscraperContext.IngestSinglePacket(singlePacketBuffer); - - } - } - - } - - private BufferedStream recordingBufferedStream; - private FileStream recordingFileStream; - private SkyscraperContext skyscraperContext; - public void Run() - { - bool cableTvMode = false; - Caps caps = streamReader.GetCaps(); - if (caps.HasFlag(Caps.SR_SIGINFO)) - { - cableTvMode = false; - } - else if (caps.HasFlag(Caps.SR_SIGINFO2)) - { - cableTvMode = true; - } - else - { - throw new NotImplementedException("Couldn't figure out what signal info to use."); - } - - if (!HasLock(cableTvMode)) - { - throw new NotImplementedException("No lock."); - } - - int misCounter = 1; - int misMode = 0; - byte[] s2_is = null; - if (!cableTvMode) - { - SearchResult sr = default; - if (!streamReader.SignalInfo(ref sr)) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.SignalInfo))); - } - - if (!sr.Lock) - return; - - misMode = sr.MIS; - s2_is = sr.IS; - } - - for (int mis = 0; mis < misCounter; mis++) - { - if (misMode != 0) - { - Console.WriteLine("Selecting MIS IS {0}", s2_is[mis]); - bool misSel = streamReader.MISSel(misMode != 0, s2_is[mis], 0xff); - if (!misSel) - { - throw new StreamReaderException(string.Format("{0} failed", nameof(streamReader.MISSel))); - } - } - - //Start Filter - if (PrepareRecording()) - { - string recordingFileName = GenerateRecordingFilename(mis, misMode); - FileInfo recordingFileInfo = new FileInfo(recordingFileName); - recordingFileInfo.Directory.EnsureExists(); - recordingFileStream = recordingFileInfo.OpenWrite(); - recordingBufferedStream = new BufferedStream(recordingFileStream); - } - - IntPtr filterReference = IntPtr.MaxValue; - packetsQueue = new Queue(); - bool filter = streamReader.SetFilter(8192, DvbCallback, 0x02, 2, ref filterReference); - if (!filter) - { - throw new Exception("failed to set filter"); - } - - //Use the Filter - skyscraperContext = new SkyscraperContext(new TsContext(), DataStorage,ObjectStorage); - skyscraperContext.TcpProxyEnabled = true; - byte[] singlePacketBuffer = new byte[188]; - while (!StopConditionMet()) - { - if (!HasPackets()) - { - Thread.Sleep(100); - continue; - } - - byte[] packetBuffer = null; - lock (packetsQueue) - { - packetBuffer = packetsQueue.Dequeue(); - } - - if (recordingBufferedStream != null) - recordingBufferedStream.Write(packetBuffer, 0, packetBuffer.Length); - - - for (int i = 0; i < packetBuffer.Length; i += 188) - { - Array.Copy(packetBuffer, i, singlePacketBuffer, 0, 188); - skyscraperContext.IngestSinglePacket(singlePacketBuffer); - } - } - - //Stop Filter - bool stopped = streamReader.DelFilter(filterReference); - if (!stopped) - { - throw new Exception("failed to stop filter"); - } - - DrainPackets(); - if (recordingBufferedStream != null) - { - recordingBufferedStream.Flush(); - recordingBufferedStream.Close(); - recordingBufferedStream.Dispose(); - recordingBufferedStream = null; - recordingFileStream.Close(); - recordingFileStream.Dispose(); - recordingFileStream = null; - } - } - } - - private string GenerateRecordingFilename(int mis, int misMode) - { - DateTime dt = DateTime.Now; - string dateFmt = string.Format("{0:D4}{1:D2}{2:D2}_{3:D2}{4:D2}", dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute); - if (namingHint != null) - { - switch (namingHint.System) - { - case STD_TYPE.STD_DVBS: - string resultS = null; - if (misMode == 0) - { - resultS = string.Format("{0}_{1}_{2}_{3}.ts", dateFmt, namingHint.SearchResult1.Freq / 1000, namingHint.SearchResult1.Pol == 0 ? "H" : "V", namingHint.SearchResult1.SR / 1000); - } - else - { - resultS = string.Format("{0}_{1}_{2}_{3}_MIS{4}.ts", dateFmt, namingHint.SearchResult1.Freq / 1000, namingHint.SearchResult1.Pol == 0 ? "H" : "V", namingHint.SearchResult1.SR / 1000, mis); - } - - return Path.Combine(RecordingOutputDirectory.FullName, resultS); - default: - throw new NotImplementedException(namingHint.System.ToString()); - } - } - else - { - return Path.Combine(RecordingOutputDirectory.FullName, string.Format(RECORDING_FILENAME_MASK, dateFmt)); - } - } - - private BlindScanResult namingHint; - public void SetNamingHint(BlindScanResult blindScanResult) - { - namingHint = blindScanResult; - } - } -} diff --git a/skyscraper8/Skyscraper/Scraper/ISkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/ISkyscraperContext.cs index ea8bd17..7806822 100644 --- a/skyscraper8/Skyscraper/Scraper/ISkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/ISkyscraperContext.cs @@ -25,5 +25,6 @@ namespace skyscraper5.Skyscraper.Scraper public void InitalizeFilterChain(params IPacketFilter[] args); - } + int GetIpCommunicationParties(); + } } diff --git a/skyscraper8/Skyscraper/Scraper/ISkyscraperUiJunction.cs b/skyscraper8/Skyscraper/Scraper/ISkyscraperUiJunction.cs index b076d3e..12a20b4 100644 --- a/skyscraper8/Skyscraper/Scraper/ISkyscraperUiJunction.cs +++ b/skyscraper8/Skyscraper/Scraper/ISkyscraperUiJunction.cs @@ -12,9 +12,13 @@ using skyscraper5.Mhp.Si.Model; using skyscraper5.Mpeg2.Descriptors; using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Scte35; +using skyscraper5.Skyscraper.Equipment; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper5.Skyscraper.Net; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.Teletext.Wss; +using skyscraper8.Skyscraper.Drawing; +using skyscraper8.Skyscraper.FrequencyListGenerator; namespace skyscraper5.Skyscraper.Scraper { @@ -48,5 +52,143 @@ namespace skyscraper5.Skyscraper.Scraper void NotifyBlockstreamCarrier(); IEnumerable GetServices(); + void OnBlindscanOpenFoundFrquenciesWindow(List foundFrequencies, STD_TYPE tunerMetadataType); + void OnBlindscanJobDone(bool success); + void OnBlindscanErrorMessage(string blindscanningLowHorizontalAreaFailed); + + /// + /// Called after the part of a band (e.g. Horizontal High) has completed blindscanning. + /// Is supposed to move the puppets in the SDL2 based UI to their home position. + /// + void OnBlindscanBandComplete(); + + /// + /// Called before a BLScan operation begins. + /// + /// The minimum frequency to scan + /// The Frequency on which we're starting. + /// The maximum frequency to scan + void OnBlindscanBeforeBLScan(int minimum, int currentProgress, int maximum); + + /// + /// Called before a BLScan operation ends. + /// + void OnBlindscanAfterBLScan(); + + /// + /// Called when a transponder is found during a BLScan2. + /// + /// + /// + /// + /// + void OnBlindscanSearchResult1Callback(BlindscanSearchResult searchResult, int polarityIndex, int lnbTypeMinimumFrequency, int lnbTypeMaximumFrequency); + + /// + /// Called before a SetChannel operation is performed. + /// + /// + void OnBlindscanBeforeSetChannel(BlindscanSearchResult blindscanResult, LnbType lnbType); + + /// + /// Called after a band (meaning e.g. Horizontal High) has been scraped. + /// In the SDL2 version, this is supposed to move the puppets back to their home position. + /// + void OnScrapeBandComplete(); + + /// + /// Called after a single transponder has been scraped. + /// In the SDL2 version, this is supposed to hide the pressure plate representing the transponder. + /// + /// + void OnBlindscanScrapeTransponderComplete(BlindscanSearchResult blindscanResult); + + /// + /// Called when beginning to gather the RF Spectrum. + /// In the SDL2 version, this is supposed to create the ScottPlot window. + /// + void OnBlindscanBeginRfSpectrum(); + + /// + /// Called when a data point for the RF Spectrum is available. + /// + /// + /// + /// + void OnBlindscanRfSpectrumEnqueueSample(SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, int frequency, double rf); + + /// + /// Called when the gathering of the RF Spectrum has been completed. + /// In the SDL2 version, this is supposed to close the ScottPlotWindow. + /// + void OnBlindscanEndRfSpectrum(); + + /// + /// Called when beginning to gather an IQ Spectrum. + /// In the SDL2 version, this is supposed to create a Surface for Pixel drawing. + /// + /// + void OnBlindscanBeginIqSpectrum(IqChartData result); + + /// + /// Called when the gathering of an IQ Spectrum has been completed. + /// In the SDL2 version, this is supposed to remove the Surface for Pixel drawing. + /// + void OnBlindscanEndIq(); + + /// + /// Called when a lock couldn't be acquired. + /// In the SDL2 version, this is supposed to play the fail.wav sound. + /// + /// + /// + void OnBlindscanLockFail(SearchResult satelliteSr, BlindscanResultState resultState); + + /// + /// Called before SetFilter is called. + /// In the SDL2 version, this is supposed to: + /// 1) Spawn all these nice windows about PAT, CAT, PMT, EIT, etc... + /// 2) Play the Success1.wav + /// 3) Set the packet counters in foundFrequenciesWindow to 0. + /// 4) Enable the Zap now button in the foundFrequenciesWindow. + /// + void OnBlindscanFilterSetUp(); + + /// + /// Called after we're done collecting packets from a transponder. + /// In the SDL2 version, this is supposed to: + /// 1) Disable the Zap now button in the foundFrequenciesWindow. + /// + void OnBlindscanScrapeStopCondition(); + + /// + /// Called after the packets collected from the transponder have all been processed. + /// In the SDL2 version, this is supposed to: + /// 1) Hide all the windows about DVB Tables + /// + void OnBlindscanAfterPacketDrain(); + + /// + /// Called when StreamReader has invoked a DvbCallback. + /// + /// 1 when the packet size is odd. 2 when out of memory + /// The size of the data StreamReader gave to the DvbCallback + void OnBlindscanPacketError(int errorCount, int length); + + void OnBlindscanPacketOk(int numPackets, int packetsQueueCount); + + /// + /// Checks whether the user asks to abort scraping and switch to the next transponder. + /// + /// Returns true if the button has been pressed. + bool IsZapNowRequested(); + + /// + /// Checks whether the user asks not to zap automatically. + /// + /// Returns true if the "Do not auto-zap" checkbox is checked in the FoundFrequenciesWIndow + bool MayAutoZap(); + + TaskQueue Tasks { get; set; } } } diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index f9fbf84..a06e72b 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -229,6 +229,14 @@ namespace skyscraper5.Skyscraper.Scraper logger.DebugFormat("Built filter chain: {0}", stringBuilder.ToString()); } + public int GetIpCommunicationParties() + { + if (trafficInfos == null) + return 0; + else + return trafficInfos.Count; + } + public void IngestFromStream(Stream stream) { byte[] buffer = new byte[188]; diff --git a/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs index 9168604..e1872b5 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs @@ -191,5 +191,7 @@ namespace skyscraper8.Skyscraper.Scraper.Storage void Ping(); IEnumerable> GetBlindscanResultFrequencies(Guid selectedGuid); + void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, bool settingsWindowScanVerticalHigh); + object[] GetLastUiBlindscanSettings(); } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs index ade5add..b448e2a 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs @@ -1121,6 +1121,21 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem throw new NotImplementedException(); } + public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, + bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, + bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, + bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, + bool settingsWindowScanVerticalHigh) + { + throw new NotImplementedException(); + } + + public object[] GetLastUiBlindscanSettings() + { + throw new NotImplementedException(); + } + public IEnumerable> SelectAllPmt() { throw new NotImplementedException(); diff --git a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs index 21c7cc2..22f3b41 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs @@ -929,6 +929,21 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory throw new NotImplementedException(); } + public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, + bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, + bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, + bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, + bool settingsWindowScanVerticalHigh) + { + throw new NotImplementedException(); + } + + public object[] GetLastUiBlindscanSettings() + { + throw new NotImplementedException(); + } + public IEnumerable> SelectAllPmt() { for (int x = 0; x < pmtEntries.Length; x++) diff --git a/skyscraper8/Skyscraper/TunerMetadata.cs b/skyscraper8/Skyscraper/TunerMetadata.cs index be19287..042a41a 100644 --- a/skyscraper8/Skyscraper/TunerMetadata.cs +++ b/skyscraper8/Skyscraper/TunerMetadata.cs @@ -1,5 +1,6 @@ using System; using System.Net.NetworkInformation; +using System.Runtime.InteropServices; using skyscraper5.Skyscraper.IO.CrazycatStreamReader; namespace skyscraper5.Skyscraper @@ -43,5 +44,19 @@ namespace skyscraper5.Skyscraper default: throw new NotImplementedException(String.Format("{0} {1}", nameof(DiseqcType), DiseqcType)); } } + + public bool IsSatellite() + { + switch (Type) + { + case STD_TYPE.STD_DVBS: return true; + case STD_TYPE.STD_DVBS2: return true; + case STD_TYPE.STD_DVBT: return false; + case STD_TYPE.STD_DVBT2: return false; + case STD_TYPE.STD_DVBC: return false; + case STD_TYPE.STD_DVBC2: return false; + default: throw new NotImplementedException(Type.ToString()); + } + } } }