Browse Source

dasdad1

feature/log-detailed-types
root 1 month ago
parent
commit
bdb79e8f65
  1. 270
      LTEMvcApp/Models/ASN1Extensions.cs
  2. 365
      LTEMvcApp/Models/ASN1Parser.cs
  3. 441
      LTEMvcApp/Models/LTECapabilities.cs
  4. 3
      LTEMvcApp/Models/LTEClient.cs
  5. 11
      LTEMvcApp/Models/StatisticsData.cs

270
LTEMvcApp/Models/ASN1Extensions.cs

@ -0,0 +1,270 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace LTEMvcApp.Models
{
/// <summary>
/// ASN1扩展方法
/// </summary>
public static class ASN1Extensions
{
/// <summary>
/// 安全获取字典值
/// </summary>
public static T GetValueOrDefault<T>(this Dictionary<string, object> dict, string key, T defaultValue = default(T))
{
if (dict != null && dict.ContainsKey(key))
{
try
{
return (T)Convert.ChangeType(dict[key], typeof(T));
}
catch
{
return defaultValue;
}
}
return defaultValue;
}
/// <summary>
/// 安全获取字典值
/// </summary>
public static object GetValueOrDefault(this Dictionary<string, object> dict, string key)
{
return dict?.ContainsKey(key) == true ? dict[key] : null;
}
/// <summary>
/// 将对象转换为字典
/// </summary>
public static Dictionary<string, object> ToDictionary(this object obj)
{
if (obj is Dictionary<string, object> dict)
return dict;
if (obj is IDictionary<string, object> idict)
return new Dictionary<string, object>(idict);
return null;
}
/// <summary>
/// 将对象转换为列表
/// </summary>
public static List<object> ToList(this object obj)
{
if (obj is List<object> list)
return list;
if (obj is IEnumerable<object> enumerable)
return enumerable.ToList();
return null;
}
/// <summary>
/// 安全转换为整数
/// </summary>
public static int? ToInt32(this object obj)
{
if (obj == null) return null;
try
{
return Convert.ToInt32(obj);
}
catch
{
return null;
}
}
/// <summary>
/// 安全转换为字符串
/// </summary>
public static string ToSafeString(this object obj)
{
return obj?.ToString();
}
/// <summary>
/// 安全转换为布尔值
/// </summary>
public static bool? ToBoolean(this object obj)
{
if (obj == null) return null;
try
{
return Convert.ToBoolean(obj);
}
catch
{
return null;
}
}
}
/// <summary>
/// ASN1工具类
/// </summary>
public static class ASN1Utils
{
/// <summary>
/// 创建ASN1对象
/// </summary>
public static Dictionary<string, object> CreateASN1Object()
{
return new Dictionary<string, object>();
}
/// <summary>
/// 创建ASN1数组
/// </summary>
public static List<object> CreateASN1Array()
{
return new List<object>();
}
/// <summary>
/// 添加属性到ASN1对象
/// </summary>
public static void AddProperty(Dictionary<string, object> obj, string name, object value)
{
if (obj == null) return;
if (string.IsNullOrEmpty(name))
{
if (obj.ContainsKey(""))
{
var existing = obj[""];
if (existing is List<object> list)
{
list.Add(value);
}
else
{
obj[""] = new List<object> { existing, value };
}
}
else
{
obj[""] = new List<object> { value };
}
}
else
{
if (obj.ContainsKey(name))
{
var existing = obj[name];
if (existing is List<object> list)
{
list.Add(value);
}
else
{
obj[name] = new List<object> { existing, value };
}
}
else
{
obj[name] = value;
}
}
}
/// <summary>
/// 添加元素到ASN1数组
/// </summary>
public static void AddElement(List<object> array, object value)
{
array?.Add(value);
}
/// <summary>
/// 深度克隆ASN1对象
/// </summary>
public static Dictionary<string, object> DeepClone(Dictionary<string, object> obj)
{
if (obj == null) return null;
var result = new Dictionary<string, object>();
foreach (var kvp in obj)
{
if (kvp.Value is Dictionary<string, object> dict)
{
result[kvp.Key] = DeepClone(dict);
}
else if (kvp.Value is List<object> list)
{
result[kvp.Key] = DeepCloneList(list);
}
else
{
result[kvp.Key] = kvp.Value;
}
}
return result;
}
/// <summary>
/// 深度克隆ASN1数组
/// </summary>
public static List<object> DeepCloneList(List<object> list)
{
if (list == null) return null;
var result = new List<object>();
foreach (var item in list)
{
if (item is Dictionary<string, object> dict)
{
result.Add(DeepClone(dict));
}
else if (item is List<object> subList)
{
result.Add(DeepCloneList(subList));
}
else
{
result.Add(item);
}
}
return result;
}
/// <summary>
/// 将ASN1对象转换为JSON字符串
/// </summary>
public static string ToJson(Dictionary<string, object> obj, bool prettyPrint = false)
{
if (obj == null) return "null";
var settings = new Newtonsoft.Json.JsonSerializerSettings
{
Formatting = prettyPrint ? Newtonsoft.Json.Formatting.Indented : Newtonsoft.Json.Formatting.None
};
return Newtonsoft.Json.JsonConvert.SerializeObject(obj, settings);
}
/// <summary>
/// 从JSON字符串创建ASN1对象
/// </summary>
public static Dictionary<string, object> FromJson(string json)
{
if (string.IsNullOrEmpty(json)) return null;
try
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
}
catch
{
return null;
}
}
}
}

365
LTEMvcApp/Models/ASN1Parser.cs

@ -0,0 +1,365 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using Newtonsoft.Json;
namespace LTEMvcApp.Models
{
/// <summary>
/// ASN1解析器,用于解析GSER格式的ASN1数据
/// </summary>
public class ASN1Parser
{
private static readonly Regex RegExpOpen = new Regex(@"((?! )[\w-\s]+(?<! ))?:?\s*{", RegexOptions.Compiled);
private static readonly Regex RegExpClose = new Regex(@"}", RegexOptions.Compiled);
private static readonly Regex RegExpValueNum = new Regex(@"([\w-]+)\s+(\d+),?$", RegexOptions.Compiled);
private static readonly Regex RegExpValueEnumerated = new Regex(@"([\w-]+)\s+([\w-']+)\s*,?$", RegexOptions.Compiled);
private static readonly Regex RegExpValueChoice = new Regex(@"([\w-]+) ([\w-]+):\s+([\w-']+)\s*,?$", RegexOptions.Compiled);
private static readonly Regex RegExpValueListNum = new Regex(@"\s+(\d+),?$", RegexOptions.Compiled);
private static readonly Regex RegExpValueListMisc = new Regex(@"\s+([\w-]+),?$", RegexOptions.Compiled);
private static readonly Regex RegExpHexDump = new Regex(@"^[0-9A-Fa-f\s]+$", RegexOptions.Compiled);
/// <summary>
/// 从GSER格式的字符串数组解析ASN1数据
/// </summary>
/// <param name="data">GSER格式的字符串数组</param>
/// <returns>解析后的ASN1对象</returns>
public static Dictionary<string, object> FromGSER(string[] data)
{
if (data == null || data.Length == 0)
return null;
var root = (ASN1Node)null;
var stack = new Stack<ASN1Node>();
try
{
int i = 0;
// 移除十六进制转储
for (; i < data.Length; i++)
{
var d = data[i];
if (!RegExpHexDump.IsMatch(d))
break;
}
for (; i < data.Length; i++)
{
var d = data[i];
// 移除注释
for (int j = 0; j < 10; j++) // 最多10次迭代
{
var c0 = d.IndexOf("/*");
if (c0 < 0) break;
var c1 = d.IndexOf("*/");
if (c1 >= 0)
{
d = d.Remove(c0, c1 + 2 - c0);
}
else
{
d = d.Substring(0, c0);
for (i++; i < data.Length; i++)
{
var d1 = data[i];
var c2 = d1.IndexOf("*/");
if (c2 >= 0)
{
d += d1.Substring(c2 + 2);
break;
}
}
}
}
var match = RegExpOpen.Match(d);
if (match.Success)
{
var node = new ASN1Node { Name = match.Groups[1].Success ? match.Groups[1].Value.Trim() : null };
if (root == null) root = node;
stack.Push(node);
continue;
}
if (stack.Count == 0) continue;
match = RegExpClose.Match(d);
if (match.Success)
{
var node = stack.Pop();
if (stack.Count == 0) // 结束
break;
AddProperty(stack.Peek(), node.Name, node.Obj ?? new Dictionary<string, object>());
continue;
}
// 数值常量
match = RegExpValueNum.Match(d);
if (match.Success)
{
AddProperty(stack.Peek(), match.Groups[1].Value, int.Parse(match.Groups[2].Value));
}
// 通用字符串
else if ((match = RegExpValueEnumerated.Match(d)).Success)
{
var value = match.Groups[2].Value;
switch (value)
{
case "TRUE":
AddProperty(stack.Peek(), match.Groups[1].Value, true);
break;
case "FALSE":
AddProperty(stack.Peek(), match.Groups[1].Value, false);
break;
default:
AddProperty(stack.Peek(), match.Groups[1].Value, value);
break;
}
}
// 带基本值的Choice
else if ((match = RegExpValueChoice.Match(d)).Success)
{
AddProperty(stack.Peek(), match.Groups[1].Value,
new Dictionary<string, object>
{
["choice"] = match.Groups[2].Value,
["value"] = match.Groups[3].Value
});
}
else if ((match = RegExpValueListNum.Match(d)).Success)
{
AddProperty(stack.Peek(), null, int.Parse(match.Groups[1].Value));
}
else if ((match = RegExpValueListMisc.Match(d)).Success)
{
AddProperty(stack.Peek(), null, match.Groups[1].Value);
}
}
// 验证解析结果
if (root == null)
return null;
if (stack.Count != 0)
{
// 栈不为空说明解析不完整,返回null
return null;
}
// 确保返回的是Dictionary<string, object>类型
if (root.Obj is Dictionary<string, object> dict)
{
return dict;
}
else if (root.Obj is List<object> list)
{
// 如果是列表,包装成字典
return new Dictionary<string, object> { ["items"] = list };
}
else if (root.Obj != null)
{
// 如果是其他类型,包装成字典
return new Dictionary<string, object> { ["value"] = root.Obj };
}
else
{
// 如果root.Obj为null,返回空字典
return new Dictionary<string, object>();
}
}
catch (Exception ex)
{
// 记录异常信息(在实际应用中可以使用日志框架)
throw new InvalidOperationException($"解析GSER数据时发生错误: {ex.Message}", ex);
}
}
/// <summary>
/// 添加属性到节点
/// </summary>
private static void AddProperty(ASN1Node node, string name, object value)
{
if (string.IsNullOrEmpty(name))
{
if (node.Obj == null) node.Obj = new List<object>();
((List<object>)node.Obj).Add(value);
}
else
{
if (node.Obj == null) node.Obj = new Dictionary<string, object>();
var dict = (Dictionary<string, object>)node.Obj;
if (!dict.ContainsKey(name))
{
dict[name] = value;
}
else
{
var cur = dict[name];
if (cur is List<object> list)
{
list.Add(value);
}
else
{
dict[name] = new List<object> { cur, value };
}
}
}
}
/// <summary>
/// 深度访问ASN1对象
/// </summary>
/// <param name="asn1">ASN1对象</param>
/// <param name="path">访问路径</param>
/// <returns>访问到的值</returns>
public static object Dig(Dictionary<string, object> asn1, params object[] path)
{
if (asn1 == null)
return null;
var current = (object)asn1;
var count = 1;
for (int i = 0; i < path.Length;)
{
var arg = path[i];
if (arg is int intArg)
{
count = intArg;
i++;
}
else
{
if (current is Dictionary<string, object> dict)
{
var key = arg.ToString();
if (!dict.ContainsKey(key))
return null;
current = dict[key];
}
else if (current is List<object> list)
{
var index = int.Parse(arg.ToString());
if (index >= list.Count)
return null;
current = list[index];
}
else
{
return null;
}
if (--count == 0)
{
i++;
count = 1;
}
}
}
return current;
}
/// <summary>
/// 映射ASN1数组
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="asn1">ASN1对象</param>
/// <param name="callback">映射函数</param>
/// <returns>映射结果</returns>
public static List<T> Map<T>(object asn1, Func<object, T> callback)
{
// 参数验证
if (callback == null)
throw new ArgumentNullException(nameof(callback), "回调函数不能为空");
// 如果asn1为null,返回空列表
if (asn1 == null)
return new List<T>();
try
{
if (asn1 is List<object> list)
{
// 处理列表类型,过滤掉null值并应用映射
return list.Where(item => item != null)
.Select(callback)
.ToList<T>();
}
else
{
// 处理单个对象
return new List<T> { callback(asn1) };
}
}
catch (Exception ex)
{
// 记录异常信息(在实际应用中可以使用日志框架)
throw new InvalidOperationException($"映射ASN1数据时发生错误: {ex.Message}", ex);
}
}
/// <summary>
/// 映射ASN1数组(带索引)
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="asn1">ASN1对象</param>
/// <param name="callback">带索引的映射函数</param>
/// <returns>映射结果</returns>
public static List<T> Map<T>(object asn1, Func<object, int, T> callback)
{
// 参数验证
if (callback == null)
throw new ArgumentNullException(nameof(callback), "回调函数不能为空");
// 如果asn1为null,返回空列表
if (asn1 == null)
return new List<T>();
try
{
if (asn1 is List<object> list)
{
// 处理列表类型,过滤掉null值并应用带索引的映射
var result = new List<T>();
int index = 0;
foreach (var item in list)
{
if (item != null)
{
result.Add(callback(item, index));
}
index++;
}
return result;
}
else
{
// 处理单个对象
return new List<T> { callback(asn1, 0) };
}
}
catch (Exception ex)
{
// 记录异常信息(在实际应用中可以使用日志框架)
throw new InvalidOperationException($"映射ASN1数据时发生错误: {ex.Message}", ex);
}
}
}
/// <summary>
/// ASN1节点
/// </summary>
public class ASN1Node
{
public string Name { get; set; }
public object Obj { get; set; }
}
}

441
LTEMvcApp/Models/LTECapabilities.cs

@ -0,0 +1,441 @@
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";
}
}

3
LTEMvcApp/Models/LTEClient.cs

@ -1936,7 +1936,8 @@ public class LTEClient
var keysToUpdate = UeList.Where(kv => kv.Value == ue1).Select(kv => kv.Key).ToList();
foreach (var key in keysToUpdate)
{
UeList[key] = ue0;
int newKey =(int)key;
UeList[newKey] = ue0;
}
// 合并属性
if (string.IsNullOrEmpty(ue0.Imsi)) ue0.Imsi = ue1.Imsi;

11
LTEMvcApp/Models/StatisticsData.cs

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Newtonsoft.Json.Linq;
@ -428,7 +427,13 @@ namespace LTEMvcApp.Models
{
lock (_lockObject)
{
return _statsQueue.ToList();
var result = new List<StatisticsData>();
foreach (var item in _statsQueue)
{
if (item != null)
result.Add(item);
}
return result;
}
}

Loading…
Cancel
Save