Rewrote the complete blindscanning engine.

This commit is contained in:
feyris-tan 2025-08-28 20:47:56 +02:00
parent 1d7c9c3807
commit 03d827df44
28 changed files with 4009 additions and 1209 deletions

View File

@ -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;
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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<BlindscanSearchResult> _foundFrequencies;
public bool doNotAutoZap;
public bool allowZapNow;
public bool zapNowRequested;
private string tableUuid;
public long statusPacketsInTotal;
public long statusPacketsInQueue;
public FoundFrequenciesWindow2(List<BlindscanSearchResult> 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();
}
}
}
}

View File

@ -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<BlindscanSearchResult> 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
}
}

View File

@ -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<IRenderable> renderables;
public void SetTaskQueue(TaskQueue tasks, List<IRenderable> jobContextRenderables)
{
this.tasks = tasks;
this.renderables = jobContextRenderables;
}
}
}

View File

@ -59,6 +59,7 @@ namespace skyscraper8.UI.ImGui.Forms
_plot.Dispose();
_skBitmap.Dispose();
_skCanvas.Dispose();
_texture.Dispose();
}
}
}

View File

@ -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

View File

@ -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<TunerMetadata> tuners;
private List<SatellitePosition> satellites;
private List<LnbType> lnbs;
private List<DishType> 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<TunerMetadata> tunerMetadatas,
List<SatellitePosition> satellitePositions, List<LnbType> lnbTypes, List<DishType> 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();
}
}
}
}
}

View File

@ -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; }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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<MessageWindow> 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)

View File

@ -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<StreamReaderScanController.StreamReaderTuner> 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();

View File

@ -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<Tuple<int, int, ProgramMapping>> pmtEntries = data.SelectAllPmt().ToList();
List<Tuple<int, int, SdtService>> 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<SearchResult2> searchResults;
private void SearchResult2Callback(SearchResult2 searchResult)
{
if (searchResults == null)
searchResults = new List<SearchResult2>();
searchResults.Add(searchResult);
Console.WriteLine("Heard something at {0}", searchResult.Freq / 1000);
}
}
}

View File

@ -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<BlindscanSearchResult> 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<BlindscanSearchResult>();
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<DiSEqC_Opcode> 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<byte[]>();
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<byte[]> 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);
}
}
}

View File

@ -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; }
}
}

View File

@ -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;
/// <summary>
/// If true, the data is in SearchResult.
/// If false, the data is in SearchResult2.
/// </summary>
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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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<ushort, SdtService>();
}
private Dictionary<ushort, SdtService> sdtServices;
private Dictionary<ushort, ProgramMapping> 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<HumanReadableService> 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;
}
}
}

View File

@ -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<Action>();
}
private Queue<Action> 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();
}
}
}
}
}

View File

@ -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<StreamReaderTuner> GetTuners(IStreamReader streamReader)
{
List<StreamReaderTuner> result = new List<StreamReaderTuner>();
bool checkForDvbExEx = streamReader.CheckForDVBExEx((index, name, type) =>
{
result.Add(new StreamReaderTuner(index, name, type));
});
if (!checkForDvbExEx)
{
return new List<StreamReaderTuner>();
}
return result;
}
public List<StreamReaderTuner> GetTunersByStandard(STD_TYPE stdType)
{
return GetTuners(streamReader).Where(x => x.Type == stdType).ToList();
}
public StreamReaderTuner GetTunerByStandard(STD_TYPE stdType)
{
List<StreamReaderTuner> 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<BlindScanResult>();
}
public List<BlindScanResult> 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; }
}
}

View File

@ -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<byte[]> 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<byte[]>();
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;
}
}
}

View File

@ -25,5 +25,6 @@ namespace skyscraper5.Skyscraper.Scraper
public void InitalizeFilterChain(params IPacketFilter[] args);
}
int GetIpCommunicationParties();
}
}

View File

@ -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<HumanReadableService> GetServices();
void OnBlindscanOpenFoundFrquenciesWindow(List<BlindscanSearchResult> foundFrequencies, STD_TYPE tunerMetadataType);
void OnBlindscanJobDone(bool success);
void OnBlindscanErrorMessage(string blindscanningLowHorizontalAreaFailed);
/// <summary>
/// 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.
/// </summary>
void OnBlindscanBandComplete();
/// <summary>
/// Called before a BLScan operation begins.
/// </summary>
/// <param name="minimum">The minimum frequency to scan</param>
/// <param name="currentProgress">The Frequency on which we're starting.</param>
/// <param name="maximum">The maximum frequency to scan</param>
void OnBlindscanBeforeBLScan(int minimum, int currentProgress, int maximum);
/// <summary>
/// Called before a BLScan operation ends.
/// </summary>
void OnBlindscanAfterBLScan();
/// <summary>
/// Called when a transponder is found during a BLScan2.
/// </summary>
/// <param name="searchResult"></param>
/// <param name="polarityIndex"></param>
/// <param name="lnbTypeMinimumFrequency"></param>
/// <param name="lnbTypeMaximumFrequency"></param>
void OnBlindscanSearchResult1Callback(BlindscanSearchResult searchResult, int polarityIndex, int lnbTypeMinimumFrequency, int lnbTypeMaximumFrequency);
/// <summary>
/// Called before a SetChannel operation is performed.
/// </summary>
/// <param name="blindscanResult"></param>
void OnBlindscanBeforeSetChannel(BlindscanSearchResult blindscanResult, LnbType lnbType);
/// <summary>
/// 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.
/// </summary>
void OnScrapeBandComplete();
/// <summary>
/// Called after a single transponder has been scraped.
/// In the SDL2 version, this is supposed to hide the pressure plate representing the transponder.
/// </summary>
/// <param name="blindscanResult"></param>
void OnBlindscanScrapeTransponderComplete(BlindscanSearchResult blindscanResult);
/// <summary>
/// Called when beginning to gather the RF Spectrum.
/// In the SDL2 version, this is supposed to create the ScottPlot window.
/// </summary>
void OnBlindscanBeginRfSpectrum();
/// <summary>
/// Called when a data point for the RF Spectrum is available.
/// </summary>
/// <param name="polarization"></param>
/// <param name="frequency"></param>
/// <param name="rf"></param>
void OnBlindscanRfSpectrumEnqueueSample(SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, int frequency, double rf);
/// <summary>
/// Called when the gathering of the RF Spectrum has been completed.
/// In the SDL2 version, this is supposed to close the ScottPlotWindow.
/// </summary>
void OnBlindscanEndRfSpectrum();
/// <summary>
/// Called when beginning to gather an IQ Spectrum.
/// In the SDL2 version, this is supposed to create a Surface for Pixel drawing.
/// </summary>
/// <param name="result"></param>
void OnBlindscanBeginIqSpectrum(IqChartData result);
/// <summary>
/// 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.
/// </summary>
void OnBlindscanEndIq();
/// <summary>
/// Called when a lock couldn't be acquired.
/// In the SDL2 version, this is supposed to play the fail.wav sound.
/// </summary>
/// <param name="satelliteSr"></param>
/// <param name="resultState"></param>
void OnBlindscanLockFail(SearchResult satelliteSr, BlindscanResultState resultState);
/// <summary>
/// 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.
/// </summary>
void OnBlindscanFilterSetUp();
/// <summary>
/// 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.
/// </summary>
void OnBlindscanScrapeStopCondition();
/// <summary>
/// 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
/// </summary>
void OnBlindscanAfterPacketDrain();
/// <summary>
/// Called when StreamReader has invoked a DvbCallback.
/// </summary>
/// <param name="errorCount">1 when the packet size is odd. 2 when out of memory</param>
/// <param name="length">The size of the data StreamReader gave to the DvbCallback</param>
void OnBlindscanPacketError(int errorCount, int length);
void OnBlindscanPacketOk(int numPackets, int packetsQueueCount);
/// <summary>
/// Checks whether the user asks to abort scraping and switch to the next transponder.
/// </summary>
/// <returns>Returns true if the button has been pressed.</returns>
bool IsZapNowRequested();
/// <summary>
/// Checks whether the user asks not to zap automatically.
/// </summary>
/// <returns>Returns true if the "Do not auto-zap" checkbox is checked in the FoundFrequenciesWIndow</returns>
bool MayAutoZap();
TaskQueue Tasks { get; set; }
}
}

View File

@ -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];

View File

@ -191,5 +191,7 @@ namespace skyscraper8.Skyscraper.Scraper.Storage
void Ping();
IEnumerable<Tuple<int, SatelliteDeliverySystemDescriptor.PolarizationEnum>> 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();
}
}

View File

@ -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<Tuple<int, int, ProgramMapping>> SelectAllPmt()
{
throw new NotImplementedException();

View File

@ -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<Tuple<int, int, ProgramMapping>> SelectAllPmt()
{
for (int x = 0; x < pmtEntries.Length; x++)

View File

@ -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());
}
}
}
}