using ImGuiNET; using SDL2Demo.Forms; using SDL2Demo.SdlWrapper; using skyscraper5.Dvb.Descriptors; using skyscraper5.Skyscraper; using skyscraper5.Skyscraper.Equipment; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper5.Skyscraper.Scraper; using skyscraper5.src.Mpeg2.PacketFilter; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper8.Skyscraper.Drawing; using skyscraper8.Skyscraper.Plugins; using skyscraper8.UI.ImGui.Forms; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using testdrid.SdlWrapper; using static SDL2Demo.Jobs.Blindscan; namespace SDL2Demo.Jobs { class CoopBlindscan : IRenderable, IJob { private static PluginLogger logger = PluginLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private IDbBlindscanJobStorage jobStorage; private List tunerMetadataList; private JobContext jobContext; private List satellites; private List lnbs; public CoopBlindscan(List tuners, List satellitePositions, List lnbTypes, IDbBlindscanJobStorage jobStorage) { this.jobStorage = jobStorage; this.tunerMetadataList = tuners.Where(x => x.Type == STD_TYPE.STD_DVBS || x.Type == STD_TYPE.STD_DVBS2).ToList(); this.settingsWindowOpen = true; this.satellites = satellitePositions; this.lnbs = lnbTypes; this.lastTuner = -2; this.somethingStarted = false; this.settingsWindowScanHorizontalLow = true; this.settingsWindowScanHorizontalHigh = true; this.settingsWindowScanVerticalLow = true; this.settingsWindowScanVerticalHigh = true; this.settingsWindowDiseqc = 1; if (tuners.Count > 2) { this.settingsWindowTunerAselection = 0; this.settingsWindowTunerBselection = 1; } } public void Cancel() { throw new NotImplementedException(); } #region Configuration Window public JobContext JobContext { get { return jobContext; } set { jobContext = value; } } public bool WindowOpen => settingsWindowOpen; public CoopBlindscanConfiguration Configuration { get; private set; } private bool settingsWindowOpen; private int settingsWindowTunerAselection; private int settingsWindowTunerBselection; private bool settingsWindowScanHorizontalLow, settingsWindowScanHorizontalHigh, settingsWindowScanVerticalLow, settingsWindowScanVerticalHigh; private bool settingsWindowCaptureFile; private int settingsWindowDiseqc; private int settingsWindowSatellite; private bool settingsWindowCollectIqGraphs; private bool settingsWindowCollectRfSpectrum; public void Render() { if (ImGui.Begin("Blindscan", ref settingsWindowOpen, ImGuiWindowFlags.AlwaysAutoResize)) { if (tunerMetadataList.Count < 2) { ImGui.Text("You need at least two DVB-S Tuners for the cooperative blindscan."); ImGui.End(); return; } ImGui.Text("This assumes that both tuners are connected to the same antenna set-up, using e.g. a splitter."); ImGui.PushID("tunerA"); if (ImGui.BeginCombo("Tuner for BLScanEx", tunerMetadataList[settingsWindowTunerAselection].Name)) { for (int i = 0; i < tunerMetadataList.Count; i++) { bool isSelected = settingsWindowTunerAselection == i; if (ImGui.Selectable(tunerMetadataList[i].Name,isSelected)) { settingsWindowTunerAselection = i; } } ImGui.EndCombo(); } ImGui.PopID(); ImGui.PushID("tunerB"); if (ImGui.BeginCombo("Tuner for SetFilter", tunerMetadataList[settingsWindowTunerBselection].Name)) { for (int i = 0; i < tunerMetadataList.Count; i++) { bool isSelected = settingsWindowTunerBselection == i; if (ImGui.Selectable(tunerMetadataList[i].Name, isSelected)) { settingsWindowTunerBselection = i; } } ImGui.EndCombo(); } ImGui.PopID(); ImGui.PushID("satellite"); 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(); } ImGui.PopID(); ImGui.Checkbox("Capture Packets to files", ref settingsWindowCaptureFile); ImGui.Checkbox("Scan Low Horizontal Region", ref settingsWindowScanHorizontalLow); ImGui.Checkbox("Scan High Horizontal Region", ref settingsWindowScanHorizontalHigh); ImGui.Checkbox("Scan Low Vertical Region", ref settingsWindowScanVerticalLow); ImGui.Checkbox("Scan High Vertical Region", ref settingsWindowScanVerticalHigh); ImGui.Checkbox("Collect IQ Graphs", ref settingsWindowCollectIqGraphs); ImGui.Checkbox("Collect RF Spectrum", ref settingsWindowCollectRfSpectrum); ImGui.PushID("diseqc"); 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); ImGui.PopID(); bool sameTunerSelected = settingsWindowTunerAselection == settingsWindowTunerBselection; if (sameTunerSelected) { ImGui.Text("Please select different tuners for the operations."); ImGui.BeginDisabled(); } if (ImGui.Button("Start")) { settingsWindowOpen = false; int lnbIndex = tunerMetadataList[settingsWindowTunerAselection].Lnbs[settingsWindowDiseqc - 1]; LnbType lnb = lnbs.Find(x => x.Id == lnbIndex); Configuration = new CoopBlindscanConfiguration(tunerMetadataList[settingsWindowTunerAselection], tunerMetadataList[settingsWindowTunerBselection], settingsWindowScanHorizontalLow, settingsWindowScanHorizontalHigh, settingsWindowScanVerticalLow, settingsWindowScanVerticalHigh, settingsWindowDiseqc, settingsWindowSatellite, SatellitePosition.FromChecksum(satellites[settingsWindowSatellite].Checksum), lnb, settingsWindowCaptureFile); } ImGui.SameLine(); if (sameTunerSelected) ImGui.EndDisabled(); if (ImGui.Button("Cancel")) { settingsWindowOpen = false; } ImGui.End(); } } public class CoopBlindscanConfiguration { public CoopBlindscanConfiguration(TunerMetadata tunerA, TunerMetadata tunerB, bool doHorizontalLow, bool doHorizontalHigh, bool doVerticalLow, bool doVerticalHigh, int diseqc, int satelliteId, SatellitePosition direction, LnbType lnbType, bool recordingEnabled) { TunerA = tunerA; TunerB = tunerB; DoHorizontalLow = doHorizontalLow; DoHorizontalHigh = doHorizontalHigh; DoVerticalLow = doVerticalLow; DoVerticalHigh = doVerticalHigh; Diseqc = diseqc; SatelliteId = satelliteId; Direction = direction; LnbType = lnbType; RecordingEnabled = recordingEnabled; } public TunerMetadata TunerA { get; } public TunerMetadata TunerB { get; } public bool DoHorizontalLow { get; } public bool DoHorizontalHigh { get; } public bool DoVerticalLow { get; } public bool DoVerticalHigh { get; } public int Diseqc { get; } public int SatelliteId { get; } public SatellitePosition Direction { get; } public LnbType LnbType { get; } public bool RecordingEnabled { get; } } #endregion #region Blindscanning Driver private IStreamReader streamReader; private DbBlindscanJob jobInDb; private List foundFrequencies; private FoundFrequenciesWindow ourFoundFrequenciesWindow; private BlindscanProgressWindow _blindscanProgressWindow; private string recordingFilename; private int packetsToDrop; private Queue packetsQueue; private JobDisplay jobDisplay; private ISkyscraperContext skyscraperContext; private DateTime startedAt; private ulong packetsReceivedInTotal; private ulong droppedPackets; public void Run() { if (JobContext == null) throw new NullReferenceException("Job Context was not enrolled."); if (JobContext.StreamReader == null) throw new NullReferenceException("No StreamReader available"); if (streamReader == null) streamReader = JobContext.StreamReader; jobInDb = new DbBlindscanJob(Guid.NewGuid(), Configuration.TunerA.MacAddress, Configuration.TunerA.Type, Configuration.SatelliteId, JobContext.Gps, Configuration.Direction); jobInDb.HorizontalHighState = Configuration.DoHorizontalHigh ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobInDb.HorizontalLowState = Configuration.DoHorizontalLow ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobInDb.VerticalLowState = Configuration.DoVerticalLow ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobInDb.VerticalHighState = Configuration.DoVerticalHigh ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobStorage.InsertBlindscanJob(jobInDb); foundFrequencies = new List(); ourFoundFrequenciesWindow = new FoundFrequenciesWindow(foundFrequencies, Configuration.TunerA.Type, JobContext); JobContext.Renderables.Add(ourFoundFrequenciesWindow); if (!RunBlindscan()) { SetTuner(-1); JobContext.ReadyForNextJob = true; return; } JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); JobContext.Puppets[2].AutoMoveTo(new Point(0, 720 / 2)); JobContext.Puppets[3].AutoMoveTo(new Point(1280 / 2, 0)); JobContext.ReadyForNextJob = true; Console.WriteLine("Blindscan Job done!"); return; } public bool RunBlindscan() { Caps caps = Configuration.TunerA.Caps; if (settingsWindowCollectRfSpectrum) { SetTuner(1); RfSpectrumData rfSpectrum = GatherRfSpectrum(); if (rfSpectrum != null) { jobContext.ObjectStorage.StoreRfSpectrum(jobInDb.JobGuid, rfSpectrum); } } if (caps.HasFlag(Caps.SR_BLSCAN2)) { SearchResult sr1 = default; int tpNum = default; int lof1 = Configuration.LnbType.Lof1 * 1000; int lof2 = Configuration.LnbType.Lof2 * 1000; int lofSw = Configuration.LnbType.LofSw * 1000; int diseqc = Configuration.TunerA.DiseqcType; int startFreq = Configuration.LnbType.MinimumFrequency * 1000; int endFreq = Configuration.LnbType.MaximumFrequency * 1000; bool anythingSuceeded = false; IntPtr allocHGlobal = Marshal.AllocHGlobal(UInt16.MaxValue); if (lofSw != 0) { if (Configuration.DoHorizontalLow) { SetTuner(1); if (SendDiseqcCommand(false, true)) { //JobContext.LogWindow.Log(String.Format("Scanning low horizontal band...")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); bool hLower = BlScan2Wrap(startFreq, lofSw, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, ((ref SearchResult searchResult) => SearchResult1Callback(searchResult, 1))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); if (!hLower) { JobContext.MessageQueue.Enqueue(new MessageWindow("Blindscanning low horizontal area failed.")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); } else { anythingSuceeded = true; jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); SetTuner(2); SendDiseqcCommand(false, true); RunScrape(); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); foundFrequencies.Clear(); } } else { JobContext.MessageQueue.Enqueue(new MessageWindow("DiSEqC Switch to low horizontal area failed.")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; jobStorage.UpdateJobState(jobInDb); } } if (Configuration.DoHorizontalHigh) { SetTuner(1); if (SendDiseqcCommand(true, true)) { //JobContext.LogWindow.Log(String.Format("Scanning high horizontal band...")); jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); bool hUpper = BlScan2Wrap(lofSw, endFreq, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, ((ref SearchResult searchResult) => SearchResult1Callback(searchResult, 2))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); if (!hUpper) { JobContext.MessageQueue.Enqueue(new MessageWindow("Blindscanning high horizontal area failed.")); jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); } else { anythingSuceeded = true; jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); SetTuner(2); SendDiseqcCommand(true, true); RunScrape(); jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); foundFrequencies.Clear(); } } else { JobContext.MessageQueue.Enqueue(new MessageWindow("DiSEqC Switch to high horizontal area failed.")); jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; jobStorage.UpdateJobState(jobInDb); } } if (Configuration.DoVerticalLow) { SetTuner(1); if (SendDiseqcCommand(false, false)) { //JobContext.LogWindow.Log(String.Format("Scanning low vertical band...")); jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); bool vLower = BlScan2Wrap(startFreq, lofSw, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, ((ref SearchResult searchResult) => SearchResult1Callback(searchResult, 3))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); if (!vLower) { JobContext.MessageQueue.Enqueue(new MessageWindow("Blindscanning low vertical area failed.")); jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); } else { anythingSuceeded = true; jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); SetTuner(2); SendDiseqcCommand(false, false); RunScrape(); jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); foundFrequencies.Clear(); } } else { JobContext.MessageQueue.Enqueue(new MessageWindow("DiSEqC Switch to low vertical area failed.")); jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; jobStorage.UpdateJobState(jobInDb); } } if (Configuration.DoVerticalHigh) { SetTuner(1); if (SendDiseqcCommand(true, false)) { //JobContext.LogWindow.Log(String.Format("Scanning high vertical band...")); jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); bool vUpper = BlScan2Wrap(lofSw, endFreq, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, ((ref SearchResult searchResult) => SearchResult1Callback(searchResult, 4))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); if (!vUpper) { JobContext.MessageQueue.Enqueue(new MessageWindow("Blindscanning high vertical area failed.")); jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); } else { anythingSuceeded = true; jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); SetTuner(2); SendDiseqcCommand(true, false); RunScrape(); jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); foundFrequencies.Clear(); } } else { JobContext.MessageQueue.Enqueue(new MessageWindow("DiSEqC Switch to high vertical area failed.")); jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; jobStorage.UpdateJobState(jobInDb); } } } else { SetTuner(1); if (SendDiseqcCommand(false, true)) { //JobContext.LogWindow.Log(String.Format("Scanning left circular band...")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); bool lCirc = BlScan2Wrap(startFreq, endFreq, 0, lof1, lof2, lofSw, allocHGlobal, ref tpNum, ((ref SearchResult searchResult) => SearchResult1Callback(searchResult, 1))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); if (!lCirc) { jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); JobContext.MessageQueue.Enqueue(new MessageWindow("Blindscanning left circular area failed.")); } else { anythingSuceeded = true; jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); SetTuner(2); SendDiseqcCommand(false, true); RunScrape(); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); foundFrequencies.Clear(); } } else { JobContext.MessageQueue.Enqueue(new MessageWindow("DiSEqC Switch to left circulation failed.")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED_DISEQC; jobStorage.UpdateJobState(jobInDb); } SetTuner(1); if (SendDiseqcCommand(false, false)) { //JobContext.LogWindow.Log(String.Format("Scanning right circular band...")); jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); bool rCirc = BlScan2Wrap(startFreq, endFreq, 1, lof1, lof2, lofSw, allocHGlobal, ref tpNum, ((ref SearchResult searchResult) => SearchResult1Callback(searchResult, 3))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); if (!rCirc) { JobContext.MessageQueue.Enqueue(new MessageWindow("Blindscanning right circular area failed.")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); } else { anythingSuceeded = true; jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); SetTuner(2); SendDiseqcCommand(false, false); RunScrape(); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); foundFrequencies.Clear(); } } else { JobContext.MessageQueue.Enqueue(new MessageWindow("DiSEqC Switch to right circulation failed.")); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); } } Marshal.FreeHGlobal(allocHGlobal); SetTuner(-1); return anythingSuceeded; } else { throw new NotImplementedException("Don't know how to blindscan with this tuner."); } } private bool somethingStarted; private int lastTuner; private bool SetTuner(int mode) { if (lastTuner == mode) return true; if (somethingStarted) { streamReader.StopDVB(); somethingStarted = false; } bool result; switch(mode) { case 1: result = streamReader.StartDvbEx(Configuration.TunerA.Index); break; case 2: result = streamReader.StartDvbEx(Configuration.TunerB.Index); break; case -1: result = true; break; default: throw new NotImplementedException(String.Format("Tuner mode {0}", mode)); } if (mode != -1 && result) somethingStarted = true; if (!result) throw new Exception("Starting tuner failed."); lastTuner = mode; return true; } private bool BlScan2Wrap(int freq_start, int freq_stop, int pol, int lof1, int lof2, int lofSw, IntPtr pSearchResult, ref int pTpNum, BlScanCallback lpFunc) { _blindscanProgressWindow = new BlindscanProgressWindow(); _blindscanProgressWindow.Start = freq_start; _blindscanProgressWindow.Progress = freq_start; _blindscanProgressWindow.End = freq_stop; lock (JobContext.Renderables) { JobContext.Renderables.Add(_blindscanProgressWindow); } bool result = streamReader.BLScan2(freq_start, freq_stop, pol, lof1, lof2, lofSw, pSearchResult, ref pTpNum, lpFunc); lock (JobContext.Renderables) { JobContext.Renderables.Remove(_blindscanProgressWindow); } 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 = Configuration.Diseqc; 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"); } //JobContext.LogWindow.Log(String.Format("Send DiSEqC Command {0:X2}", (byte)myOpcode), 8); DateTime started = DateTime.Now; bool result = streamReader.SendDiSEqC((uint)2, myOpcode); TimeSpan timeTaken = DateTime.Now - started; //JobContext.LogWindow.Log(String.Format("DiSEqC Comannd sent in {0:F1} seconds.", timeTaken.TotalSeconds)); if (timeTaken.TotalSeconds > 10) { //JobContext.LogWindow.Log(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) { BlindscanResult blindscanResult = new BlindscanResult(searchResult, Configuration.LnbType.MinimumFrequency, Configuration.LnbType.MaximumFrequency); JobContext.Puppets[blindscanResult.sr1.Pol].AutoMoveTo(blindscanResult.Position); lock (JobContext.PressurePlates) { JobContext.PressurePlates.Add(blindscanResult); } lock (foundFrequencies) { foundFrequencies.Add(blindscanResult); } //JobContext.LogWindow.Log(String.Format("Found frequency: {0}, {1}", searchResult.Freq / 1000, searchResult.Pol == 0 ? "H" : "V")); SoundPlayer.PlaySoundFile("lock.wav"); _blindscanProgressWindow.Progress = searchResult.Freq; jobStorage.InsertSearchResult(jobInDb, true, searchResult, polarityIndex, new SearchResult2()); } public void RunScrape() { int lof1 = Configuration.LnbType.Lof1 * 1000; int lof2 = Configuration.LnbType.Lof2 * 1000; int lofSw = Configuration.LnbType.LofSw * 1000; foreach (BlindscanResult blindscanResult in foundFrequencies) { recordingFilename = null; DateTime now = DateTime.Now; JobContext.Puppets[2 + blindscanResult.sr1.Pol].AutoMoveTo(blindscanResult.Position); blindscanResult.State = BlindscanResultState.Tuning; jobStorage.UpdateTransponderState(jobInDb, blindscanResult.Satellite, blindscanResult.sr1, blindscanResult.State, blindscanResult.sr2); bool channel = streamReader.SetChannel(blindscanResult.sr1.Freq, blindscanResult.sr1.SR, blindscanResult.sr1.Pol, blindscanResult.sr1.FEC, lof1, lof2, lofSw); if (!channel) { blindscanResult.State = BlindscanResultState.TuningFailed; jobStorage.UpdateTransponderState(jobInDb, blindscanResult.Satellite, blindscanResult.sr1, blindscanResult.State, blindscanResult.sr2); continue; } 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, blindscanResult.sr1.Freq / 1000, blindscanResult.sr1.Pol == 0 ? "H" : "V", blindscanResult.sr1.SR / 1000, (int)(Configuration.Direction.angle * 10), Configuration.Direction.cardinalDirection == 0 ? "E" : "W"); RunSkyscraper(blindscanResult); blindscanResult.Visible = false; } JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); JobContext.Puppets[2].AutoMoveToHome(); JobContext.Puppets[3].AutoMoveToHome(); } private RfSpectrumData GatherRfSpectrum() { Caps caps = streamReader.GetCaps(); if (caps.HasFlag(Caps.SR_RFSCAN2)) { return GatherRfSpectrumCable(); } else if (!caps.HasFlag(Caps.SR_RFSCAN)) { logger.Log(PluginLogLevel.Error, "Couldn't figure out whether to use RFScan or RFScan2!"); return null; } SdlScottPlotWindowRfSpectrum window = new SdlScottPlotWindowRfSpectrum(jobContext.ImgUiDevice); jobContext.Renderables.Add(window); int lof1 = Configuration.LnbType.Lof1 * 1000; int lof2 = Configuration.LnbType.Lof2 * 1000; int lofSw = Configuration.LnbType.LofSw * 1000; int startFreq = Configuration.LnbType.MinimumFrequency * 1000; int endFreq = Configuration.LnbType.MaximumFrequency * 1000; RfSpectrumData spectrumData = RfSpectrumData.Create(); void RunRfScan(RfSpectrumData spectrum, int startFreq, int endFreq, SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, DiSEqC_Opcode diseqcCmd, int lof1, int lof2, int lofSw) { const int STEP = 1000; streamReader.SendDiSEqC(2, diseqcCmd); RfSpectrumDataBlock block = spectrumData.CreateBlock(startFreq, endFreq, STEP, polarization); for (int i = startFreq; i <= endFreq; i += STEP) { double rf = Double.NaN; streamReader.RFScan(i, diseqcCmd.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL) ? 0 : 1, lof1, lof2, lofSw, out rf); Console.WriteLine("{0} {1}, {2}", i, polarization.ToString().Substring(0, 1), rf); block.Push(i, rf); window.EnqueueSample(polarization, i, rf); } } foreach (DiSEqC_Opcode opcode in GetIqGraphDiseqcOpcodes()) { RunRfScan(spectrumData, startFreq, endFreq, opcode.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL) ? SatelliteDeliverySystemDescriptor.PolarizationEnum.HorizontalLinear : SatelliteDeliverySystemDescriptor.PolarizationEnum.VerticalLinear, opcode, lof1, lof2, lofSw); } lock (jobContext.Renderables) { JobContext.Renderables.Remove(window); window.Dispose(); window = null; } return spectrumData; } private RfSpectrumData GatherRfSpectrumCable() { throw new NotImplementedException(); } private IEnumerable GetIqGraphDiseqcOpcodes() { DiSEqC_Opcode baseDiseqc = DiSEqC_Opcode.DISEQC_HIGH_NIBBLE; int parameter = Configuration.Diseqc; switch (parameter) { case 1: baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_A; baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_A; break; case 2: baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_A; baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_B; break; case 3: baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_B; baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_A; break; case 4: baseDiseqc |= DiSEqC_Opcode.DISEQC_OPTION_B; baseDiseqc |= DiSEqC_Opcode.DISEQC_POSITION_B; break; default: throw new ArgumentOutOfRangeException("DiSEqC Switch Position"); } if (settingsWindowScanHorizontalLow || settingsWindowScanHorizontalHigh) yield return baseDiseqc | DiSEqC_Opcode.DISEQC_HORIZONTAL | DiSEqC_Opcode.DISEQC_LOW_BAND; if (settingsWindowScanVerticalLow || settingsWindowScanVerticalHigh) yield return baseDiseqc | DiSEqC_Opcode.DISEQC_VERTICAL | DiSEqC_Opcode.DISEQC_LOW_BAND; yield break; } private IqChartData GatherIqGraph() { Caps caps = streamReader.GetCaps(); if (caps.HasFlag(Caps.SR_IQSCAN2)) { return GatherIQGraphCable(); } else if (!caps.HasFlag(Caps.SR_IQSCAN)) { logger.Log(PluginLogLevel.Error, "Couldn't figure out whether to use IQScan or IQScan2!"); return null; } /* * */ IqChartData result = IqChartData.Create(); IqWindow iqWindow = new IqWindow(JobContext.ImgUiDevice, result); Monitor.Enter(JobContext.Renderables); JobContext.Renderables.Add(iqWindow); Monitor.Exit(JobContext.Renderables); sbyte[] buffer = new sbyte[400]; DateTime started = DateTime.Now; while (!result.IsComplete) { bool iqScan = 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); lock (jobContext.Renderables) { JobContext.Renderables.Remove(iqWindow); iqWindow.Dispose(); iqWindow = null; } return result; } private IqChartData GatherIQGraphCable() { throw new NotImplementedException(); } private void RunSkyscraper(BlindscanResult result) { int misCounter = 1; bool misMode = false; bool cableTvMode = false; Caps caps = streamReader.GetCaps(); SearchResult satelliteSr = new SearchResult(); SearchResult2 cableSr = new SearchResult2(); if (caps.HasFlag(Caps.SR_SIGINFO)) { //JobContext.LogWindow.Log(String.Format("Trying to BLScanEx..."), 8); if (!streamReader.BLScanEx(result.sr1.Freq, 5000, result.sr1.Pol, Configuration.LnbType.Lof1 * 1000, Configuration.LnbType.Lof2 * 1000, Configuration.LnbType.LofSw * 1000, 1000000, (STD_TYPE)result.sr1.StdType, ref satelliteSr)) { //No blindscan? No problem! Try anyway! satelliteSr = result.sr1; satelliteSr.Lock = false; result.State = BlindscanResultState.BlScanFailure; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); } if (!satelliteSr.Lock) { //JobContext.LogWindow.Log(String.Format("Trying to SetChannel..."), 8); bool channel = streamReader.SetChannel(result.sr1.Freq, result.sr1.SR, result.sr1.Freq, result.sr1.FEC, Configuration.LnbType.Lof1 * 1000, Configuration.LnbType.Lof2 * 1000, Configuration.LnbType.LofSw * 1000); if (!channel) { result.State = BlindscanResultState.TuningFailed; SoundPlayer.PlaySoundFile("fail.wav"); jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); return; } else { //JobContext.LogWindow.Log(String.Format("Trying to get SignalInfo..."), 8); bool signalInfo = streamReader.SignalInfo(ref satelliteSr); if (!signalInfo) { result.State = BlindscanResultState.TuningFailed; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); return; } if (!satelliteSr.Lock) { result.State = BlindscanResultState.NoLock; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); 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)) { //JobContext.LogWindow.Log(String.Format("Trying to SetChannel2..."), 8); bool channel2 = streamReader.SetChannel2((uint)result.sr2.Freq, (uint)result.sr2.BW); if (!channel2) { result.State = BlindscanResultState.TuningFailed; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); return; } //JobContext.LogWindow.Log(String.Format("Trying to get SignalInfo2..."), 8); bool signalInfo2 = streamReader.SignalInfo2(ref cableSr); if (!signalInfo2) { result.State = BlindscanResultState.TuningFailed; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); return; } if (!cableSr.Lock) { result.State = BlindscanResultState.NoLock; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); return; } } else { throw new NotImplementedException("Couldn't figure out what signal info to use."); } if (settingsWindowCollectIqGraphs) { result.State = BlindscanResultState.IqCollecting; IqChartData plot = GatherIqGraph(); if (plot != null) { result.State = BlindscanResultState.IqSaving; JobContext.ObjectStorage.StoreIqGraph(jobInDb.JobGuid, result.GetFrequency(), result.GetPolarity(), plot); } } for (int mis = 0; mis < misCounter; mis++) { if (misMode) { //JobContext.LogWindow.Log(String.Format("Selecting MIS IS {0}", satelliteSr.IS[mis]), 8); bool misSel = streamReader.MISSel(misMode, satelliteSr.IS[mis], 0xff); if (!misSel) { result.State = BlindscanResultState.MisFailure; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); return; } } //Start Filter TsRecorder tsRecorder = null; if (Configuration.RecordingEnabled) { tsRecorder = new TsRecorder(); tsRecorder.Recording = true; string outputDirName = JobContext.Ini.ReadValue("recording", "output_dir", "recording_output"); tsRecorder.RecordingOutputDirectory = new DirectoryInfo(outputDirName); tsRecorder.RecordingOutputDirectory.EnsureExists(); if (tsRecorder.PrepareRecording()) { tsRecorder.SetNextFilename(recordingFilename); tsRecorder.CreateBufferedStream(); } } IntPtr filterReference = IntPtr.MaxValue; //JobContext.LogWindow.Log(String.Format("Set-Up filter..."), 8); packetsToDrop = 1024; packetsQueue = new Queue(); ourFoundFrequenciesWindow.statusPacketsInqueue = 0; ourFoundFrequenciesWindow.statusPacketsInTotal = 0; bool filter = streamReader.SetFilter(8192, DvbCallback, 0x02, 2, ref filterReference); if (!filter) { result.State = BlindscanResultState.FilterFailure; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); SoundPlayer.PlaySoundFile("fail.wav"); return; } //JobContext.LogWindow.Log(String.Format("Filter set-up complete!"), 8); //Use the Filter result.State = BlindscanResultState.Scraping; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); jobDisplay = new JobDisplay(JobContext); lock (JobContext.Renderables) { JobContext.Renderables.Add(jobDisplay); } SoundPlayer.PlaySoundFile("Success1.wav"); SkipFilter skipper = new SkipFilter(SkipFilter.CRAZYSCAN_BUFFER * 7); skyscraperContext = SkyscraperContextFactory.CreateSkyscraper(JobContext.DataStorage, JobContext.ObjectStorage); skyscraperContext.TcpProxyEnabled = true; skyscraperContext.UiJunction = jobDisplay; IPacketFilter[] packetFilters = new IPacketFilter[0]; if (tsRecorder != null) packetFilters = new IPacketFilter[] { tsRecorder, skipper }; skyscraperContext.InitalizeFilterChain(packetFilters); byte[] singlePacketBuffer = new byte[188]; startedAt = DateTime.MinValue; packetsReceivedInTotal = 0; ourFoundFrequenciesWindow.allowZapNow = true; //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); } } ourFoundFrequenciesWindow.allowZapNow = false; //Stop Filter //JobContext.LogWindow.Log(String.Format("Deleting Filter..."), 8); bool stopped = streamReader.DelFilter(filterReference); if (!stopped) { result.State = BlindscanResultState.DelFilterFailed; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); return; } //JobContext.LogWindow.Log(String.Format("Deleted filter!"), 8); DrainPackets(); skyscraperContext.Dispose(); if (tsRecorder != null) tsRecorder.Dispose(); lock (JobContext.Renderables) { JobContext.Renderables.Remove(jobDisplay); } result.State = BlindscanResultState.DataSaving; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); foreach (HumanReadableService humanReadableService in jobDisplay.GetServices()) { jobStorage.InsertTransponderService(jobInDb, result.Satellite, result.sr1, result.sr2, humanReadableService); } jobDisplay = null; result.State = BlindscanResultState.Done; jobStorage.UpdateTransponderState(jobInDb, result.Satellite, result.sr1, result.State, result.sr2); } } private void DvbCallback(IntPtr data, int length) { if (length % 188 == 0) { try { byte[] buffer = new byte[length]; Marshal.Copy(data, buffer, 0, length); if (packetsToDrop <= 0) { lock (packetsQueue) { packetsQueue.Enqueue(buffer); } } packetsToDrop -= (buffer.Length / 188); packetsReceivedInTotal += (uint)(buffer.Length / 188); ourFoundFrequenciesWindow.statusPacketsInTotal = packetsReceivedInTotal; ourFoundFrequenciesWindow.statusPacketsInqueue = packetsQueue.Count; } catch (OutOfMemoryException e) { droppedPackets++; } } else { //JobContext.LogWindow.Log(String.Format("odd packet size!"), 8); } } private bool StopConditionMet() { if (startedAt == DateTime.MinValue) startedAt = DateTime.Now; if (ourFoundFrequenciesWindow.zapNowRequested) { ourFoundFrequenciesWindow.zapNowRequested = false; return true; } if (ourFoundFrequenciesWindow.doNotAutoZap) return false; if (packetsReceivedInTotal == 0 && (DateTime.Now - startedAt).TotalSeconds > 5) return true; if (jobDisplay != null) { if (jobDisplay.GseCommunicationParties > 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; //JobContext.LogWindow.Log(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) { //JobContext.LogWindow.Log(String.Format("{0} packets left ({1}).", packetsQueue.Count, drainTickerNow.ToLongTimeString()),8); } } //JobContext.LogWindow.Log(String.Format("Packets drained in {0} seconds.", (DateTime.Now - startedAt).TotalSeconds), 8); } #endregion } }