diff --git a/skyscraper8.Tests/Tests/CoverageTests/MathTests.cs b/skyscraper8.Tests/Tests/CoverageTests/MathTests.cs new file mode 100644 index 0000000..5c01822 --- /dev/null +++ b/skyscraper8.Tests/Tests/CoverageTests/MathTests.cs @@ -0,0 +1,19 @@ +using skyscraper8.Skyscraper.Math; + +namespace skyscraper8.Tests.NUnit.Tests.CoverageTests; + +[TestFixture] +public class MathTests +{ + [Test] + public void TestPlsConversions() + { + int originalGoldCode = 131070; + + int calculatedRootCode = PlsCodeConverter.GoldToRoot(originalGoldCode); + Assert.That(calculatedRootCode, Is.EqualTo(16416)); + + int calculatedGoldCode = PlsCodeConverter.RootToGold(calculatedRootCode); + Assert.That(calculatedGoldCode, Is.EqualTo(originalGoldCode)); + } +} \ No newline at end of file diff --git a/skyscraper8.sln.DotSettings.user b/skyscraper8.sln.DotSettings.user index 0f7a660..6aa6dc7 100644 --- a/skyscraper8.sln.DotSettings.user +++ b/skyscraper8.sln.DotSettings.user @@ -17,6 +17,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -38,6 +39,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index 5e567cc..375da65 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -103,317 +103,337 @@ namespace skyscraper5 if (args.Length != 0) { - if (args[0].ToLowerInvariant().EndsWith(".ts")) - { - FileInfo fi = new FileInfo(args[0]); - if (fi.Exists) - HandleSingleFile(fi); - else - Console.WriteLine("{0} missing.", fi.FullName); - return; - } + if (args[0].ToLowerInvariant().EndsWith(".ts")) + { + FileInfo fi = new FileInfo(args[0]); + if (fi.Exists) + HandleSingleFile(fi); + else + Console.WriteLine("{0} missing.", fi.FullName); + return; + } - if (args[0].ToLowerInvariant().EndsWith(".m3u8")) - { - M3U8Stream m3U8Stream = new M3U8Stream(args[0]); - DataStorage dataStorage = new InMemoryScraperStorage(); - ObjectStorage objectStorage = new FilesystemStorage(new DirectoryInfo(".")); - SkyscraperContext skyscraperContext = new SkyscraperContext(new TsContext(), dataStorage, objectStorage); - skyscraperContext.InitalizeFilterChain(); - skyscraperContext.IngestFromStream(m3U8Stream); - return; - } + if (args[0].ToLowerInvariant().EndsWith(".m3u8")) + { + M3U8Stream m3U8Stream = new M3U8Stream(args[0]); + DataStorage dataStorage = new InMemoryScraperStorage(); + ObjectStorage objectStorage = new FilesystemStorage(new DirectoryInfo(".")); + SkyscraperContext skyscraperContext = + new SkyscraperContext(new TsContext(), dataStorage, objectStorage); + skyscraperContext.InitalizeFilterChain(); + skyscraperContext.IngestFromStream(m3U8Stream); + return; + } - if (args[0].ToLowerInvariant().Equals("bumutest")) - { - FileInfo fi = new FileInfo(args[1]); - FileStream fstream = fi.OpenRead(); - - TsContext mpeg2 = new TsContext(); - SkyscraperContext skyscraper = new SkyscraperContext(mpeg2, new InMemoryScraperStorage(), new BlackholeObjectStorage()); - skyscraper.InitalizeFilterChain(); + if (args[0].ToLowerInvariant().Equals("bumutest")) + { + FileInfo fi = new FileInfo(args[1]); + FileStream fstream = fi.OpenRead(); - MultiprotocolEncapsulationDecoder mpeDecoder = new MultiprotocolEncapsulationDecoder(skyscraper); - PsiDecoder psiDecoder = new PsiDecoder(0x1019, mpeDecoder); - mpeg2.RegisterPacketProcessor(0x1019, psiDecoder); + TsContext mpeg2 = new TsContext(); + SkyscraperContext skyscraper = new SkyscraperContext(mpeg2, new InMemoryScraperStorage(), + new BlackholeObjectStorage()); + skyscraper.InitalizeFilterChain(); - skyscraper.IngestFromStream(fstream); - } - if (args[0].Equals("aactest")) - { - new AacTestProgram().Run(); - return; - } - if (args[0].ToLowerInvariant().Equals("cscan")) - { - HandleCrazyScanToTestingSystem(args[1]); - return; - } - if (args[0].ToLowerInvariant().Equals("cscan-live")) - { - HandleCrazyScanToLiveSystem(args[1]); - return; - } - if (args[0].ToLowerInvariant().Equals("cscan-live-notimeout")) - { - HandleCrazyScanToLiveSystem(args[1], false); - return; - } + MultiprotocolEncapsulationDecoder mpeDecoder = new MultiprotocolEncapsulationDecoder(skyscraper); + PsiDecoder psiDecoder = new PsiDecoder(0x1019, mpeDecoder); + mpeg2.RegisterPacketProcessor(0x1019, psiDecoder); - if (args[0].ToLowerInvariant().Equals("udpin")) - { - HandleUdpTesting(); - return; - } - if (args[0].ToLowerInvariant().Equals("udp-agent")) - { - HandleUdpLive(); - return; - } + skyscraper.IngestFromStream(fstream); + } - if (args[0].Equals("abertest")) - { - FileInfo fi = new FileInfo(args[1]); - if (!fi.Exists) - { - Console.WriteLine("{0} not found", fi.FullName); - return; - } - AbertisDemoProgram abertisDemo = new AbertisDemoProgram(fi); - abertisDemo.Run(); - return; - } + if (args[0].Equals("aactest")) + { + new AacTestProgram().Run(); + return; + } - if (args[0].ToLowerInvariant().Equals("t2mitest")) - { - new TestApp(args[1]).Run(); - return; - } - - if (args[0].ToLowerInvariant().Equals("ioctltest")) - { - IoctlTest(); - return; - } - - if (args[0].ToLowerInvariant().Equals("m2tstots")) - { - FileInfo infile = new FileInfo(args[1]); - FileInfo outfile = new FileInfo(args[2]); - new M2TsToTs(infile,outfile).Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("cscan")) + { + HandleCrazyScanToTestingSystem(args[1]); + return; + } - if (Directory.Exists(args[0])) - { - DirectoryInfo doThisDir = new DirectoryInfo(args[0]); - ProcessDirectory(doThisDir); - return; - } + if (args[0].ToLowerInvariant().Equals("cscan-live")) + { + HandleCrazyScanToLiveSystem(args[1]); + return; + } - if (args[0].ToLowerInvariant().Equals("proxytest")) - { - TcpTsProxy tcpTsProxy = new TcpTsProxy(); - Thread.Sleep(5000); - tcpTsProxy.Dispose(); - return; - } + if (args[0].ToLowerInvariant().Equals("cscan-live-notimeout")) + { + HandleCrazyScanToLiveSystem(args[1], false); + return; + } - if (args[0].ToLowerInvariant().Equals("importtest")) - { - DirectoryInfo doThisDir = new DirectoryInfo(args[1]); - InMemoryScraperStorage imss = new InMemoryScraperStorage(); - FilesystemStorage fs = new FilesystemStorage(new DirectoryInfo(".")); - TsFileCollectionImporter importer = new TsFileCollectionImporter(imss, fs, doThisDir); - importer.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("udpin")) + { + HandleUdpTesting(); + return; + } + + if (args[0].ToLowerInvariant().Equals("udp-agent")) + { + HandleUdpLive(); + return; + } + + if (args[0].Equals("abertest")) + { + FileInfo fi = new FileInfo(args[1]); + if (!fi.Exists) + { + Console.WriteLine("{0} not found", fi.FullName); + return; + } + + AbertisDemoProgram abertisDemo = new AbertisDemoProgram(fi); + abertisDemo.Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("t2mitest")) + { + new TestApp(args[1]).Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("ioctltest")) + { + IoctlTest(); + return; + } + + if (args[0].ToLowerInvariant().Equals("m2tstots")) + { + FileInfo infile = new FileInfo(args[1]); + FileInfo outfile = new FileInfo(args[2]); + new M2TsToTs(infile, outfile).Run(); + return; + } + + if (Directory.Exists(args[0])) + { + DirectoryInfo doThisDir = new DirectoryInfo(args[0]); + ProcessDirectory(doThisDir); + return; + } + + if (args[0].ToLowerInvariant().Equals("proxytest")) + { + TcpTsProxy tcpTsProxy = new TcpTsProxy(); + Thread.Sleep(5000); + tcpTsProxy.Dispose(); + return; + } + + if (args[0].ToLowerInvariant().Equals("importtest")) + { + DirectoryInfo doThisDir = new DirectoryInfo(args[1]); + InMemoryScraperStorage imss = new InMemoryScraperStorage(); + FilesystemStorage fs = new FilesystemStorage(new DirectoryInfo(".")); + TsFileCollectionImporter importer = new TsFileCollectionImporter(imss, fs, doThisDir); + importer.Run(); + return; + } - //fsimport "D:\Skyscraper" "E:\\" - if (args[0].ToLowerInvariant().Equals("fsimport")) - { - DirectoryInfo srcDir = new DirectoryInfo(args[1]); - DirectoryInfo tgtDir = new DirectoryInfo(args[2]); - FilesystemStorage fss = new FilesystemStorage(tgtDir); - TsFileCollectionImporter importer = new TsFileCollectionImporter(fss, fss, srcDir); - importer.Run(); - return; - } - - if (args[0].ToLowerInvariant().Equals("webservertest")) - { - SkyscraperWebserver webserverTest = SkyscraperWebserver.GetInstance(); - webserverTest.Start(); - while (webserverTest.IsListening) - { - Thread.Sleep(1000); - } + //fsimport "D:\Skyscraper" "E:\\" + if (args[0].ToLowerInvariant().Equals("fsimport")) + { + DirectoryInfo srcDir = new DirectoryInfo(args[1]); + DirectoryInfo tgtDir = new DirectoryInfo(args[2]); + FilesystemStorage fss = new FilesystemStorage(tgtDir); + TsFileCollectionImporter importer = new TsFileCollectionImporter(fss, fss, srcDir); + importer.Run(); + return; + } - return; - } + if (args[0].ToLowerInvariant().Equals("webservertest")) + { + SkyscraperWebserver webserverTest = SkyscraperWebserver.GetInstance(); + webserverTest.Start(); + while (webserverTest.IsListening) + { + Thread.Sleep(1000); + } - if (args[0].ToLowerInvariant().Equals("gpstest")) - { - GpsManager.GpsTest(); - return; - } - - if (args[0].ToLowerInvariant().Equals("what-can-i-receive")) - { - WhatCanIReceive.StandaloneProgram(); - return; - } + return; + } - if (args[0].ToLowerInvariant().Equals("make-dummy-ts")) - { - DummyTsGenerator dummyTsGenerator = new DummyTsGenerator(); - dummyTsGenerator.Run(); - return; - } - - if (args[0].ToLowerInvariant().Equals("file-live")) - { - Program.HandleFileToLiveSystem(args[1]); - return; - } + if (args[0].ToLowerInvariant().Equals("gpstest")) + { + GpsManager.GpsTest(); + return; + } - if (args[0].ToLowerInvariant().Equals("hlsproxy")) - { - DirectoryInfo di = new DirectoryInfo(args[1]); - HlsProxy hlsproxy = new HlsProxy(di); - hlsproxy.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("what-can-i-receive")) + { + WhatCanIReceive.StandaloneProgram(); + return; + } - if (args[0].ToLowerInvariant().Equals("hlsproxy-destructive")) - { - DirectoryInfo di = new DirectoryInfo(args[1]); - HlsProxy hlsproxy = new HlsProxy(di); - hlsproxy.DestructiveMode = true; - hlsproxy.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("make-dummy-ts")) + { + DummyTsGenerator dummyTsGenerator = new DummyTsGenerator(); + dummyTsGenerator.Run(); + return; + } - if (args[0].ToLowerInvariant().Equals("satip")) - { - QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args); - qadsipc.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("file-live")) + { + Program.HandleFileToLiveSystem(args[1]); + return; + } - if (args[0].ToLowerInvariant().Equals("satip-playout")) - { - QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args); - qadsipc.SetPlayoutMode(args); - qadsipc.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("hlsproxy")) + { + DirectoryInfo di = new DirectoryInfo(args[1]); + HlsProxy hlsproxy = new HlsProxy(di); + hlsproxy.Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("hlsproxy-destructive")) + { + DirectoryInfo di = new DirectoryInfo(args[1]); + HlsProxy hlsproxy = new HlsProxy(di); + hlsproxy.DestructiveMode = true; + hlsproxy.Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("satip")) + { + QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args); + qadsipc.Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("satip-playout")) + { + QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args); + qadsipc.SetPlayoutMode(args); + qadsipc.Run(); + return; + } - if (args[0].ToLowerInvariant().Equals("shannon")) - { - if (args.Length != 2) - { - Console.WriteLine("Specify ONE file, please."); - return; - } - FileInfo fi = new FileInfo(args[1]); - if (!fi.Exists) - { - Console.WriteLine("{0} doesn't exist.", fi.FullName); - return; - } - FileStream fileStream = fi.OpenRead(); - EntropyCalculatorStream entropyCalculatorStream = new EntropyCalculatorStream(); - fileStream.CopyTo(entropyCalculatorStream); - fileStream.Close(); - fileStream.Dispose(); - Console.WriteLine("Entropy value: {0} ({1}%)", entropyCalculatorStream.Entropy, entropyCalculatorStream.Percentage); - return; - } + if (args[0].ToLowerInvariant().Equals("shannon")) + { + if (args.Length != 2) + { + Console.WriteLine("Specify ONE file, please."); + return; + } - if (args[0].ToLowerInvariant().Equals("pcap-on")) - { - TogglePcapConfiguration(1); - return; - } - if (args[0].ToLowerInvariant().Equals("pcap-off")) - { - TogglePcapConfiguration(2); - return; - } + FileInfo fi = new FileInfo(args[1]); + if (!fi.Exists) + { + Console.WriteLine("{0} doesn't exist.", fi.FullName); + return; + } - if (args[0].ToLowerInvariant().Equals("subts-on")) - { - ToggleSubTsDumpConfiguration(true); - return; - } + FileStream fileStream = fi.OpenRead(); + EntropyCalculatorStream entropyCalculatorStream = new EntropyCalculatorStream(); + fileStream.CopyTo(entropyCalculatorStream); + fileStream.Close(); + fileStream.Dispose(); + Console.WriteLine("Entropy value: {0} ({1}%)", entropyCalculatorStream.Entropy, + entropyCalculatorStream.Percentage); + return; + } - if (args[0].ToLowerInvariant().Equals("subts-off")) - { - ToggleSubTsDumpConfiguration(false); - return; - } + if (args[0].ToLowerInvariant().Equals("pcap-on")) + { + TogglePcapConfiguration(1); + return; + } - if (args[0].ToLowerInvariant().Equals("pts2bbf")) - { - if (args[1].ToLowerInvariant().Equals("bbfudpdecap")) - { - FileInfo fi = new FileInfo(args[2]); - Pts2Bbf.Run(fi, true); - return; - } - else - { - FileInfo fi = new FileInfo(args[1]); - Pts2Bbf.Run(fi, false); - return; - } - } + if (args[0].ToLowerInvariant().Equals("pcap-off")) + { + TogglePcapConfiguration(2); + return; + } - if (args[0].ToLowerInvariant().Equals("pts2bbf2")) - { - FileInfo fi = new FileInfo(args[1]); - Pts2Bbf2 pts2Bbf2 = new Pts2Bbf2(fi); - pts2Bbf2.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("subts-on")) + { + ToggleSubTsDumpConfiguration(true); + return; + } - if (args[0].ToLowerInvariant().Equals("stid135test")) - { - FileInfo fi = new FileInfo(args[1]); - Stid135Test.Run(fi); - return; - } + if (args[0].ToLowerInvariant().Equals("subts-off")) + { + ToggleSubTsDumpConfiguration(false); + return; + } - if (args[0].ToLowerInvariant().Equals("make-catalogue")) - { - DirectoryInfo di = new DirectoryInfo(args[1]); - logger.InfoFormat("Input directory: {0}", di.FullName); - FileInfo fi = new FileInfo(args[2]); - logger.InfoFormat("Output File: {0}", fi.FullName); - CatalogueGenerator catalogueGenerator = new CatalogueGenerator(di, fi); - catalogueGenerator.Run(); - catalogueGenerator.Dispose(); - return; - } - if (args[0].ToLowerInvariant().Equals("rotation-catalogue")) - { - TsRotationToCsv rotator = new TsRotationToCsv(); - rotator.SourceDir = new DirectoryInfo(args[1]); - rotator.DestinationCsv = new FileInfo(args[2]); - rotator.Run(); - return; - } + if (args[0].ToLowerInvariant().Equals("pts2bbf")) + { + if (args[1].ToLowerInvariant().Equals("bbfudpdecap")) + { + FileInfo fi = new FileInfo(args[2]); + Pts2Bbf.Run(fi, true); + return; + } + else + { + FileInfo fi = new FileInfo(args[1]); + Pts2Bbf.Run(fi, false); + return; + } + } - if (args[0].ToLowerInvariant().Equals("salvage")) - { - Salvager salvager = new Salvager(); - salvager.Run(args); - return; - } - } + if (args[0].ToLowerInvariant().Equals("pts2bbf2")) + { + FileInfo fi = new FileInfo(args[1]); + Pts2Bbf2 pts2Bbf2 = new Pts2Bbf2(fi); + pts2Bbf2.Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("stid135test")) + { + FileInfo fi = new FileInfo(args[1]); + Stid135Test.Run(fi); + return; + } + + if (args[0].ToLowerInvariant().Equals("make-catalogue")) + { + DirectoryInfo di = new DirectoryInfo(args[1]); + logger.InfoFormat("Input directory: {0}", di.FullName); + FileInfo fi = new FileInfo(args[2]); + logger.InfoFormat("Output File: {0}", fi.FullName); + CatalogueGenerator catalogueGenerator = new CatalogueGenerator(di, fi); + catalogueGenerator.Run(); + catalogueGenerator.Dispose(); + return; + } + + if (args[0].ToLowerInvariant().Equals("rotation-catalogue")) + { + TsRotationToCsv rotator = new TsRotationToCsv(); + rotator.SourceDir = new DirectoryInfo(args[1]); + rotator.DestinationCsv = new FileInfo(args[2]); + rotator.Run(); + return; + } + + if (args[0].ToLowerInvariant().Equals("salvage")) + { + Salvager salvager = new Salvager(); + salvager.Run(args); + return; + } + + if (args[0].ToLowerInvariant().Equals("satip-oldconfig")) + { + SatIpOldconfig satIpOldconfig = new SatIpOldconfig(); + satIpOldconfig.Run(); + return; + } + } /*Passing passing = new Passing(); if (!passing.Boot()) diff --git a/skyscraper8/QuickAndDirtySatIpClient.cs b/skyscraper8/QuickAndDirtySatIpClient.cs index 045c641..deaf70c 100644 --- a/skyscraper8/QuickAndDirtySatIpClient.cs +++ b/skyscraper8/QuickAndDirtySatIpClient.cs @@ -13,6 +13,7 @@ using skyscraper5.Mpeg2; using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Scraper.Storage.Filesystem; using skyscraper5.Skyscraper.Scraper.Storage.InMemory; +using skyscraper8.Skyscraper; using skyscraper8.Skyscraper.Scraper.Storage; namespace skyscraper8 @@ -124,7 +125,25 @@ namespace skyscraper8 rtspClient.AutoReconnect = false; Keepalive(); DiSEqC_Opcode opcode = BuildDiseqcOpcode(); - string url = RtspClient.MakeUrl(opcode, frequency, isS2, symbolRate, null, false); + string url = null; + if (oldconfig != null) + { + url = RtspClient.MakeUrl(oldconfig); + } + else + { + url = RtspClient.MakeUrl(opcode, frequency, isS2, symbolRate, null, false); + } + + if (string.IsNullOrEmpty(url)) + { + logger.Fatal("Somehow I reached a code-path that didn't generate a SAT>IP String. This is a bug, tell Fey."); + return; + } + else + { + logger.DebugFormat("SAT>IP Tuning String: {0}", url); + } RtspDescribeResponse describe = rtspClient.GetDescribe(url); SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); @@ -250,8 +269,36 @@ namespace skyscraper8 private int destinationPort; private bool playoutMode; private bool multicastMode; + private readonly SatIpOldconfig oldconfig; - private void Setup_OnRtcpPacket(byte[] data, int length) + public QuickAndDirtySatIpClient(SatIpOldconfig args) + { + this.oldconfig = args; + + if (args.ServerIp.Equals("auto")) + { + this.ipAddress = this.AutodetectIPAddress(); + } + else + { + this.ipAddress = IPAddress.Parse(args.ServerIp); + } + + this.diseqcNumber = args.Diseqc; + this.polarity = args.Polarity.ToUpperInvariant()[0]; + this.frequency = args.Frequency; + this.isS2 = ParseDvbStandard(args.System); + this.symbolRate = args.SymbolRate; + + //Playout mode + this.destinationPort = args.DestinationPort; + this.playoutMode = true; + this.destinationIp = IPAddress.Parse(args.DestinationIp); + this.multicastMode = true; + } + + + private void Setup_OnRtcpPacket(byte[] data, int length) { //rtcps++; } diff --git a/skyscraper8/SatIp/RtspClient.cs b/skyscraper8/SatIp/RtspClient.cs index 6a6891c..7029829 100644 --- a/skyscraper8/SatIp/RtspClient.cs +++ b/skyscraper8/SatIp/RtspClient.cs @@ -5,10 +5,13 @@ using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using log4net; using skyscraper5.Skyscraper; using skyscraper5.Skyscraper.IO.CrazycatStreamReader; using skyscraper8.SatIp.RtspRequests; using skyscraper8.SatIp.RtspResponses; +using skyscraper8.Skyscraper; +using skyscraper8.Skyscraper.Math; namespace skyscraper8.SatIp { @@ -16,6 +19,8 @@ namespace skyscraper8.SatIp { private uint cseqCounter; private const string USER_AGENT = "sophiaNetRtspClient/1.0"; + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + public RtspClient(string ip, int port) { @@ -339,6 +344,62 @@ namespace skyscraper8.SatIp return sb.ToString(); } + public static string? MakeUrl(SatIpOldconfig config) + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("/?src={0}", config.Diseqc); + sb.AppendFormat("&freq={0}", config.Frequency); + sb.AppendFormat("&pol={0}", config.Polarity.ToLowerInvariant()[0]); + sb.AppendFormat("&msys=dvb{0}", config.System.ToLowerInvariant()); + sb.AppendFormat("&sr={0}", config.SymbolRate); + sb.AppendFormat("&pids=all"); + + string xIsi = null; + int? xPls = null; + if (config.UseDigitalDevicesExtensions) + { + if (config.ForceBbframeOutput) + { + xIsi = "0x80000000"; + } + else if (config.ForceIqOutput) + { + xIsi = "0x10000000"; + } + else if (config.EnableMis) + { + xIsi = config.MisSelection.ToString(); + } + + switch (config.PlsMode) + { + case "none": + break; + case "gold": + xPls = config.PlsValue; + break; + case "root": + xPls = PlsCodeConverter.RootToGold(config.PlsValue); + break; + default: + logger.WarnFormat("Don't know what PLS code Type {0} is, assuming no PLS.",config.PlsMode); + break; + } + } + + if (!string.IsNullOrEmpty(xIsi)) + { + sb.AppendFormat("&x_isi={0}", xIsi); + } + + if (xPls.HasValue) + { + sb.AppendFormat("&x_pls={0}", xPls.Value); + } + + return sb.ToString(); + } + private bool disposed; public void Dispose() { diff --git a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs index bf03811..7ea9c31 100644 --- a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs @@ -33,14 +33,22 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol x => { byte[] addressBytes = x.Address.GetAddressBytes(); - if (addressBytes[0] == 169 || addressBytes.Length != 4) - { - logger.WarnFormat("The address {0} will not be used because it's network type is not supported.", new IPAddress(addressBytes)); - return null; + if (addressBytes[0] == 169 || addressBytes.Length != 4) + { + logger.WarnFormat("The address {0} will not be used because it's network type is not supported.", x.Address); + return null; } Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); temp.Bind(x); - temp.SendTo(Encoding.UTF8.GetBytes(SEARCH_STRING), SocketFlags.None, remoteEndPoint); + try + { + temp.SendTo(Encoding.UTF8.GetBytes(SEARCH_STRING), SocketFlags.None, remoteEndPoint); + } + catch (SocketException e) + { + logger.WarnFormat("The address {0} will not be used because an error occurred when broadcasting the search string: {1}",x.Address,e.Message); + } + return temp; }); @@ -84,10 +92,10 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol { IPInterfaceProperties ipProperties = networkInterface.GetIPProperties(); UnicastIPAddressInformationCollection addresses = ipProperties.UnicastAddresses; - if (addresses.Count == 0) - { - logger.WarnFormat("Network interface {0} does not have an unicast address.", networkInterface.Name); - return IPAddress.Loopback; + if (addresses.Count == 0) + { + logger.WarnFormat("Network interface {0} does not have an unicast address.", networkInterface.Name); + return IPAddress.Loopback; } UnicastIPAddressInformation[] addressArray = addresses.ToArray(); Array.Sort(addressArray, (a, b) => RateIpAddress(b).CompareTo(RateIpAddress(a))); diff --git a/skyscraper8/Skyscraper/Ini.cs b/skyscraper8/Skyscraper/Ini.cs index 35ae392..3088777 100644 --- a/skyscraper8/Skyscraper/Ini.cs +++ b/skyscraper8/Skyscraper/Ini.cs @@ -90,6 +90,19 @@ namespace skyscraper5.Skyscraper return Boolean.Parse(s); } + public ushort ReadValue(string category, string key, ushort defaultVaule) + { + if (!ContainsKey(category)) + return defaultVaule; + + IniSection section = this[category]; + if (!section.ContainsKey(key)) + return defaultVaule; + + string s = section[key]; + return ushort.Parse(s); + } + public int ReadValue(string category, string key, int defaultVaule) { if (!ContainsKey(category)) @@ -103,6 +116,20 @@ namespace skyscraper5.Skyscraper return Int32.Parse(s); } + public byte ReadValue(string category, string key, byte defaultVaule) + { + if (!ContainsKey(category)) + return defaultVaule; + + IniSection section = this[category]; + if (!section.ContainsKey(key)) + return defaultVaule; + + string s = section[key]; + return Byte.Parse(s); + } + + public string ReadValue(string category, string key, string defaultVaule) { if (!ContainsKey(category)) diff --git a/skyscraper8/Skyscraper/Math/PlsCodeConverter.cs b/skyscraper8/Skyscraper/Math/PlsCodeConverter.cs new file mode 100644 index 0000000..8ad4a3d --- /dev/null +++ b/skyscraper8/Skyscraper/Math/PlsCodeConverter.cs @@ -0,0 +1,32 @@ +namespace skyscraper8.Skyscraper.Math; + +public static class PlsCodeConverter +{ + public static int RootToGold(int root) + { + var g = 0; + var X = 1; + for( g = 0; g < 262144; g += 1) + { + if( X == root ) + break; + X = ((( X ^ (X >> 7)) & 1) << 17) | (X >> 1); + } + + return g; + } + + public static int GoldToRoot(int gold) + { + var g = 0; + var X = 1; + for( g = 0; g < 262143; g += 1) + { + if( g == gold ) + break; + X = ((( X ^ (X >> 7)) & 1) << 17) | (X >> 1); + } + + return X; + } +} \ No newline at end of file diff --git a/skyscraper8/Skyscraper/OldconfigEngine.cs b/skyscraper8/Skyscraper/OldconfigEngine.cs new file mode 100644 index 0000000..ba8b65f --- /dev/null +++ b/skyscraper8/Skyscraper/OldconfigEngine.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.IO; + +public enum ConfigType { Bool, Choice, String, ValidatedString } + +// Delegate signature for custom validation functions +public delegate (bool IsValid, string? ErrorMessage) ConfigValidator(string input); + +public class ConfigOption +{ + public string Id { get; set; } + public string Description { get; set; } + public ConfigType Type { get; set; } = ConfigType.Bool; + public string DefaultValue { get; set; } = "y"; + public List Choices { get; set; } = []; + public Func, bool>? Dependency { get; set; } + + // Delegate for string validation rules + public ConfigValidator? Validator { get; set; } + + public ConfigOption() + { + } + + public ConfigOption(string id, string description, ConfigType type, string defaultValue) + { + Id = id; + Description = description; + Type = type; + DefaultValue = defaultValue; + } + + public void SetChoices(params string[] args) + { + Choices = new List(args); + } +} + +public class OldConfigEngine +{ + private readonly List _schema = []; + private readonly Dictionary _currentConfig = []; + + public void RegisterOption(ConfigOption option) => _schema.Add(option); + + public void LoadExistingConfig(string filePath) + { + if (!File.Exists(filePath)) return; + foreach (var line in File.ReadAllLines(filePath)) + { + var trimmed = line.Trim(); + if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith("#")) continue; + var parts = trimmed.Split('=', 2); + if (parts.Length == 2) _currentConfig[parts[0].Trim()] = parts[1].Trim(); + } + } + + public void RunInteractiveConfig() + { + Console.WriteLine("*"); + Console.WriteLine("* Restart config based on current configuration"); + Console.WriteLine("*"); + + foreach (var opt in _schema) + { + if (opt.Dependency != null && !opt.Dependency(_currentConfig)) + continue; + + if (_currentConfig.ContainsKey(opt.Id)) + continue; + + string selectedValue = PromptUser(opt); + _currentConfig[opt.Id] = selectedValue; + } + + Console.WriteLine("\n*** End of configuration. ***"); + } + + public string PromptUser(ConfigOption opt) + { + while (true) + { + switch (opt.Type) + { + case ConfigType.Bool: + string choicesHint = opt.DefaultValue.ToLower() == "y" ? "[Y/n]" : "[y/N]"; + Console.Write($"{opt.Description} ({opt.Id}) {choicesHint} "); + + var key = Console.ReadKey(intercept: false); + Console.WriteLine(); + + if (key.Key == ConsoleKey.Enter) + return opt.DefaultValue; + if (key.Key == ConsoleKey.Y) + return "true"; + if (key.Key == ConsoleKey.N) + return "false"; + if (key.Key == ConsoleKey.Q || key.KeyChar == '?') + { + Console.WriteLine($" Help: Toggles option {opt.Id}. Select Y or N."); + continue; + } + break; + + case ConfigType.Choice: + Console.WriteLine($"{opt.Description} ({opt.Id})"); + for (int i = 0; i < opt.Choices.Count; i++) + { + string marker = opt.Choices[i] == opt.DefaultValue ? " (NEW)" : ""; + Console.WriteLine($" {i + 1}. {opt.Choices[i]}{marker}"); + } + Console.Write($"choice[1-{opt.Choices.Count}]: "); + + string? choiceInput = Console.ReadLine()?.Trim(); + if (string.IsNullOrEmpty(choiceInput)) return opt.DefaultValue; + if (int.TryParse(choiceInput, out int idx) && idx >= 1 && idx <= opt.Choices.Count) + { + return opt.Choices[idx - 1]; + } + break; + + case ConfigType.String: + Console.Write($"{opt.Description} ({opt.Id}) [{opt.DefaultValue}]: "); + string? strInput = Console.ReadLine()?.Trim(); + return string.IsNullOrEmpty(strInput) ? opt.DefaultValue : strInput; + + case ConfigType.ValidatedString: + Console.Write($"{opt.Description} ({opt.Id}) [{opt.DefaultValue}]: "); + string rawVal = Console.ReadLine()?.Trim() ?? string.Empty; + string valueToValidate = string.IsNullOrEmpty(rawVal) ? opt.DefaultValue : rawVal; + + if (opt.Validator != null) + { + var (isValid, errorMessage) = opt.Validator(valueToValidate); + if (!isValid) + { + Console.WriteLine($" [Error] {errorMessage ?? "Invalid value provided."}"); + continue; // Re-prompt on validation failure + } + } + + return valueToValidate; + } + + Console.WriteLine("Invalid choice. Try again."); + } + } + + public void SaveConfig(string filePath) + { + using var writer = new StreamWriter(filePath); + writer.WriteLine($"# Automatically generated config - {DateTime.UtcNow:u}"); + foreach (var kvp in _currentConfig) + { + writer.WriteLine($"{kvp.Key}={kvp.Value}"); + } + } +} \ No newline at end of file diff --git a/skyscraper8/Skyscraper/SatIpOldconfig.cs b/skyscraper8/Skyscraper/SatIpOldconfig.cs new file mode 100644 index 0000000..1484be3 --- /dev/null +++ b/skyscraper8/Skyscraper/SatIpOldconfig.cs @@ -0,0 +1,196 @@ +using System.Net; +using skyscraper5.Skyscraper; +using skyscraper5.Skyscraper.Plugins; +using skyscraper5.Skyscraper.Scraper; + +namespace skyscraper8.Skyscraper; + +public class SatIpOldconfig +{ + private const string INI_CATEGORY = "satip_oldconfig"; + + public string ServerIp { get; private set; } + public int Diseqc{ get; private set; } + public string Polarity{ get; private set; } + public int Frequency{ get; private set; } + public string System{ get; private set; } + public int SymbolRate{ get; private set; } + public bool UseDigitalDevicesExtensions{ get; private set; } + public bool ForceBbframeOutput{ get; private set; } + public bool ForceIqOutput{ get; private set; } + public string PlsMode{ get; private set; } + public int PlsValue{ get; private set; } + public bool EnableMis{ get; private set; } + public byte MisSelection{ get; private set; } + public string DestinationIp{ get; private set; } + public ushort DestinationPort{ get; private set; } + + public void Run() + { + PluginManager pluginManager = PluginManager.GetInstance(); + Ini ini = pluginManager.Ini; + OldConfigEngine configEngine = new OldConfigEngine(); + + ServerIp = ini.ReadValue(INI_CATEGORY, "ip", "auto"); + Diseqc = ini.ReadValue(INI_CATEGORY, "diseqc", 1); + Polarity = ini.ReadValue(INI_CATEGORY, "polarity", "H"); + Frequency = ini.ReadValue(INI_CATEGORY, "frequency", 11523); + System = ini.ReadValue(INI_CATEGORY, "system", "S2"); + SymbolRate = ini.ReadValue(INI_CATEGORY, "symbolRate", 22000); + UseDigitalDevicesExtensions = ini.ReadValue(INI_CATEGORY, "digitalDevicesExtensions", false); + ForceBbframeOutput = ini.ReadValue(INI_CATEGORY, "forceBbframeOutput", false); + ForceIqOutput = ini.ReadValue(INI_CATEGORY, "forceIqOutput", false); + PlsMode = ini.ReadValue(INI_CATEGORY, "plsMode", "none"); + PlsValue = ini.ReadValue(INI_CATEGORY, "plsValue", 131070); + EnableMis = ini.ReadValue(INI_CATEGORY, "misEnabled", false); + MisSelection = ini.ReadValue(INI_CATEGORY, "misSelector", (byte)1); + DestinationIp = ini.ReadValue(INI_CATEGORY, "destinationIp", "239.192.0.1"); + DestinationPort = ini.ReadValue(INI_CATEGORY, "destinationPort", (ushort)6969); + + + ConfigOption ipOption = new ConfigOption("ip", "The IP of the SAT>IP server or \"auto\"", ConfigType.ValidatedString, ServerIp); + ipOption.Validator = validateIpTuple; + ServerIp = configEngine.PromptUser(ipOption); + + ConfigOption diseqcOption = new ConfigOption("diseqc", "DiSEqC Port 1,2,3 or 4?", ConfigType.ValidatedString, Diseqc.ToString()); + diseqcOption.SetChoices("1", "2", "3", "4"); + Diseqc = Int32.Parse(configEngine.PromptUser(diseqcOption)); + + ConfigOption polarityOption = new ConfigOption("polarity", "Polarity H or V?", ConfigType.Choice, Polarity); + polarityOption.SetChoices("H", "V"); + Polarity = configEngine.PromptUser(polarityOption); + + ConfigOption frequencyOption = new ConfigOption("frequency", "Frequency in MHz", ConfigType.ValidatedString, Frequency.ToString()); + frequencyOption.Validator = frequencyValid; + Frequency = Int32.Parse(configEngine.PromptUser(frequencyOption)); + + ConfigOption systemOption = new ConfigOption("system", "Transmission system: S or S2?", ConfigType.Choice, System); + systemOption.SetChoices("S", "S2"); + System = configEngine.PromptUser(systemOption); + + ConfigOption symbolRateOption = new ConfigOption("symbolRate", "Symbol-Rate in k/syms", ConfigType.ValidatedString, SymbolRate.ToString()); + frequencyOption.Validator = frequencyValid; + SymbolRate = Int32.Parse(configEngine.PromptUser(symbolRateOption)); + + ConfigOption ddExtensionsOption = new ConfigOption("ddExtensions", "Use Digital Devices OctopusNET extensions?", ConfigType.Bool, UseDigitalDevicesExtensions.ToString()); + UseDigitalDevicesExtensions = Boolean.Parse(configEngine.PromptUser(ddExtensionsOption)); + + if (UseDigitalDevicesExtensions) + { + ConfigOption forceBbFrameOutputOption = new ConfigOption("forceBbframeOutput", "Force BBFRAME output?", ConfigType.Bool, ForceBbframeOutput.ToString()); + ForceBbframeOutput = Boolean.Parse(configEngine.PromptUser(forceBbFrameOutputOption)); + + if (!ForceBbframeOutput) + { + ConfigOption forceIqOutputOption = new ConfigOption("forceIqOutput", "Output encapsulated IQ data?", ConfigType.Bool, ForceIqOutput.ToString()); + ForceIqOutput = Boolean.Parse(configEngine.PromptUser(forceIqOutputOption)); + } + + ConfigOption plsModeOption = new ConfigOption("plsMode", "Physical Layer Scrambling Mode?", ConfigType.Choice, PlsMode); + plsModeOption.SetChoices("none", "root", "gold"); + PlsMode = configEngine.PromptUser(plsModeOption); + if (!PlsMode.Equals("none")) + { + ConfigOption plsValueOption = new ConfigOption("plsValue", String.Format("{0} code?", PlsMode.ToUpperInvariant()), ConfigType.ValidatedString, PlsValue.ToString()); + plsValueOption.Validator = frequencyValid; + PlsValue = Int32.Parse(configEngine.PromptUser(plsValueOption)); + } + + ConfigOption misEnabledOption = new ConfigOption("misEnabled", "Tune for Multi Input Stream?", ConfigType.Bool, "false"); + EnableMis = Boolean.Parse(configEngine.PromptUser(misEnabledOption)); + if (EnableMis) + { + ConfigOption misSelectorOptions = new ConfigOption("misValue", "Multi Input Stream Selection? (0-255)", ConfigType.ValidatedString, MisSelection.ToString()); + misSelectorOptions.Validator = byteValidator; + MisSelection = Byte.Parse(configEngine.PromptUser(misSelectorOptions)); + } + } + + ConfigOption destIpOption = new ConfigOption("destinationIp", "SAT>IP Multicast destination IP address?",ConfigType.ValidatedString, DestinationIp); + destIpOption.Validator = serverIpValidatorTuple; + DestinationIp = configEngine.PromptUser(destIpOption); + + ConfigOption destPortOption = new ConfigOption("destinationPort", "SAT>IP Multicast destination Port?", ConfigType.ValidatedString, DestinationPort.ToString()); + destPortOption.Validator = destinationTypeValidatorTuple; + DestinationPort = ushort.Parse(configEngine.PromptUser(destPortOption)); + + ini.WriteValue(INI_CATEGORY, "ip", ServerIp); + ini.WriteValue(INI_CATEGORY, "diseqc", Diseqc); + ini.WriteValue(INI_CATEGORY, "polarity", Polarity); + ini.WriteValue(INI_CATEGORY, "frequency", Frequency); + ini.WriteValue(INI_CATEGORY, "system", System); + ini.WriteValue(INI_CATEGORY, "sybolRate", SymbolRate); + ini.WriteValue(INI_CATEGORY, "digitalDevicesExtensions", UseDigitalDevicesExtensions); + ini.WriteValue(INI_CATEGORY, "forceBbframeOutput", ForceBbframeOutput); + ini.WriteValue(INI_CATEGORY, "forceIqOutput", ForceIqOutput); + ini.WriteValue(INI_CATEGORY, "plsMode", PlsMode); + ini.WriteValue(INI_CATEGORY, "plsValue", PlsValue); + ini.WriteValue(INI_CATEGORY, "misEnabled", EnableMis); + ini.WriteValue(INI_CATEGORY, "misSelector", MisSelection); + ini.WriteValue(INI_CATEGORY, "destinationIp", DestinationIp); + ini.WriteValue(INI_CATEGORY, "destinationPort", DestinationPort); + pluginManager.SaveConfiguration(); + Console.WriteLine("Settings saved."); + + QuickAndDirtySatIpClient quickAndDirtySatIpClient = new QuickAndDirtySatIpClient(this); + quickAndDirtySatIpClient.Run(); + } + + private (bool IsValid, string? ErrorMessage) destinationTypeValidatorTuple(string input) + { + ushort number; + bool result = ushort.TryParse(input, out number); + if (!result) + { + return (false, "Port number must be numeric between 1024-65500"); + } + + if (number < 1024) + { + return (false, "Port Number must be above 1023"); + } + + if (number > 65500) + { + return (false, "Port Number must be below 65500"); + } + + return (true, ""); + } + + private (bool IsValid, string? ErrorMessage) serverIpValidatorTuple(string input) + { + if (input.Equals("auto")) + { + return (true, ""); + } + + IPAddress outAddress; + bool result = IPAddress.TryParse(input, out outAddress); + return (result, "Address must either be \"auto\" or a multicast IP address."); + } + + private (bool IsValid, string? ErrorMessage) byteValidator(string input) + { + byte number; + bool result = Byte.TryParse(input, out number); + return (result, "Input must be a number between 0 and 255."); + } + + private (bool IsValid, string? ErrorMessage) frequencyValid(string input) + { + int number; + bool result = Int32.TryParse(input, out number); + return (result, "Must be a natural 32-bit number."); + } + + private (bool IsValid, string? ErrorMessage) validateIpTuple(string input) + { + if (input.Equals("auto")) + return (true,""); + + IPAddress resultAddr = null; + bool result = IPAddress.TryParse(input, out resultAddr); + return (result, "Result must me a valid IPv4 address or \"auto\""); + } +} \ No newline at end of file