390 lines
15 KiB
C#
390 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.NetworkInformation;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using skyscraper5.Dvb.Descriptors;
|
|
using skyscraper5.Skyscraper.IO;
|
|
using skyscraper5.Skyscraper.Plugins;
|
|
|
|
namespace skyscraper5.Docsis.MacManagement
|
|
{
|
|
[SkyscraperPlugin]
|
|
[MacManagementMessageType(3, 29)]
|
|
[MacManagementMessageType(5, 51)]
|
|
public class UpstreamChannelDescriptor : MacManagementMessage
|
|
{
|
|
public UpstreamChannelDescriptor(PhysicalAddress source, PhysicalAddress destination, byte[] buffer) : base(source, destination, buffer)
|
|
{
|
|
MemoryStream ms = new MemoryStream(buffer, false);
|
|
UpstreamChannelID = ms.ReadUInt8();
|
|
ConfigurationChangeCount = ms.ReadUInt8();
|
|
MinislotSize = ms.ReadUInt8();
|
|
DownstreamChannelId = ms.ReadUInt8();
|
|
|
|
while (ms.GetAvailableBytes() >= 2)
|
|
{
|
|
byte type = ms.ReadUInt8();
|
|
byte length = ms.ReadUInt8();
|
|
if (ms.GetAvailableBytes() < length)
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
byte[] v = ms.ReadBytes(length);
|
|
switch (type)
|
|
{
|
|
//Found in CM-SP-MULPIv3.1-I03-1406101.pdf on page 107
|
|
case 1:
|
|
ModulationRate = v[0];
|
|
break;
|
|
case 2:
|
|
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
|
|
Frequency = BitConverter.ToUInt32(v);
|
|
break;
|
|
case 3:
|
|
PreamblePattern = v;
|
|
break;
|
|
case 5:
|
|
if (BurstDescriptors == null)
|
|
BurstDescriptors = new List<BurstDescriptor>();
|
|
BurstDescriptors.Add(new BurstDescriptor(v));
|
|
break;
|
|
case 6:
|
|
ExtendedPreamblePattern = v;
|
|
break;
|
|
case 7:
|
|
if (v[0] == 1) S_CDMAMode = true;
|
|
else if (v[0] == 2) S_CDMAMode = false;
|
|
else break;
|
|
break;
|
|
case 15:
|
|
//Undocumented as of DOCSIS 4.0 ?
|
|
break;
|
|
case 16:
|
|
RangingRequired = (RangingRequiredEnum)v[0];
|
|
break;
|
|
case 23:
|
|
goto case 5;
|
|
case 24:
|
|
(v[0], v[1]) = (v[1], v[0]);
|
|
UcdChangeIndicator = new UcdChangeIndicatorBitmask(BitConverter.ToUInt16(v, 0));
|
|
break;
|
|
case 25:
|
|
OfdmaTimestampSnapshot = v[0] & 0x0f;
|
|
OfdmaTimestampSnapshot <<= 8; //4 bits
|
|
OfdmaTimestampSnapshot += v[1];
|
|
OfdmaTimestampSnapshot <<= 8; //12 bits
|
|
OfdmaTimestampSnapshot += v[2];
|
|
OfdmaTimestampSnapshot <<= 8; //20 bits
|
|
OfdmaTimestampSnapshot += v[3];
|
|
OfdmaTimestampSnapshot <<= 4; //28 bits
|
|
OfdmaTimestampSnapshot += ((v[4] & 0xf0) >> 4);
|
|
OfdmaTimestampSnapshotDivideBy20 = v[4] & 0x0f;
|
|
break;
|
|
case 26:
|
|
OfdmaCyclicPrefixSize = v[0];
|
|
break;
|
|
case 27:
|
|
OfdmaRolloffPeriodSize = v[0];
|
|
break;
|
|
case 28:
|
|
SubcarrierSpacing = v[0];
|
|
break;
|
|
case 29:
|
|
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
|
|
CenterFrequencyOfSubcarrier0 = BitConverter.ToUInt32(v);
|
|
break;
|
|
case 30:
|
|
SubcarrierExclusionBand = new Tuple<ushort, ushort>[length / 4];
|
|
for (int i = 0; i < length / 4; i++)
|
|
{
|
|
(v[(i * 4) + 0], v[(i * 4) + 1]) = (v[(i * 4) + 1], v[(i * 4) + 0]);
|
|
(v[(i * 4) + 2], v[(i * 4) + 3]) = (v[(i * 4) + 3], v[(i * 4) + 2]);
|
|
SubcarrierExclusionBand[i] = new Tuple<ushort, ushort>(BitConverter.ToUInt16(v, (i * 4) + 0), BitConverter.ToUInt16(v, (i * 4) + 2));
|
|
}
|
|
break;
|
|
case 32:
|
|
SymbolsInOfdmaFrame = v[0];
|
|
break;
|
|
case 33:
|
|
byte[] v2 = new byte[4];
|
|
(v2[0], v2[1], v2[2]) = (v[2], v[1], v[0]);
|
|
RandomizationSeed = BitConverter.ToUInt32(v2, 0);
|
|
break;
|
|
default:
|
|
if (type > 34)
|
|
{
|
|
Valid = false;
|
|
return;
|
|
}
|
|
throw new NotImplementedException(String.Format("{0} TLV type {1}", nameof(UpstreamChannelDescriptor), type));
|
|
|
|
}
|
|
}
|
|
Valid = true;
|
|
}
|
|
|
|
public uint RandomizationSeed { get; set; }
|
|
|
|
public byte? SymbolsInOfdmaFrame { get; set; }
|
|
|
|
public Tuple<ushort, ushort>[] SubcarrierExclusionBand { get; private set; }
|
|
|
|
public uint? CenterFrequencyOfSubcarrier0 { get; set; }
|
|
|
|
public byte? SubcarrierSpacing { get; set; }
|
|
|
|
public byte? OfdmaRolloffPeriodSize { get; set; }
|
|
|
|
public byte? OfdmaCyclicPrefixSize { get; set; }
|
|
|
|
public int? OfdmaTimestampSnapshotDivideBy20 { get; set; }
|
|
|
|
public int? OfdmaTimestampSnapshot { get; set; }
|
|
|
|
public UcdChangeIndicatorBitmask UcdChangeIndicator { get; private set; }
|
|
|
|
public List<BurstDescriptor> BurstDescriptors { get; private set; }
|
|
|
|
public bool? S_CDMAMode { get; set; }
|
|
|
|
public byte[] PreamblePattern { get; set; }
|
|
|
|
public uint? Frequency { get; set; }
|
|
|
|
public byte? ModulationRate { get; set; }
|
|
|
|
public byte DownstreamChannelId { get; set; }
|
|
|
|
public byte MinislotSize { get; set; }
|
|
|
|
public byte ConfigurationChangeCount { get; set; }
|
|
|
|
public byte UpstreamChannelID { get; set; }
|
|
|
|
public byte[] ExtendedPreamblePattern { get; private set; }
|
|
|
|
public RangingRequiredEnum RangingRequired { get; private set; }
|
|
|
|
public enum RangingRequiredEnum : byte
|
|
{
|
|
NoRangingRequired = 0,
|
|
UnicastInitialRangingRequired = 1,
|
|
BroadcastInitialRangingRequired = 2,
|
|
ProbingRequired = 3
|
|
}
|
|
|
|
|
|
public class BurstDescriptor
|
|
{
|
|
public BurstDescriptor(byte[] buffer)
|
|
{
|
|
MemoryStream ms = new MemoryStream(buffer, false);
|
|
IntervalUsageCode = ms.ReadUInt8();
|
|
while (ms.GetAvailableBytes() > 2)
|
|
{
|
|
byte type = ms.ReadUInt8();
|
|
byte length = ms.ReadUInt8();
|
|
byte[] v = ms.ReadBytes(length);
|
|
switch (type)
|
|
{
|
|
//Found in CM-SP-MULPIv4.0-I01-190815.pdf, page 118
|
|
case 1:
|
|
ModulationType = v[0];
|
|
break;
|
|
case 2:
|
|
if (v[0] == 1)
|
|
DifferentialEncoding = true;
|
|
else if (v[0] == 2)
|
|
DifferentialEncoding = false;
|
|
else
|
|
break;
|
|
break;
|
|
case 3:
|
|
(v[1], v[0]) = (v[0], v[1]);
|
|
PreambleLength = BitConverter.ToUInt16(v, 0);
|
|
break;
|
|
case 4:
|
|
(v[1], v[0]) = (v[0], v[1]);
|
|
PreambleValueOffset = BitConverter.ToUInt16(v, 0);
|
|
break;
|
|
case 5:
|
|
FecErrorCorrection = v[0];
|
|
break;
|
|
case 6:
|
|
FecCodewordInformationBytes = v[0];
|
|
break;
|
|
case 7:
|
|
(v[1], v[0]) = (v[0], v[1]);
|
|
ScramblerSeed = BitConverter.ToUInt16(v, 0);
|
|
ScramblerSeed &= 0x7fff;
|
|
break;
|
|
case 8:
|
|
MaximumBurstSize = v[0];
|
|
break;
|
|
case 9:
|
|
GuardTimeSize = v[0];
|
|
break;
|
|
case 10:
|
|
LastCodewordLength = (CodewordLength)v[0];
|
|
break;
|
|
case 11:
|
|
if (v[0] == 1)
|
|
Scrambler = true;
|
|
else if (v[0] == 2)
|
|
Scrambler = false;
|
|
else
|
|
break;
|
|
break;
|
|
case 12:
|
|
RsInterleaverDepth = v[0];
|
|
break;
|
|
case 13:
|
|
(v[1], v[0]) = (v[0], v[1]);
|
|
RsInterleaverBlockSize = BitConverter.ToUInt16(v, 0);
|
|
break;
|
|
case 14:
|
|
PreambleType = (PreambleTypeEnum)v[0];
|
|
break;
|
|
case 19:
|
|
(v[1], v[0]) = (v[0], v[1]);
|
|
SubcarriersInitialRanging = BitConverter.ToUInt16(v, 0);
|
|
break;
|
|
case 20:
|
|
(v[1], v[0]) = (v[0], v[1]);
|
|
SubcarriersFineRanging = BitConverter.ToUInt16(v, 0);
|
|
break;
|
|
case 21:
|
|
OfdmaDataProfiles = new OfdmaDataProfile[length / 2];
|
|
for (int i = 0; i < length / 2; i++)
|
|
{
|
|
OfdmaDataProfiles[i] = new OfdmaDataProfile(v[(i * 2) + 0], v[(i * 2) + 1]);
|
|
}
|
|
break;
|
|
case 22:
|
|
OfdmaBroadcastIrStartingPowerLevel = (double)v[0] * 1.6;
|
|
OfdmaBroadcastIrStartingPowerLevelIncrease = (double)v[1] * 0.25;
|
|
break;
|
|
default:
|
|
throw new NotImplementedException(String.Format("{0} {1} {2}", nameof(BurstDescriptor), nameof(type), type));
|
|
}
|
|
}
|
|
}
|
|
|
|
public OfdmaDataProfile[] OfdmaDataProfiles { get; private set; }
|
|
|
|
public ushort? SubcarriersFineRanging { get; set; }
|
|
|
|
public double? OfdmaBroadcastIrStartingPowerLevelIncrease { get; set; }
|
|
public double? OfdmaBroadcastIrStartingPowerLevel { get; set; }
|
|
|
|
public ushort? SubcarriersInitialRanging { get; set; }
|
|
|
|
public PreambleTypeEnum? PreambleType { get; private set; }
|
|
public enum PreambleTypeEnum : byte
|
|
{
|
|
QPSK0 = 1,
|
|
QPSK1 = 2
|
|
}
|
|
|
|
public ushort? RsInterleaverBlockSize { get; set; }
|
|
|
|
public byte? RsInterleaverDepth { get; set; }
|
|
|
|
public bool? Scrambler { get; set; }
|
|
|
|
public CodewordLength? LastCodewordLength { get; set; }
|
|
public enum CodewordLength : byte
|
|
{
|
|
Fixed = 1,
|
|
Shortened = 2
|
|
}
|
|
|
|
public byte? GuardTimeSize { get; set; }
|
|
|
|
public byte? MaximumBurstSize { get; set; }
|
|
|
|
public int? ScramblerSeed { get; set; }
|
|
|
|
public byte? FecCodewordInformationBytes { get; set; }
|
|
|
|
public byte? FecErrorCorrection { get; set; }
|
|
|
|
public ushort? PreambleValueOffset { get; set; }
|
|
|
|
public ushort? PreambleLength { get; set; }
|
|
|
|
public bool? DifferentialEncoding { get; set; }
|
|
|
|
public byte? ModulationType { get; set; }
|
|
|
|
public byte IntervalUsageCode { get; set; }
|
|
}
|
|
|
|
public class UcdChangeIndicatorBitmask
|
|
{
|
|
private readonly ushort rawValue;
|
|
|
|
public UcdChangeIndicatorBitmask(ushort readUInt16Be)
|
|
{
|
|
this.rawValue = readUInt16Be;
|
|
}
|
|
|
|
public bool ChangeIuc14 => (rawValue & 0x0020) != 0;
|
|
public bool ChangeIuc13 => (rawValue & 0x0040) != 0;
|
|
public bool ChangeIuc12 => (rawValue & 0x0080) != 0;
|
|
public bool ChangeIuc11 => (rawValue & 0x0100) != 0;
|
|
public bool ChangeIuc10 => (rawValue & 0x0200) != 0;
|
|
public bool ChangeIuc9 => (rawValue & 0x0400) != 0;
|
|
public bool ChangeIuc6 => (rawValue & 0x0800) != 0;
|
|
public bool ChangeIuc5 => (rawValue & 0x1000) != 0;
|
|
public bool ChangeOtherParameters => (rawValue & 0x2000) != 0;
|
|
public bool ChangeUnusedSubcarrierSpecification => (rawValue & 0x4000) != 0;
|
|
public bool ChangeSubcarrierExclusionBand => (rawValue & 0x8000) != 0;
|
|
|
|
public ushort GetRawValue()
|
|
{
|
|
return rawValue;
|
|
}
|
|
}
|
|
|
|
public class OfdmaDataProfile
|
|
{
|
|
private readonly byte first;
|
|
private readonly byte second;
|
|
|
|
public OfdmaDataProfile(byte first, byte second)
|
|
{
|
|
this.first = first;
|
|
this.second = second;
|
|
}
|
|
|
|
public ModulationOrderIndex Modulation => (ModulationOrderIndex)((first & 0xf0) >> 4);
|
|
|
|
public int PilotPatternIndex => (first & 0x0f);
|
|
|
|
public byte NumberOfMinisolts => second;
|
|
|
|
public enum ModulationOrderIndex
|
|
{
|
|
NoBitLoading,
|
|
Reserved,
|
|
QPSK,
|
|
_8QAM,
|
|
_16QAM,
|
|
_32QAM,
|
|
_64QAM,
|
|
_128QAM,
|
|
_256QAM,
|
|
_512QAM,
|
|
_1024QAM,
|
|
_2048QAM,
|
|
_4096QAM
|
|
}
|
|
}
|
|
}
|
|
}
|