From 82cf5383301cb9681d876ad8daf7cf3fb2d800f0 Mon Sep 17 00:00:00 2001 From: yanghongwei Date: Sun, 4 Aug 2024 22:18:34 +0800 Subject: [PATCH] =?UTF-8?q?gps=20=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- langguanApi.xml | 53 +++++++++ langguanApi/Common/CacheManager.cs | 4 + langguanApi/Common/Gps/MessageHeader.cs | 31 +++++ langguanApi/Common/Gps/ProtocolParser.cs | 110 ++++++++++++++++++ langguanApi/Common/Proxy/HttpProxy.cs | 4 + langguanApi/Common/Redis/RedisHelper.cs | 3 + langguanApi/Controllers/HomeController.cs | 131 +++++++++++++++++++++- langguanApi/Extensions/SocketExtension.cs | 2 + langguanApi/Model/FactorCode.cs | 2 + langguanApi/Service/HJ212/NetSession.cs | 53 ++++++++- langguanApi/Service/HJ212SocketServer.cs | 2 +- 11 files changed, 386 insertions(+), 9 deletions(-) create mode 100644 langguanApi/Common/Gps/MessageHeader.cs create mode 100644 langguanApi/Common/Gps/ProtocolParser.cs diff --git a/langguanApi.xml b/langguanApi.xml index adaa7b4..0e9e02d 100644 --- a/langguanApi.xml +++ b/langguanApi.xml @@ -9,6 +9,12 @@ 缓存管理 + + + 构造函数 + + + 缓存数据 @@ -19,11 +25,53 @@ 缓存时间秒,0=int.max , + + + gps 协议解析器 + + + + + 解析消息头 + + + + + + + + 解析位置信息 + + + + + + + 解析终端注册消息 + + + + + + + + 解析位置上报消息 + + + + + http + + + 构造函数 + + + 获取数据 @@ -47,6 +95,11 @@ sub + + + 构造函数 + + 缓存天气信息 diff --git a/langguanApi/Common/CacheManager.cs b/langguanApi/Common/CacheManager.cs index 4a7637d..0c04069 100644 --- a/langguanApi/Common/CacheManager.cs +++ b/langguanApi/Common/CacheManager.cs @@ -12,6 +12,10 @@ namespace langguanApi.Common public class CacheManager { private readonly IDatabase _redisDatabase; + /// + /// 构造函数 + /// + /// public CacheManager(RedisHelper redisHelper) { _redisDatabase = redisHelper._database; diff --git a/langguanApi/Common/Gps/MessageHeader.cs b/langguanApi/Common/Gps/MessageHeader.cs new file mode 100644 index 0000000..8f25af6 --- /dev/null +++ b/langguanApi/Common/Gps/MessageHeader.cs @@ -0,0 +1,31 @@ +namespace langguanApi.Common.Gps +{ + public class MessageHeader + { + public ushort MessageId { get; set; } + public ushort MessageBodyProperty { get; set; } + public string TerminalId { get; set; } + public ushort MessageSerialNumber { get; set; } + } + public class TerminalRegisterMessage + { + public ushort ProvinceId { get; set; } + public ushort CityId { get; set; } + public byte[] ManufacturerId { get; set; } + public byte[] TerminalType { get; set; } + public byte[] TerminalId { get; set; } + public byte LicensePlateColor { get; set; } + public string LicensePlate { get; set; } + } + public class LocationReportMessage + { + public uint AlarmFlag { get; set; } + public uint Status { get; set; } + public uint Latitude { get; set; } + public uint Longitude { get; set; } + public ushort Altitude { get; set; } + public ushort Speed { get; set; } + public ushort Direction { get; set; } + public DateTime Time { get; set; } + } +} diff --git a/langguanApi/Common/Gps/ProtocolParser.cs b/langguanApi/Common/Gps/ProtocolParser.cs new file mode 100644 index 0000000..b113aa0 --- /dev/null +++ b/langguanApi/Common/Gps/ProtocolParser.cs @@ -0,0 +1,110 @@ +using System.Text; + +namespace langguanApi.Common.Gps +{ + /// + /// gps 协议解析器 + /// + public class ProtocolParser + { + /// + /// 解析消息头 + /// + /// + /// + /// + public static MessageHeader ParseHeader(byte[] data, ref int offset) + { + var header = new MessageHeader + { + MessageId = BitConverter.ToUInt16(data, offset), + MessageBodyProperty = BitConverter.ToUInt16(data, offset + 2), + TerminalId = Encoding.ASCII.GetString(data, offset + 4, 6), + MessageSerialNumber = BitConverter.ToUInt16(data, offset + 10) + }; + + offset += 12; + return header; + } + public struct Position + { + public double Latitude; + public double Longitude; + public double Altitude; + } + /// + /// 解析位置信息 + /// + /// + /// + public static Position ParsePosition(byte[] data) + { + // 根据协议中的位置信息的偏移量和长度进行解析 + int positionOffset = 21; // 位置信息在数据中的偏移量 + int latitudeOffset = positionOffset + 0; + int longitudeOffset = positionOffset + 8; + int altitudeOffset = positionOffset + 16; + + double latitude = BitConverter.ToDouble(data, latitudeOffset); + double longitude = BitConverter.ToDouble(data, longitudeOffset); + double altitude = BitConverter.ToDouble(data, altitudeOffset); + + return new Position + { + Latitude = latitude, + Longitude = longitude, + Altitude = altitude + }; + } + + /// + /// 解析终端注册消息 + /// + /// + /// + /// + public static TerminalRegisterMessage ParseTerminalRegisterMessage(byte[] data, ref int offset) + { + var message = new TerminalRegisterMessage + { + ProvinceId = BitConverter.ToUInt16(data, offset), + CityId = BitConverter.ToUInt16(data, offset + 2), + ManufacturerId = data.Skip(offset + 4).Take(5).ToArray(), + TerminalType = data.Skip(offset + 9).Take(8).ToArray(), + TerminalId = data.Skip(offset + 17).Take(7).ToArray(), + LicensePlateColor = data[offset + 24], + LicensePlate = Encoding.ASCII.GetString(data, offset + 25, data.Length - offset - 25) + }; + + offset += 25 + message.LicensePlate.Length; + return message; + } + /// + /// 解析位置上报消息 + /// + /// + /// + /// + public static LocationReportMessage ParseLocationReportMessage(byte[] data, ref int offset) + { + var message = new LocationReportMessage + { + AlarmFlag = BitConverter.ToUInt32(data, offset), + Status = BitConverter.ToUInt32(data, offset + 4), + Latitude = BitConverter.ToUInt32(data, offset + 8), + Longitude = BitConverter.ToUInt32(data, offset + 12), + Altitude = BitConverter.ToUInt16(data, offset + 16), + Speed = BitConverter.ToUInt16(data, offset + 18), + Direction = BitConverter.ToUInt16(data, offset + 20), + Time = DateTime.ParseExact( + Encoding.ASCII.GetString(data, offset + 22, 6), + "yyMMddHHmmss", + null + ) + }; + + offset += 28; + return message; + } + } +} diff --git a/langguanApi/Common/Proxy/HttpProxy.cs b/langguanApi/Common/Proxy/HttpProxy.cs index 3a323ff..8532d4a 100644 --- a/langguanApi/Common/Proxy/HttpProxy.cs +++ b/langguanApi/Common/Proxy/HttpProxy.cs @@ -10,6 +10,10 @@ namespace langguanApi.Common.Proxy public class HttpProxy { private readonly IHttpClientFactory _httpClientFactory; + /// + /// 构造函数 + /// + /// public HttpProxy(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; diff --git a/langguanApi/Common/Redis/RedisHelper.cs b/langguanApi/Common/Redis/RedisHelper.cs index 22fa2b4..4442479 100644 --- a/langguanApi/Common/Redis/RedisHelper.cs +++ b/langguanApi/Common/Redis/RedisHelper.cs @@ -9,6 +9,9 @@ namespace langguanApi.Common.Redis /// sub /// public ISubscriber _subscriber; + /// + /// 构造函数 + /// public RedisHelper() { // var con = RedisOptions.Default.GetConnect(); diff --git a/langguanApi/Controllers/HomeController.cs b/langguanApi/Controllers/HomeController.cs index c1797f2..cbcd0c7 100644 --- a/langguanApi/Controllers/HomeController.cs +++ b/langguanApi/Controllers/HomeController.cs @@ -1,9 +1,17 @@ -using langguanApi.Model; +using JT808.Protocol.MessageBody; +using JT808.Protocol; +using langguanApi.Model; using langguanApi.Service; using langguanApi.Service.HJ212; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Org.BouncyCastle.Utilities; using System.Text; +using JT808.Protocol.Extensions; +using static langguanApi.Service.WeatherService; +using langguanApi.Common.Gps; +using NPOI.SS.Formula.Functions; +using static langguanApi.Common.Gps.ProtocolParser; namespace langguanApi.Controllers { @@ -23,7 +31,7 @@ namespace langguanApi.Controllers [HttpGet("view")] public async Task View() { - return Ok( await _homeService.View() ); + return Ok(await _homeService.View()); } [HttpGet("test")] @@ -35,11 +43,128 @@ namespace langguanApi.Controllers /// public async Task test(int num = 1, string key = "") { - // string rawText = "数据报:##0250QN=20240424224800000;ST=22;CN=2011;PW=123456;MN=LGYC022024690001;Flag=5;CP=&&DataTime=20240424224800;a34001-Rtd=356.2"; + // 示例数据(需替换为实际接收到的协议数据) + string hexData = "787811010868120321167279808D3202001AB12F0D0A"; + byte[] protocolData = HexStringToByteArray(hexData); + // 进行转义还原 + byte[] restoredData = RestoreEscape(protocolData); + + // 验证校验码 + if (!VerifyChecksum(restoredData)) + { + Console.WriteLine("Checksum verification failed."); + } + Position? position = ParsePosition(restoredData); + + if (position.HasValue) + { + Console.WriteLine($"Latitude: {position.Value.Latitude}"); + Console.WriteLine($"Longitude: {position.Value.Longitude}"); + Console.WriteLine($"Altitude: {position.Value.Altitude}"); + } + else + { + Console.WriteLine("Failed to parse position."); + } + // Console.WriteLine("经度:" + lon + " 纬度:" + lat); + + // string rawText = "数据报:##0250QN=20240424224800000;ST=22;CN=2011;PW=123456;MN=LGYC022024690001;Flag=5;CP=&&DataTime=20240424224800;a34001-Rtd=356.2"; //NetPackage netPackage = NetPackage.Parse(rawText, null); //((NetServer)Server).RaiseReceivedData(this, netPackage, rawText); return Ok(); } + public static Position? ParsePosition(byte[] data) + { + // 根据协议中的位置信息的偏移量和长度进行解析 + int positionOffset = 21; // 位置信息在数据中的偏移量 + int latitudeOffset = positionOffset + 0; + int longitudeOffset = positionOffset + 4; + int altitudeOffset = positionOffset + 8; + // 检查数组长度是否足够长 + if (data.Length < altitudeOffset + 2) + { + Console.WriteLine("Data array is not long enough to contain position information."); + return null; + } + + // 解析纬度(单位:百万分之一度) + int rawLatitude = BitConverter.ToInt32(data, latitudeOffset); + double latitude = rawLatitude / 1000000.0; + + // 解析经度(单位:百万分之一度) + int rawLongitude = BitConverter.ToInt32(data, longitudeOffset); + double longitude = rawLongitude / 1000000.0; + + // 解析高度(单位:米) + int rawAltitude = BitConverter.ToInt16(data, altitudeOffset); + double altitude = rawAltitude; + + return new Position + { + Latitude = latitude, + Longitude = longitude, + Altitude = altitude + }; + } + + private static bool VerifyChecksum(byte[] data) + { + // 校验码在数据包的倒数第二个字节 + byte receivedChecksum = data[data.Length - 2]; + byte calculatedChecksum = 0; + + // 校验范围是从第一个字节到倒数第三个字节 + for (int i = 0; i < data.Length - 2; i++) + { + calculatedChecksum ^= data[i]; + } + + return receivedChecksum == calculatedChecksum; + } + private static byte[] RestoreEscape(byte[] data) + { + List result = new List(); + for (int i = 0; i < data.Length; i++) + { + if (data[i] == 0x7D) + { + if (i + 1 < data.Length) + { + if (data[i + 1] == 0x02) + { + result.Add(0x7E); + i++; + } + else if (data[i + 1] == 0x01) + { + result.Add(0x7D); + i++; + } + } + } + else + { + result.Add(data[i]); + } + } + return result.ToArray(); + } + private static byte[] HexStringToByteArray(string hex) + { + int NumberChars = hex.Length; + byte[] bytes = new byte[NumberChars / 2]; + for (int i = 0; i < NumberChars; i += 2) + { + bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); + } + return bytes; + } + public struct Position + { + public double Latitude; + public double Longitude; + public double Altitude; + } } } diff --git a/langguanApi/Extensions/SocketExtension.cs b/langguanApi/Extensions/SocketExtension.cs index 62f34f7..b48eda5 100644 --- a/langguanApi/Extensions/SocketExtension.cs +++ b/langguanApi/Extensions/SocketExtension.cs @@ -12,10 +12,12 @@ namespace langguanApi.Extensions { // services.AddSingleton(); services.AddTransient(); + services.AddSingleton(); // 808协议 services.AddTransient(); IServiceProvider serviceProvider = services.BuildServiceProvider(); _ = serviceProvider.GetService().Start(); + _ = serviceProvider.GetService().Start(); serviceProvider.GetService().CreatTask(); } } diff --git a/langguanApi/Model/FactorCode.cs b/langguanApi/Model/FactorCode.cs index b8975e8..7fa4758 100644 --- a/langguanApi/Model/FactorCode.cs +++ b/langguanApi/Model/FactorCode.cs @@ -416,6 +416,8 @@ a34040, a99010, a99049, + + LA, a99054 //a99051, #endregion diff --git a/langguanApi/Service/HJ212/NetSession.cs b/langguanApi/Service/HJ212/NetSession.cs index 95c4a2e..8dc7407 100644 --- a/langguanApi/Service/HJ212/NetSession.cs +++ b/langguanApi/Service/HJ212/NetSession.cs @@ -1,6 +1,13 @@ using IceCoffee.FastSocket.Tcp; +using JT808.Protocol; +using JT808.Protocol.Extensions; +using JT808.Protocol.MessageBody; +using langguanApi.Common.Gps; using langguanApi.Model; +using Npoi.Mapper; +using NPOI.SS.Formula.Functions; using System.Text; +using static langguanApi.Common.Gps.ProtocolParser; namespace langguanApi.Service.HJ212 { @@ -31,11 +38,12 @@ namespace langguanApi.Service.HJ212 /// protected override void OnReceived() { - if (ReadBuffer.IndexOf(35) != 0L)// '#' - { - return; - // throw new Exception("异常TCP连接 IP: " + RemoteIPEndPoint); - } + + //if (ReadBuffer.IndexOf(35) != 0L)// '#' + //{ + // return; + // // throw new Exception("异常TCP连接 IP: " + RemoteIPEndPoint); + //} string rawText = null; while (ReadBuffer.CanReadLine) @@ -43,6 +51,41 @@ namespace langguanApi.Service.HJ212 try { byte[] data = ReadBuffer.ReadLine(); + + Console.WriteLine($"原始数据:{data}----------"); + Console.WriteLine($"原始数据HexString:{data.ToHexString()}--------------------"); + Console.WriteLine($"原始数据ASCII:{Encoding.ASCII.GetString(data)}-"); + + Position position = ParsePosition(data); + + Console.WriteLine($"Latitude: {position.Latitude}"); + Console.WriteLine($"Longitude: {position.Longitude}"); + Console.WriteLine($"Altitude: {position.Altitude}"); + int offset = 0; + // 解析消息头 + var header = ProtocolParser.ParseHeader(data, ref offset); + Console.WriteLine($"Message ID: {header.MessageId}, Terminal ID: {header.TerminalId}"); + + // 解析终端注册消息 + var registerMessage = ProtocolParser.ParseTerminalRegisterMessage(data, ref offset); + Console.WriteLine($"Province ID: {registerMessage.ProvinceId}, City ID: {registerMessage.CityId}"); + Console.WriteLine($"License Plate: {registerMessage.LicensePlate}"); + + offset = 0; + // 解析位置信息汇报消息 + var locationReportMessage = ProtocolParser.ParseLocationReportMessage(data, ref offset); + Console.WriteLine($"Latitude: {locationReportMessage.Latitude}, Longitude: {locationReportMessage.Longitude}"); + Console.WriteLine($"Speed: {locationReportMessage.Speed}, Time: {locationReportMessage.Time}"); + + + + + var jT808Package = new JT808Serializer().Deserialize(data); + //4.数据包体 + JT808_0x0200 jT808_0x0200 = (JT808_0x0200)jT808Package.Bodies; + var lon = jT808_0x0200.Lat; + var lat = jT808_0x0200.Lng; + Console.WriteLine("经度:" + lon + " 纬度:" + lat); rawText = Encoding.UTF8.GetString(data); NetPackage netPackage = NetPackage.Parse(rawText, GetUnpackCache); ((NetServer)Server).RaiseReceivedData(this, netPackage, rawText); diff --git a/langguanApi/Service/HJ212SocketServer.cs b/langguanApi/Service/HJ212SocketServer.cs index 2110bd5..8a3196a 100644 --- a/langguanApi/Service/HJ212SocketServer.cs +++ b/langguanApi/Service/HJ212SocketServer.cs @@ -35,7 +35,7 @@ namespace langguanApi.Service /// /// 服务端口号 /// - private int port => 5001; + private int port => 5003; // 编码 // private string code; ///