From c64a0f5c4620f676e27b082665136e5371750dea Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sun, 9 Nov 2025 12:16:44 +0100 Subject: [PATCH] Can now parse RMT, CMT and TBTP2 from GSE packets. --- skyscraper8/GS/GSE-BFBS/GseL2SHandler.cs | 40 ++++++++++ .../InteractionChannel/GseTableStructure.cs | 4 +- .../InteractionChannelErrorState.cs | 3 +- skyscraper8/InteractionChannel/Model/Cmt.cs | 1 + skyscraper8/InteractionChannel/Model/Rmt.cs | 78 ++++++++++--------- 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/skyscraper8/GS/GSE-BFBS/GseL2SHandler.cs b/skyscraper8/GS/GSE-BFBS/GseL2SHandler.cs index 310e612..0281042 100644 --- a/skyscraper8/GS/GSE-BFBS/GseL2SHandler.cs +++ b/skyscraper8/GS/GSE-BFBS/GseL2SHandler.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using skyscraper5.src.InteractionChannel; +using skyscraper5.src.InteractionChannel.Model; +using skyscraper5.src.InteractionChannel.Model2; using skyscraper8.InteractionChannel; namespace skyscraper8.GS.GSE_BFBS @@ -19,9 +22,46 @@ namespace skyscraper8.GS.GSE_BFBS public void PushPacket(byte[] buffer) { GseTableStructure gseTableStructure = new GseTableStructure(buffer); + if (!gseTableStructure.Valid) + { + Context.Rcs2Output.OnInteractionChannelError(InteractionChannelErrorState.GseTableStructureInvalid); + return; + } + + MemoryStream ms = new MemoryStream(gseTableStructure.TableContent, false); switch (gseTableStructure.TableId) { + case 0x41: + Rmt rmt = new Rmt(ms, true); + if (!rmt.Valid) + { + Context.Rcs2Output.OnInteractionChannelError(InteractionChannelErrorState.RmtInvalid); + return; + } + + Context.Rcs2Output.OnRcsMap(rmt); + return; + case 0xa4: + Cmt cmt = new Cmt(ms); + if (!cmt.Valid) + { + Context.Rcs2Output.OnInteractionChannelError(InteractionChannelErrorState.CmtInvalid); + return; + } + Context.Rcs2Output.OnCorrectionMessage(gseTableStructure.InteractiveNetworkId, cmt); + return; + case 0xad: + Tbtp2 tbtp2 = new Tbtp2(ms); + if (!tbtp2.Valid) + { + Context.Rcs2Output.OnInteractionChannelError(InteractionChannelErrorState.Tbtp2Invalid); + return; + } + Context.Rcs2Output.OnTerminalBurstTimePlan2(gseTableStructure.InteractiveNetworkId, tbtp2); + return; default: + //See en_30154502v010401p.pdf + //page 49 throw new NotImplementedException(String.Format( "Unknown DVB-RCS2 Table Id: 0x{0:X2}\nIf this is reproducible on this stream, please consider submitting me a sample.", gseTableStructure.TableId)); diff --git a/skyscraper8/InteractionChannel/GseTableStructure.cs b/skyscraper8/InteractionChannel/GseTableStructure.cs index 22c3f5c..cc63ea0 100644 --- a/skyscraper8/InteractionChannel/GseTableStructure.cs +++ b/skyscraper8/InteractionChannel/GseTableStructure.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using skyscraper5.Skyscraper; using skyscraper5.Skyscraper.IO; namespace skyscraper8.InteractionChannel @@ -10,7 +11,7 @@ namespace skyscraper8.InteractionChannel /// /// Represents the structure in ETSI EN 301 545-2 V1.4.1, clause 6.4.3.1.1 /// - internal class GseTableStructure + internal class GseTableStructure : Validatable { public GseTableStructure(byte[] buffer) { @@ -23,6 +24,7 @@ namespace skyscraper8.InteractionChannel CurrentNextIndicator = (byteA & 0x01) != 0; TableContent = ms.ReadBytes(ms.GetAvailableBytes()); + Valid = true; } public byte[] TableContent { get; private set; } diff --git a/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs b/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs index ac6faf3..73658b4 100644 --- a/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs +++ b/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs @@ -22,6 +22,7 @@ namespace skyscraper5.src.InteractionChannel Fct2Invalid, Tbtp2Invalid, Tmst2Invalid, - BctInvalid + BctInvalid, + GseTableStructureInvalid } } diff --git a/skyscraper8/InteractionChannel/Model/Cmt.cs b/skyscraper8/InteractionChannel/Model/Cmt.cs index 1bf1067..1c4b648 100644 --- a/skyscraper8/InteractionChannel/Model/Cmt.cs +++ b/skyscraper8/InteractionChannel/Model/Cmt.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using skyscraper5.Mpeg2; namespace skyscraper5.src.InteractionChannel.Model { diff --git a/skyscraper8/InteractionChannel/Model/Rmt.cs b/skyscraper8/InteractionChannel/Model/Rmt.cs index 826493b..c357df6 100644 --- a/skyscraper8/InteractionChannel/Model/Rmt.cs +++ b/skyscraper8/InteractionChannel/Model/Rmt.cs @@ -16,48 +16,51 @@ namespace skyscraper5.src.InteractionChannel.Model { private static TsDescriptorUnpacker tsDescriptorUnpacker; - public Rmt(MemoryStream ms) + public Rmt(MemoryStream ms, bool gseMode = false) { if (tsDescriptorUnpacker == null) tsDescriptorUnpacker = TsDescriptorUnpacker.GetInstance(); - byte tableId = ms.ReadUInt8(); - if (tableId != 0x41) + if (!gseMode) { - Valid = false; - return; + byte tableId = ms.ReadUInt8(); + if (tableId != 0x41) + { + Valid = false; + return; + } + + byte byteA = ms.ReadUInt8(); + bool sectionSyntaxIndicator = (byteA & 0x80) != 1; + if (!sectionSyntaxIndicator) + { + Valid = false; + return; + } + + bool reservedFutureUse = (byteA & 0x40) != 1; + int reserved = (byteA & 0x30) >> 4; + + int sectionLength = (byteA & 0x0f); + sectionLength <<= 8; + sectionLength += ms.ReadUInt8(); + if (sectionLength != ms.GetAvailableBytes()) + { + Valid = false; + return; + } + + NetworkId = ms.ReadUInt16BE(); + + byte byteB = ms.ReadUInt8(); + reserved = (byteB & 0xc0) >> 6; + int versionNumber = (byteB & 0x3e) >> 1; + bool currentNextIndicator = (byteB & 0x01) != 0; + + byte sectionNumber = ms.ReadUInt8(); + byte lastSectionNumber = ms.ReadUInt8(); } - byte byteA = ms.ReadUInt8(); - bool sectionSyntaxIndicator = (byteA & 0x80) != 1; - if (!sectionSyntaxIndicator) - { - Valid = false; - return; - } - - bool reservedFutureUse = (byteA & 0x40) != 1; - int reserved = (byteA & 0x30) >> 4; - - int sectionLength = (byteA & 0x0f); - sectionLength <<= 8; - sectionLength += ms.ReadUInt8(); - if (sectionLength != ms.GetAvailableBytes()) - { - Valid = false; - return; - } - - NetworkId = ms.ReadUInt16BE(); - - byte byteB = ms.ReadUInt8(); - reserved = (byteB & 0xc0) >> 6; - int versionNumber = (byteB & 0x3e) >> 1; - bool currentNextIndicator = (byteB & 0x01) != 0; - - byte sectionNumber = ms.ReadUInt8(); - byte lastSectionNumber = ms.ReadUInt8(); - byte byteC = ms.ReadUInt8(); int reservedFutureUseB = (byteC & 0xf0) >> 4; int networkDescriptorsLength = (byteC & 0x0f); @@ -85,7 +88,8 @@ namespace skyscraper5.src.InteractionChannel.Model Linkages.Add((_0x4a_LinkageDescriptor)descriptor); continue; } - throw new NotImplementedException(); + + throw new NotImplementedException(String.Format("Unknown descriptor 0x{0:X2} in RCS Map Table. If this is reproducible, consider submitting a sample of this stream.")); } byte byteD = ms.ReadUInt8(); @@ -141,7 +145,7 @@ namespace skyscraper5.src.InteractionChannel.Model child.SatelliteReturnLink = (_0xa9_SatelliteReturnLinkDescriptor)descriptor; break; default: - throw new NotImplementedException(); + throw new NotImplementedException(String.Format("Unknown descriptor 0x{0:X2} in RCS Map Table. If this is reproducible, consider submitting a sample of this stream.")); } } }