using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Drawing; using System.Net.NetworkInformation; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; using ImGuiNET; using Newtonsoft.Json; using SDL2Demo.Forms; using SDL2Demo.SdlWrapper; using skyscraper5.Skyscraper; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Equipment; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.src.Mpeg2.PacketFilter; using skyscraper8.Skyscraper.Scraper.Storage; namespace SDL2Demo.Jobs { internal class Blindscan : IRenderable, IJob { #region Driver public bool WindowOpen; public BlindscanTarget SelectedBlindscanTarget; public class BlindscanTarget { public BlindscanTarget(string name, int tunerIndex, STD_TYPE tunerStandard, int diseqcType, SatellitePosition satPosition, int satIndex, LnbType lnbType, PhysicalAddress tunerMetadataMacAddress) { this.name = name; this.tunerIndex = tunerIndex; this.tunerStandard = tunerStandard; this.diseqcType = diseqcType; this.satPosition = satPosition; this.satIndex = satIndex; this.buttonUuid = Guid.NewGuid().ToString(); this.lnbType = lnbType; this.macAddress = tunerMetadataMacAddress; } public string name; public int tunerIndex; public STD_TYPE tunerStandard; public int diseqcType; public SatellitePosition satPosition; public int satIndex; public string buttonUuid; public LnbType lnbType; public readonly PhysicalAddress macAddress; public bool IsTorC() { switch (tunerStandard) { case STD_TYPE.STD_DVBC: return true; case STD_TYPE.STD_DVBC2: return true; case STD_TYPE.STD_DVBT: return true; case STD_TYPE.STD_DVBT2: return true; case STD_TYPE.STD_DVBS: return false; case STD_TYPE.STD_DVBS2: return false; default: throw new NotImplementedException(tunerStandard.ToString()); } } } private List possibleBlindscanTargets; private string tableUuid; private bool willCaptureFiles; private IStreamReader streamReader; private bool hasSwitchingLnb; private bool willScanHorizontalLow, willScanHorizontalHigh, willScanVerticalLow, willScanVerticalHigh; private bool continuationDataExists; public bool ContinuationMode; private FoundFrequenciesWindow ourFoundFrequenciesWindow; private bool continueOldJob; private DbBlindscanJob jobInDb; private IDbBlindscanJobStorage jobStorage; public Blindscan(List tuners, List satellitePositions, List lnbTypes, DataStorage dataStorage) { this.jobStorage = dataStorage; continuationDataExists = jobStorage.TestForIncompleteJob(); possibleBlindscanTargets = new List(); foreach (TunerMetadata tunerMetadata in tuners) { switch (tunerMetadata.Type) { case STD_TYPE.STD_DVBS: int numSatsFromDiseqcType = tunerMetadata.GetNumSatsFromDiseqcType(); for (int i = 0; i < numSatsFromDiseqcType; i++) { SatellitePosition satellitePosition = satellitePositions.Find(x => x.Checksum == tunerMetadata.Satellites[i]); LnbType lnbType = lnbTypes.Find(x => x.Id == tunerMetadata.Lnbs[i]); if (satellitePosition == null) continue; if (lnbType == null) continue; if (lnbType.LofSw != 0) { hasSwitchingLnb = true; willScanHorizontalHigh = true; willScanHorizontalLow = true; willScanVerticalHigh = true; willScanVerticalLow = true; } possibleBlindscanTargets.Add(new BlindscanTarget(tunerMetadata.Name, tunerMetadata.Index, tunerMetadata.Type, tunerMetadata.DiseqcType, satellitePosition, i, lnbType, tunerMetadata.MacAddress)); } break; case STD_TYPE.STD_DVBC: possibleBlindscanTargets.Add(new BlindscanTarget(tunerMetadata.Name, tunerMetadata.Index, tunerMetadata.Type, 0, null, 0, null, tunerMetadata.MacAddress)); break; case STD_TYPE.STD_DVBT: possibleBlindscanTargets.Add(new BlindscanTarget(tunerMetadata.Name, tunerMetadata.Index, tunerMetadata.Type, 0, null, 0, null, tunerMetadata.MacAddress)); break; default: throw new NotImplementedException(tunerMetadata.Type.ToString()); } } WindowOpen = true; tableUuid = Guid.NewGuid().ToString(); } public void Render() { if (ImGui.Begin("Blindscan", ref WindowOpen, ImGuiWindowFlags.AlwaysAutoResize)) { if (possibleBlindscanTargets.Count == 0) { ImGui.Text("No possible blindscan targets!"); ImGui.Text("Did you configure the tuners and satellite positions?"); ImGui.End(); return; } ImGui.BeginTable(tableUuid, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit); foreach (BlindscanTarget possibleBlindscanTarget in possibleBlindscanTargets) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(possibleBlindscanTarget.name); ImGui.TableSetColumnIndex(1); if (possibleBlindscanTarget.tunerStandard == STD_TYPE.STD_DVBS) { ImGui.Text(String.Format("DiSEqC Position {0}", possibleBlindscanTarget.satIndex)); } else if (possibleBlindscanTarget.tunerStandard == STD_TYPE.STD_DVBC) { ImGui.Text("DVB-C"); } ImGui.TableSetColumnIndex(2); if (possibleBlindscanTarget.tunerStandard == STD_TYPE.STD_DVBS) { ImGui.Text(String.Format("{0} ({1})", possibleBlindscanTarget.satPosition.name, possibleBlindscanTarget.lnbType.Name)); } else { ImGui.TextWrapped(possibleBlindscanTarget.tunerIndex.ToString()); } ImGui.TableSetColumnIndex(3); ImGui.PushID(possibleBlindscanTarget.buttonUuid); if (ImGui.Button("Run scan")) { WindowOpen = false; SelectedBlindscanTarget = possibleBlindscanTarget; ContinuationMode = false; } ImGui.PopID(); } ImGui.EndTable(); ImGui.Checkbox("Capture Packets to files", ref willCaptureFiles); if (hasSwitchingLnb) { ImGui.Checkbox("Scan Low Horizontal Region", ref willScanHorizontalLow); ImGui.Checkbox("Scan High Horizontal Region", ref willScanHorizontalHigh); ImGui.Checkbox("Scan Low Vertical Region", ref willScanVerticalLow); ImGui.Checkbox("Scan High Vertical Region", ref willScanVerticalHigh); } if (continuationDataExists) { if (ImGui.Button("Continue with previous run")) { WindowOpen = false; ContinuationMode = true; } } ImGui.End(); } } 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; if (continueOldJob) { throw new NotImplementedException("continue old blindscan job"); } else { jobInDb = new DbBlindscanJob(Guid.NewGuid(), SelectedBlindscanTarget.macAddress, SelectedBlindscanTarget.tunerStandard, SelectedBlindscanTarget.satIndex, JobContext.Gps, SelectedBlindscanTarget.satPosition); if (SelectedBlindscanTarget.IsTorC()) { jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_WAITING; jobInDb.HorizontalHighState = DbBlindscanJobPolarizationStatus.NOT_SELECTED_NON_S_HINT; jobInDb.VerticalLowState = DbBlindscanJobPolarizationStatus.NOT_SELECTED_NON_S_HINT; jobInDb.VerticalHighState = DbBlindscanJobPolarizationStatus.NOT_SELECTED_NON_S_HINT; } else { jobInDb.HorizontalHighState = willScanHorizontalHigh ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobInDb.HorizontalLowState = willScanHorizontalLow ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobInDb.VerticalLowState = willScanVerticalLow ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; jobInDb.VerticalHighState = willScanVerticalHigh ? DbBlindscanJobPolarizationStatus.SELECTED_WAITING : DbBlindscanJobPolarizationStatus.NOT_SELECTED; } jobStorage.InsertBlindscanJob(jobInDb); } JobContext.LogWindow.Log("Attempting to start the tuner...", 8); if (!streamReader.StartDvbEx(SelectedBlindscanTarget.tunerIndex)) { JobContext.MessageQueue.Enqueue(new MessageWindow("Failed to start tuner.")); JobContext.ReadyForNextJob = true; return; } JobContext.LogWindow.Log("Tuner started", 8); foundFrequencies = new List(); ourFoundFrequenciesWindow = new FoundFrequenciesWindow(foundFrequencies, SelectedBlindscanTarget.tunerStandard, JobContext); JobContext.Renderables.Add(ourFoundFrequenciesWindow); if (!RunBlindscan()) { streamReader.StopDVB(); 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)); //RunScrape(); streamReader.StopDVB(); JobContext.ReadyForNextJob = true; Console.WriteLine("Blindscan Job done!"); return; } public void Cancel() { throw new NotImplementedException(); } public JobContext JobContext { get; set; } #endregion Driver #region Scanner public class BlindscanResult : IPressurePlate { internal BlindscanResult() { } public BlindscanResult(SearchResult2 dvbcResult, int minFreq, int maxFreq) { Visible = true; State = BlindscanResultState.Found; int w = (dvbcResult.Freq / 1000) - minFreq; int hundert = 1280; int g = (maxFreq - minFreq); int x = w * hundert / g; Position = new Point(x, 600); sr2 = dvbcResult; Satellite = false; } public BlindscanResult(SearchResult searchResult, int satPositionMinFreq, int satPositionMaxFreq) { int x = 0, y = 0; if (searchResult.Pol == 0) { //Horizontal int w = (searchResult.Freq / 1000) - satPositionMinFreq; int hundert = 1280; int g = (satPositionMaxFreq - satPositionMinFreq); x = w * hundert / g; y = 720 / 2; } else { //Vertical int w = (searchResult.Freq / 1000) - satPositionMinFreq; int hundert = 720; int g = (satPositionMaxFreq - satPositionMinFreq); x = 1280 / 2; y = w * hundert / g; } Position = new Point(x, y); Visible = true; sr1 = searchResult; Satellite = true; } public bool Visible { get; set; } public Point Position { get; private set; } public BlindscanResultState State { get; set; } public SearchResult sr1; public SearchResult2 sr2; public bool Satellite { get; private set; } public long GetFrequency() { if (Satellite) { return sr1.Freq; } else { return sr2.Freq; } } public char GetPolarity() { if (Satellite) { char polarity; switch (sr1.Pol) { case 0: polarity = 'H'; break; case 1: polarity = 'V'; break; case 2: polarity = 'L'; break; case 3: polarity = 'R'; break; default: polarity = 'W'; break; //W for WTF? } return polarity; } else { return 'C'; } } } public bool RunBlindscan() { Caps caps = streamReader.GetCaps(); switch (SelectedBlindscanTarget.tunerStandard) { case STD_TYPE.STD_DVBC: if (caps.HasFlag(Caps.SR_AIRSCAN)) { int startFreq = 48000; int endFreq = 1000000; uint step = 3000; uint bandwidth = 8000; STD_TYPE stdType = STD_TYPE.STD_DVBC; SearchResult2 sr2 = default; int tpNum = default; jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_BLINDSCANNING; jobStorage.UpdateJobState(jobInDb); IntPtr pSearchResult = Marshal.AllocHGlobal(UInt16.MaxValue); bool airScan = streamReader.AirScan(startFreq, endFreq, step, bandwidth, (int)stdType, pSearchResult, ref tpNum, ((ref SearchResult2 searchResult) => SearchResult2Callback(searchResult))); JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); Marshal.FreeHGlobal(pSearchResult); if (!airScan) { jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_FAILED; jobStorage.UpdateJobState(jobInDb); JobContext.MessageQueue.Enqueue(new MessageWindow("AirScan failed.")); return false; } jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_SCRAPING; jobStorage.UpdateJobState(jobInDb); RunScrape(); jobInDb.HorizontalLowState = DbBlindscanJobPolarizationStatus.SELECTED_DONE; jobStorage.UpdateJobState(jobInDb); return true; } else { throw new NotImplementedException("Don't know how to blindscan with this tuner."); } case STD_TYPE.STD_DVBS: if (caps.HasFlag(Caps.SR_BLSCAN2)) { SearchResult sr1 = default; int tpNum = default; int lof1 = SelectedBlindscanTarget.lnbType.Lof1 * 1000; int lof2 = SelectedBlindscanTarget.lnbType.Lof2 * 1000; int lofSw = SelectedBlindscanTarget.lnbType.LofSw * 1000; int diseqc = SelectedBlindscanTarget.diseqcType; int startFreq = SelectedBlindscanTarget.lnbType.MinimumFrequency * 1000; int endFreq = SelectedBlindscanTarget.lnbType.MaximumFrequency * 1000; bool anythingSuceeded = false; IntPtr allocHGlobal = Marshal.AllocHGlobal(UInt16.MaxValue); if (lofSw != 0) { if (willScanHorizontalLow) { if (SendDiseqcCommand(diseqc, 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); 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 (willScanHorizontalHigh) { if (SendDiseqcCommand(diseqc, true, true)) { SendDiseqcCommand(diseqc, 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); 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 (willScanVerticalLow) { if (SendDiseqcCommand(diseqc, 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); 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 (willScanVerticalHigh) { if (SendDiseqcCommand(diseqc, 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); 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 { if (SendDiseqcCommand(diseqc, 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); 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); } if (SendDiseqcCommand(diseqc, 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); 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); return anythingSuceeded; } else { throw new NotImplementedException("Don't know how to blindscan with this tuner."); } default: throw new NotImplementedException(SelectedBlindscanTarget.tunerStandard.ToString()); } } private BlindscanProgressWindow _blindscanProgressWindow; 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 void SearchResult1Callback(SearchResult searchResult, int polarityIndex) { BlindscanResult blindscanResult = new BlindscanResult(searchResult, SelectedBlindscanTarget.lnbType.MinimumFrequency, SelectedBlindscanTarget.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()); } private void SearchResult2Callback(SearchResult2 searchResult) { BlindscanResult blindscanResult = new BlindscanResult(searchResult, 48, 1000); JobContext.Puppets[0].AutoMoveTo(new Point(blindscanResult.Position.X, blindscanResult.Position.Y)); lock (JobContext.PressurePlates) { JobContext.PressurePlates.Add(blindscanResult); } lock (foundFrequencies) { foundFrequencies.Add(blindscanResult); } JobContext.LogWindow.Log(String.Format("Found frequency: {0}", searchResult.Freq / 1000)); SoundPlayer.PlaySoundFile("lock.wav"); jobStorage.InsertSearchResult(jobInDb, false, new SearchResult(), 7, searchResult); } private bool 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) { int parameter = SelectedBlindscanTarget.satIndex + 1; 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)diseqcType, 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(diseqcType, highBand, horizontal); } return result; } private List foundFrequencies; #endregion Scanner #region Scraper public void RunScrape() { int lof1 = 0; int lof2 = 0; int lofSw = 0; if (SelectedBlindscanTarget.tunerStandard == STD_TYPE.STD_DVBS) { lof1 = SelectedBlindscanTarget.lnbType.Lof1 * 1000; lof2 = SelectedBlindscanTarget.lnbType.Lof2 * 1000; lofSw = SelectedBlindscanTarget.lnbType.LofSw * 1000; } foreach (BlindscanResult blindscanResult in foundFrequencies) { recordingFilename = null; DateTime now = DateTime.Now; switch (SelectedBlindscanTarget.tunerStandard) { case STD_TYPE.STD_DVBS: 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)(SelectedBlindscanTarget.satPosition.angle * 10), SelectedBlindscanTarget.satPosition.cardinalDirection == 0 ? "E" : "W"); break; case STD_TYPE.STD_DVBC: JobContext.Puppets[1].AutoMoveTo(blindscanResult.Position); blindscanResult.State = BlindscanResultState.Tuning; jobStorage.UpdateTransponderState(jobInDb, blindscanResult.Satellite, blindscanResult.sr1, blindscanResult.State, blindscanResult.sr2); bool channel2 = streamReader.SetChannel2((uint)blindscanResult.sr2.Freq, (uint)blindscanResult.sr2.BW); if (!channel2) { 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}_C_{5}_{6}.ts", now.Year, now.Month, now.Day, now.Hour, now.Minute, blindscanResult.sr2.Freq / 1000, blindscanResult.sr2.SR); break; default: throw new NotImplementedException(SelectedBlindscanTarget.tunerStandard.ToString()); } RunSkyscraper(blindscanResult); blindscanResult.Visible = false; } JobContext.Puppets[0].AutoMoveToHome(); JobContext.Puppets[1].AutoMoveToHome(); JobContext.Puppets[2].AutoMoveToHome(); JobContext.Puppets[3].AutoMoveToHome(); } private JobDisplay jobDisplay; private ISkyscraperContext skyscraperContext; private string recordingFilename; 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 droppedPackets; private ulong packetsReceivedInTotal; private Queue packetsQueue; private int packetsToDrop; 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 HasPackets() { lock (packetsQueue) { return packetsQueue.Count > 0; } } private DateTime startedAt; private sbyte[] iqBuffer; private DateTime prevIqTimestamp; private IqWindow iqWindow; 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 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); } 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)) { /*if (caps.HasFlag(Caps.SR_MISSEL)) if (!streamReader.MISSel(false, 0, 0)) { result.State = BlindscanResultState.MisFailure; return; } */ /*S2Mode m = new S2Mode(); if (caps.HasFlag(Caps.SR_MODSEL)) if (!streamReader.ModSel(ref m, 0)) { result.State = BlindscanResultState.ModFailure; return; }*/ /* if (caps.HasFlag(Caps.SR_PLSSEL)) if (!streamReader.PLSSel(0, 0)) { result.State = BlindscanResultState.PlsFailure; return; } */ JobContext.LogWindow.Log(String.Format("Trying to BLScanEx..."), 8); if (!streamReader.BLScanEx(result.sr1.Freq, 5000, result.sr1.Pol, SelectedBlindscanTarget.lnbType.Lof1 * 1000, SelectedBlindscanTarget.lnbType.Lof2 * 1000, SelectedBlindscanTarget.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, SelectedBlindscanTarget.lnbType.Lof1 * 1000, SelectedBlindscanTarget.lnbType.Lof2 * 1000, SelectedBlindscanTarget.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."); } 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 (willCaptureFiles) { 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"); 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 }; skyscraperContext.InitalizeFilterChain(tsRecorder); 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); } /*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)) { result.State = BlindscanResultState.NoLock; return; } int misCounter = 1; int misMode = 0; byte[] s2_is = null; if (!cableTvMode) { SearchResult sr = default; if (!streamReader.SignalInfo(ref sr)) { result.State = BlindscanResultState.NoLock; return; } if (sr.MIS > 16) sr.MIS = 0; if (!sr.Lock) return; misMode = sr.MIS; s2_is = sr.IS; } for (int mis = 0; mis < misCounter; mis++) { if (misMode != 0) { JobContext.LogWindow.Log(String.Format("Selecting MIS IS {0}", s2_is[mis]),8); bool misSel = streamReader.MISSel(misMode != 0, s2_is[mis], 0xff); if (!misSel) { result.State = BlindscanResultState.MisFailure; return; } } //Start Filter if (PrepareRecording()) { FileInfo recordingFileInfo = new FileInfo(Path.Combine(RecordingOutputDirectory.FullName,recordingFilename)); recordingFileInfo.Directory.EnsureExists(); recordingFileStream = recordingFileInfo.OpenWrite(); recordingBufferedStream = new BufferedStream(recordingFileStream); } IntPtr filterReference = IntPtr.MaxValue; JobContext.LogWindow.Log(String.Format("before set filter"), 8); packetsQueue = new Queue(); bool filter = streamReader.SetFilter(8192, DvbCallback, 0x02, 2, ref filterReference); if (!filter) { result.State = BlindscanResultState.FilterFailure; return; } //Use the Filter result.State = BlindscanResultState.Scraping; jobDisplay = new JobDisplay(JobContext); lock (JobContext.Renderables) { JobContext.Renderables.Add(jobDisplay); } skyscraperContext = SkyscraperContextFactory.CreateSkyscraper(JobContext.ScraperEventLogger, JobContext.ScraperStorage); skyscraperContext.TcpProxyEnabled = true; skyscraperContext.UiJunction = jobDisplay; byte[] singlePacketBuffer = new byte[188]; 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); } } skyscraperContext.Dispose(); //Stop Filter bool stopped = streamReader.DelFilter(filterReference); if (!stopped) { result.State = BlindscanResultState.DelFilterFailed; return; } DrainPackets(); if (recordingBufferedStream != null) { recordingBufferedStream.Flush(); recordingBufferedStream.Close(); recordingBufferedStream.Dispose(); recordingBufferedStream = null; recordingFileStream.Close(); recordingFileStream.Dispose(); recordingFileStream = null; } lock (JobContext.Renderables) { JobContext.Renderables.Remove(jobDisplay); } jobDisplay = null; result.State = BlindscanResultState.Done;*/ } } #endregion }