You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
441 lines
17 KiB
441 lines
17 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace LTEMvcApp.Models
|
|
{
|
|
/// <summary>
|
|
/// LTE能力解析器
|
|
/// </summary>
|
|
public class LTECapabilities
|
|
{
|
|
public string UEId { get; set; }
|
|
public List<BandInfo> Bands { get; set; } = new List<BandInfo>();
|
|
public int? Category { get; set; }
|
|
public int? CategoryDL { get; set; }
|
|
public int? CategoryUL { get; set; }
|
|
public List<Dictionary<string, object>> ASN1Data { get; set; } = new List<Dictionary<string, object>>();
|
|
public Dictionary<string, object> BandCombinations { get; set; } = new Dictionary<string, object>();
|
|
public List<List<BandCombinationInfo>> CA { get; set; }
|
|
public List<BandInfo> NRBands { get; set; }
|
|
public string VoNR { get; set; }
|
|
public List<List<BandCombinationInfo>> MRDC { get; set; }
|
|
|
|
private List<string[]> _pendingData = new List<string[]>();
|
|
private int _count = 0;
|
|
|
|
public static readonly Dictionary<string, int> UE_CAPS_MIMO = new Dictionary<string, int>
|
|
{
|
|
["twoLayers"] = 2,
|
|
["fourLayers"] = 4,
|
|
["eightLayers"] = 8
|
|
};
|
|
|
|
/// <summary>
|
|
/// 获取类别信息
|
|
/// </summary>
|
|
public string GetCategory()
|
|
{
|
|
var cat = new List<string>();
|
|
if (CategoryDL.HasValue)
|
|
cat.Add($"DL={CategoryDL}");
|
|
if (CategoryUL.HasValue)
|
|
cat.Add($"UL={CategoryUL}");
|
|
|
|
if (cat.Count > 0)
|
|
return string.Join(", ", cat);
|
|
|
|
if (Category.HasValue)
|
|
return Category.ToString();
|
|
|
|
return "?";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加待解析数据
|
|
/// </summary>
|
|
public void Add(string[] data)
|
|
{
|
|
if (data != null && data.Length > 0)
|
|
{
|
|
_pendingData.Add(data);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析所有待处理数据
|
|
/// </summary>
|
|
public LTECapabilities Parse()
|
|
{
|
|
while (_pendingData.Count > 0)
|
|
{
|
|
_count++;
|
|
ParseASN1(ASN1Parser.FromGSER(_pendingData[0]));
|
|
_pendingData.RemoveAt(0);
|
|
}
|
|
return _count > 0 ? this : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析ASN1数据
|
|
/// </summary>
|
|
private void ParseASN1(Dictionary<string, object> asn1)
|
|
{
|
|
if (asn1 == null) return;
|
|
|
|
ASN1Data.Add(asn1);
|
|
|
|
var ratList = ASN1Parser.Dig(asn1, "ueCapabilityInformation", "ueCapabilityInformation-r8", "ue-CapabilityRAT-ContainerList") as List<object> ?? new List<object>();
|
|
var ratList1 = ASN1Parser.Dig(asn1, "ueCapabilityInformation", "ueCapabilityInformation", "ue-CapabilityRAT-ContainerList") as List<object>;
|
|
|
|
if (ratList1 != null)
|
|
{
|
|
ratList.AddRange(ratList1);
|
|
}
|
|
|
|
foreach (var rat in ratList)
|
|
{
|
|
if (rat is Dictionary<string, object> ratDict)
|
|
{
|
|
var ratType = ratDict.GetValueOrDefault("rat-Type")?.ToString();
|
|
var container = ratDict.GetValueOrDefault("ueCapabilityRAT-Container") ?? ratDict.GetValueOrDefault("ue-CapabilityRAT-Container");
|
|
|
|
switch (ratType)
|
|
{
|
|
case "eutra":
|
|
ParseRatEUTRA(container as Dictionary<string, object>);
|
|
break;
|
|
case "nr":
|
|
ParseRatNR(container as Dictionary<string, object>);
|
|
break;
|
|
case "eutra-nr":
|
|
ParseRatEUTRA_NR(container as Dictionary<string, object>);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Category == null)
|
|
{
|
|
ParseR13(asn1);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析R13版本
|
|
/// </summary>
|
|
private void ParseR13(Dictionary<string, object> asn1)
|
|
{
|
|
var root = ASN1Parser.Dig(asn1, "ueCapabilityInformation-r13", "ueCapabilityInformation-r13", "ue-Capability-Container-r13") as Dictionary<string, object>;
|
|
if (root != null)
|
|
{
|
|
// Category
|
|
if (root.ContainsKey("ue-Category-NB-r13"))
|
|
{
|
|
Category = Convert.ToInt32(root["ue-Category-NB-r13"]);
|
|
}
|
|
|
|
var bands = ASN1Parser.Dig(root, "rf-Parameters-r13", "supportedBandList-r13") as List<object>;
|
|
if (bands != null)
|
|
{
|
|
var mappedBands = ASN1Parser.Map<BandInfo>(bands, b =>
|
|
{
|
|
if (b is Dictionary<string, object> bandDict)
|
|
{
|
|
return new BandInfo { Band = Convert.ToInt32(bandDict["band-r13"]) };
|
|
}
|
|
return new BandInfo();
|
|
});
|
|
|
|
if (mappedBands != null && mappedBands.Count > 0)
|
|
{
|
|
//Bands = mappedBands.Cast<BandInfo>().ToList();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析EUTRA RAT
|
|
/// </summary>
|
|
private void ParseRatEUTRA(Dictionary<string, object> asn1)
|
|
{
|
|
if (asn1 == null) return;
|
|
|
|
if (asn1.ContainsKey("ue-Category"))
|
|
{
|
|
Category = Convert.ToInt32(asn1["ue-Category"]);
|
|
}
|
|
|
|
var mimo = 1;
|
|
if (Category >= 5)
|
|
{
|
|
mimo = 4;
|
|
}
|
|
else if (Category >= 2)
|
|
{
|
|
mimo = 2;
|
|
}
|
|
|
|
// Bands
|
|
var extBands = new List<int>();
|
|
var bands = ASN1Parser.Dig(asn1, "rf-Parameters", "supportedBandListEUTRA") as List<object>;
|
|
if (bands != null)
|
|
{
|
|
var mappedBands = ASN1Parser.Map<BandInfo>(bands, (b, i) =>
|
|
{
|
|
if (b is Dictionary<string, object> bandDict)
|
|
{
|
|
var band = Convert.ToInt32(bandDict["bandEUTRA"]);
|
|
if (band == 64)
|
|
{
|
|
extBands.Add(i);
|
|
}
|
|
return new BandInfo { Band = band };
|
|
}
|
|
return new BandInfo();
|
|
});
|
|
|
|
if (mappedBands != null && mappedBands.Count > 0)
|
|
{
|
|
//Bands = mappedBands.Cast<BandInfo>().ToList();
|
|
var ext = ASN1Parser.Dig(asn1, 2, "nonCriticalExtension", "lateNonCriticalExtension", 3, "nonCriticalExtension", "rf-Parameters-v9e0", "supportedBandListEUTRA-v9e0") as List<object>;
|
|
if (ext != null)
|
|
{
|
|
foreach (var b in extBands)
|
|
{
|
|
if (b < ext.Count && ext[b] is Dictionary<string, object> extBand)
|
|
{
|
|
Bands[b].Band = Convert.ToInt32(extBand["bandEUTRA-v9e0"]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// CA
|
|
var ca = ASN1Parser.Dig(asn1, 2, "nonCriticalExtension") as Dictionary<string, object>;
|
|
if (ca != null)
|
|
{
|
|
try
|
|
{
|
|
extBands.Clear();
|
|
var ca1 = ca.GetValueOrDefault("nonCriticalExtension") as Dictionary<string, object>;
|
|
if (ca1 != null)
|
|
{
|
|
if (ca1.ContainsKey("ue-Category-v1020"))
|
|
{
|
|
Category = Convert.ToInt32(ca1["ue-Category-v1020"]);
|
|
}
|
|
|
|
var rfParams = ca1.GetValueOrDefault("rf-Parameters-v1020") as Dictionary<string, object>;
|
|
if (rfParams != null)
|
|
{
|
|
var supportedBandComb = rfParams.GetValueOrDefault("supportedBandCombination-r10") as List<object>;
|
|
if (supportedBandComb != null)
|
|
{
|
|
CA = ASN1Parser.Map<List<BandCombinationInfo>>(supportedBandComb, (c0, i0) =>
|
|
{
|
|
if (c0 is List<object> c0List)
|
|
{
|
|
return ASN1Parser.Map<BandCombinationInfo>(c0List, (c1, i1) =>
|
|
{
|
|
if (c1 is Dictionary<string, object> c1Dict)
|
|
{
|
|
var band = Convert.ToInt32(c1Dict["bandEUTRA-r10"]);
|
|
if (band == 64)
|
|
{
|
|
//extBands.Add(new[] { i0, i1 });
|
|
}
|
|
|
|
var dl = c1Dict.GetValueOrDefault("bandParametersDL-r10") as List<object>;
|
|
var ul = c1Dict.GetValueOrDefault("bandParametersUL-r10") as List<object>;
|
|
|
|
var result = new BandCombinationInfo
|
|
{
|
|
Band = band,
|
|
MIMO = mimo
|
|
};
|
|
|
|
if (dl != null && dl.Count > 0 && dl[0] is Dictionary<string, object> dlDict)
|
|
{
|
|
result.DL = dlDict.GetValueOrDefault("ca-BandwidthClassDL-r10")?.ToString();
|
|
if (dlDict.ContainsKey("supportedMIMO-CapabilityDL-r10"))
|
|
{
|
|
var mimoCap = dlDict["supportedMIMO-CapabilityDL-r10"].ToString();
|
|
result.MIMO_9_10 = UE_CAPS_MIMO.GetValueOrDefault(mimoCap, mimo);
|
|
}
|
|
}
|
|
|
|
if (ul != null && ul.Count > 0 && ul[0] is Dictionary<string, object> ulDict)
|
|
{
|
|
result.UL = ulDict.GetValueOrDefault("ca-BandwidthClassUL-r10")?.ToString();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
return new BandCombinationInfo();
|
|
});
|
|
}
|
|
return new List<BandCombinationInfo>();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
|
|
if (Bands != null && Bands.Count > 0)
|
|
{
|
|
//Bands = Bands.OrderBy(b => b.Band).ToList();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析NR RAT
|
|
/// </summary>
|
|
private void ParseRatNR(Dictionary<string, object> asn1)
|
|
{
|
|
if (asn1 == null) return;
|
|
|
|
// Bands
|
|
var bands = ASN1Parser.Dig(asn1, "rf-Parameters", "supportedBandListNR") as List<object>;
|
|
if (bands != null)
|
|
{
|
|
var mappedBands = ASN1Parser.Map<BandInfo>(bands, b =>
|
|
{
|
|
if (b is Dictionary<string, object> bandDict)
|
|
{
|
|
return new BandInfo { Band = Convert.ToInt32(bandDict["bandNR"]) };
|
|
}
|
|
return new BandInfo();
|
|
});
|
|
|
|
if (mappedBands != null && mappedBands.Count > 0)
|
|
{
|
|
NRBands = mappedBands;
|
|
}
|
|
}
|
|
|
|
// VoNR
|
|
var v1540 = ASN1Parser.Dig(asn1, 2, "nonCriticalExtension") as Dictionary<string, object>;
|
|
if (v1540 != null)
|
|
{
|
|
var vonr = new List<string>();
|
|
if (ASN1Parser.Dig(v1540, "ims-Parameters", "ims-ParametersFRX-Diff", "voiceOverNR")?.ToString() == "supported")
|
|
{
|
|
vonr.AddRange(new[] { "FR1", "FR2" });
|
|
}
|
|
else
|
|
{
|
|
if (ASN1Parser.Dig(v1540, "fr1-Add-UE-NR-Capabilities-v1540", "ims-ParametersFRX-Diff", "voiceOverNR")?.ToString() == "supported")
|
|
vonr.Add("FR1");
|
|
if (ASN1Parser.Dig(v1540, "fr2-Add-UE-NR-Capabilities-v1540", "ims-ParametersFRX-Diff", "voiceOverNR")?.ToString() == "supported")
|
|
vonr.Add("FR2");
|
|
}
|
|
if (vonr.Count > 0)
|
|
{
|
|
VoNR = string.Join(", ", vonr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析EUTRA-NR RAT
|
|
/// </summary>
|
|
private void ParseRatEUTRA_NR(Dictionary<string, object> asn1)
|
|
{
|
|
if (asn1 == null) return;
|
|
|
|
var bands = ASN1Parser.Dig(asn1, "rf-ParametersMRDC", "supportedBandCombinationList") as List<object>;
|
|
if (bands != null)
|
|
{
|
|
MRDC = ASN1Parser.Map<List<BandCombinationInfo>>(bands, band =>
|
|
{
|
|
if (band is Dictionary<string, object> bandDict)
|
|
{
|
|
var bl = bandDict.GetValueOrDefault("bandList") as Dictionary<string, object>;
|
|
if (bl != null)
|
|
{
|
|
var result = new List<BandCombinationInfo>();
|
|
|
|
var nr = bl.GetValueOrDefault("nr") as List<object>;
|
|
if (nr != null)
|
|
{
|
|
result.AddRange(ASN1Parser.Map<BandCombinationInfo>(nr, b =>
|
|
{
|
|
if (b is Dictionary<string, object> bDict)
|
|
{
|
|
return new BandCombinationInfo
|
|
{
|
|
Band = Convert.ToInt32(bDict["bandNR"]),
|
|
BandType = "NR",
|
|
DL = bDict.GetValueOrDefault("ca-BandwidthClassDL-NR")?.ToString(),
|
|
UL = bDict.GetValueOrDefault("ca-BandwidthClassUL-NR")?.ToString()
|
|
};
|
|
}
|
|
return new BandCombinationInfo();
|
|
}));
|
|
}
|
|
|
|
var eutra = bl.GetValueOrDefault("eutra") as List<object>;
|
|
if (eutra != null)
|
|
{
|
|
result.AddRange(ASN1Parser.Map<BandCombinationInfo>(eutra, b =>
|
|
{
|
|
if (b is Dictionary<string, object> bDict)
|
|
{
|
|
return new BandCombinationInfo
|
|
{
|
|
Band = Convert.ToInt32(bDict["bandEUTRA"]),
|
|
DL = bDict.GetValueOrDefault("ca-BandwidthClassDL-EUTRA")?.ToString(),
|
|
UL = bDict.GetValueOrDefault("ca-BandwidthClassUL-EUTRA")?.ToString()
|
|
};
|
|
}
|
|
return new BandCombinationInfo();
|
|
}));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
return new List<BandCombinationInfo>();
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置频段组合
|
|
/// </summary>
|
|
public void SetBandComb(Dictionary<string, object> json, string ratType)
|
|
{
|
|
BandCombinations[ratType] = json;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 频段信息
|
|
/// </summary>
|
|
public class BandInfo
|
|
{
|
|
public int Band { get; set; }
|
|
public bool DL256QAM { get; set; }
|
|
public string BandType { get; set; } = "LTE";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 频段组合信息
|
|
/// </summary>
|
|
public class BandCombinationInfo
|
|
{
|
|
public int Band { get; set; }
|
|
public string DL { get; set; }
|
|
public string UL { get; set; }
|
|
public int MIMO { get; set; }
|
|
public int? MIMO_9_10 { get; set; }
|
|
public bool MIMO4_3_4 { get; set; }
|
|
public string BandType { get; set; } = "LTE";
|
|
}
|
|
}
|