diff --git a/GT808ClientTest.csproj b/GT808ClientTest.csproj new file mode 100644 index 0000000..25ea763 --- /dev/null +++ b/GT808ClientTest.csproj @@ -0,0 +1,94 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9} + Exe + Properties + GT808ClientTest + GT808ClientTest + v4.0 + + + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + ..\Libs\log4net.dll + + + False + bin\Debug\Plugin.Common.dll + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + \ No newline at end of file diff --git a/GT808ClientTest.sln b/GT808ClientTest.sln new file mode 100644 index 0000000..b39d5d7 --- /dev/null +++ b/GT808ClientTest.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.539 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GT808ClientTest", "GT808ClientTest.csproj", "{DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Debug|Any CPU.ActiveCfg = Debug|x86 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Debug|x64.ActiveCfg = Debug|x64 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Debug|x64.Build.0 = Debug|x64 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Debug|x86.ActiveCfg = Debug|x86 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Debug|x86.Build.0 = Debug|x86 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Release|Any CPU.ActiveCfg = Release|x86 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Release|x64.ActiveCfg = Release|x64 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Release|x64.Build.0 = Release|x64 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Release|x86.ActiveCfg = Release|x86 + {DAEB7DF5-2FA8-4663-A15C-F8E52C1A19A9}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BAA1F5E7-D1F4-4D5E-A8BD-C3C293C9BA3B} + EndGlobalSection +EndGlobal diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..01eb057 --- /dev/null +++ b/Program.cs @@ -0,0 +1,493 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; +using System.Diagnostics; +using System.Threading; +using Gps.Plugin.Tcp.GT808; +using Gps.Plugin.Common.Helpers; +using System.Configuration; + +namespace GT808ClientTest +{ + class Program + { + protected static log4net.ILog log = null; + private string ip; + private int port; + private string deviceId; + Random r = new Random(); + private int interval; + private int sendCountByOneDevice; + private ProcessCounter processCounter; + private static bool sendLogPrint; + private static bool waitReceive; + private static bool receiveLogPrint; + + static Program() + { + log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)); + log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + } + private double initLat = 38.01342; + private double initLon = 114.560478; + + public Program(string ip, int port, string deviceId, int interval, int sendCountByOneDevice, ProcessCounter processCounter) + { + // TODO: Complete member initialization + this.latlonBuilder = new LatlonBuilder(initLat, initLon, 31.802893, 39.300299, 104.941406, 117.861328); + this.ip = ip; + this.port = port; + this.deviceId = deviceId; + this.interval = interval; + this.sendCountByOneDevice = sendCountByOneDevice; + this.processCounter = processCounter; + } + + private static byte[] stringtobytes(string str) + { + string[] strs = str.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries); + byte[] buffer = new byte[strs.Length]; + for (int i = 0; i < strs.Length; ++i) + { + buffer[i] = Convert.ToByte(strs[i], 16); + } + + return buffer; + } + + static void Main(string[] args) + { + AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); + + //var headpack = new Gps.Plugin.Tcp.GT808.HeadPack(); + //byte[] packBytes = stringtobytes("7E-01-02-00-0E-00-20-47-05-52-32-00-00-32-30-31-32-30-31-31-39-30-38-31-30-34-37-0D-7E"); + //if (RawFormatter.Instance.Bytes2Struct(headpack, packBytes , 1, HeadPack.PackSize)) + //{ + // Console.WriteLine("OK"); + // Console.ReadKey(); + //} + + //MessageContext pack = new MessageContext(); + //byte[] packBytes = stringtobytes("68-68-25-00-00-00-00-00-00-00-12-34-56-00-18-10-DC-01-13-13-06-17-04-14-11-DC-0C-4A-7F-5C-1A-00-00-00-00-00-00-00-00-00-0A-0D"); + //if (RawFormatter.Instance.Bytes2Struct(pack, packBytes, BodyData.PackSize, MessageContext.PackSize)) + //{ + // Console.WriteLine("OK"); + // Console.ReadKey(); + //} + + sendLogPrint = Convert.ToBoolean(ConfigurationManager.AppSettings["sendLogPrint"]); + waitReceive = Convert.ToBoolean(ConfigurationManager.AppSettings["waitReceive"]); + receiveLogPrint = Convert.ToBoolean(ConfigurationManager.AppSettings["receiveLogPrint"]); + + string ip = ""; + int port = 0; + while (port == 0 || string.IsNullOrEmpty(ip)) + { + string line = ""; + string configValue = ConfigurationManager.AppSettings["remoteServerPort"]; + if (string.IsNullOrEmpty(configValue)) + { + Console.Write("请输入服务器IP和端口(113.31.92.200:8201):"); + line = Console.ReadLine(); + } + else + { + line = configValue; + } + + if (string.IsNullOrEmpty(line)) + line = "113.31.92.200:8201"; + + int pos = line.IndexOf(':'); + if (pos == -1) + { + Console.WriteLine("正确格式:xx.xxx.xxx.xxx:xxxx"); + continue; + } + + ip = line.Substring(0, pos); + string strPort = line.Substring(pos + 1); + + int.TryParse(strPort, out port); + } + + int min = 0, max = 0; + string deviceIdRangeValue = ConfigurationManager.AppSettings["deviceIdRange"]; + if (string.IsNullOrEmpty(deviceIdRangeValue)) + { + Console.WriteLine("生成设备标识格式为:0000000000000000,0000000000000001...."); + Console.Write("依客户端网络情况输入要模拟的客户端数量(1-10000):"); + string strCount = Console.ReadLine(); + max = int.Parse(strCount); + } + else + { + string[] items = deviceIdRangeValue.Split('-'); + min = int.Parse(items[0]); + max = int.Parse(items[1]); + } + + int interval = 30; + string strInterval = ConfigurationManager.AppSettings["interval"]; + if (string.IsNullOrEmpty(strInterval)) + { + Console.Write("每个消息间隔(秒):"); + strInterval = Console.ReadLine(); + interval = int.Parse(strInterval); + } + else + { + interval = int.Parse(strInterval); + } + + int sendCountByOneDevice = 30; + string strSendCountByOneDevice = ConfigurationManager.AppSettings["sendCountByOneDevice"]; + if (string.IsNullOrEmpty(strSendCountByOneDevice)) + { + Console.Write("每个设备发送共多少个包后断开连接:"); + strSendCountByOneDevice = Console.ReadLine(); + sendCountByOneDevice = int.Parse(strSendCountByOneDevice); + } + else + { + sendCountByOneDevice = int.Parse(strSendCountByOneDevice); + } + + ProcessCounter processCounter = new ProcessCounter((max - min + 1) * sendCountByOneDevice, pc => + { + Console.Title = pc.ToString(); + }); + + for (int i = min; i <= max; ++i) + { + string deviceId = string.Concat("010000", i.ToString("00000")); + + Program p = new Program(ip, port, deviceId, interval, sendCountByOneDevice, processCounter); + + //p.Run(); + Thread iThred = new Thread(p.Run); + iThred.Start(); + + //Thread.SpinWait(2); + } + Console.ReadLine(); + } + + private void Run() + { + Console.WriteLine("Thread {0} Start {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString()); + + Socket tcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + try + { + tcp.Connect(IPAddress.Parse(ip), port); + + try + { + while (this.sendCountByOneDevice-- > 0) + { + if (SendPosition(tcp)) + { + processCounter.IncrSuccess(); + } + else + { + processCounter.IncrFailed(); + } + Thread.Sleep(interval * 1000); + //Thread.Sleep(100); + } + /* + if (SendPosition(tcp)) + { + processCounter.IncrSuccess(); + } + else + { + processCounter.IncrFailed(); + } + + if (--this.sendCountByOneDevice <= 0) + { + //timer.Change(-1, -1); + //try + //{ + // tcp.Disconnect(true); + // tcp.Dispose(); + //} + //catch (Exception exp) + //{ + // log.Warn("断开连接出错:" + exp.Message); + //} + } + else + { + //SendPosition(tcp); + //timer.Change(Math.Max(1, interval * 1000 - watch.ElapsedMilliseconds), -1); + } + */ + } + catch (SocketException exp) + { + log.Debug("连接已经断开, 重连接中"); + //timer.Change(Timeout.Infinite, Timeout.Infinite); + this.Run(); + } + catch (Exception ex) + { + log.Error(ex.Message, ex); + //timer.Change(Math.Max(1, interval * 1000 - watch.ElapsedMilliseconds), -1); + } + } + catch (ThreadAbortException) + { + return; + } + catch (Exception exp) + { + log.Error(exp); + + } + Console.WriteLine("Thread {0} End {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString()); + + } + + ushort seqNum = 1; + ushort GetNextSeqNum() + { + lock (this) + { + return ++seqNum; + } + } + + private byte[] bufferRecv = new byte[1024]; + private LatlonBuilder latlonBuilder; + + private bool SendPosition(Socket tcp) + { + HeadPack head = new HeadPack() { SeqNO = GetNextSeqNum(), MessageId = (ushort)MessageIds.PositionReport, BodyProp = (ushort)0 }; + head.SetDeviceId(this.deviceId); + + double lat; + double lon; + int speed = 10 + r.Next(90); + latlonBuilder.GetNextLatlon(speed, out lat, out lon); + + PositionReportPack pack = new PositionReportPack() + { + AlermFlags = 0, + Speed = (ushort)(speed * 10), + State = 0, + Latitude = Convert.ToUInt32(lat * 1000000), + Longitude = Convert.ToUInt32(lon * 1000000), + Altitude = 200, + Direction = 0, + Time = DateTime.Now.ToString("yyMMddHHmmss") + }; + + byte[] bytesSend = RawFormatter.Instance.Struct2Bytes(pack); + + BodyPropertyHelper.SetMessageLength(ref head.BodyProp, (ushort)bytesSend.Length); + + byte[] headBytes = RawFormatter.Instance.Struct2Bytes(head); + byte[] fullBytes = headBytes.Concat(bytesSend).ToArray(); + byte checkByte = PackHelper.CalcCheckByte(fullBytes, 0, fullBytes.Length); + + bytesSend = (new byte[] { 0x7e } + .Concat(PackHelper.EncodeBytes(fullBytes).Concat(new byte[] { checkByte })) + .Concat(new byte[] { 0x7e })).ToArray(); + + //发送消息 + SendBytes(tcp, bytesSend); + //控制台打印日志cpu占用太高 + if (sendLogPrint) + { + Console.WriteLine("{0} {1}, LatLon:{2:0.000000},{3:0.000000}", head.GetDeviceId(), DateTime.Now.ToString(), lat, lon); + } + //等待接收服务端返回值 + var success = true; + if (waitReceive) + { + success = RecvBytes(tcp); + //var success = true; + } + return success; + } + void SendBytes(Socket tcp, byte[] bytes) + { + lock (System.Reflection.MethodBase.GetCurrentMethod()) + { + if (bytes.Length != tcp.Send(bytes)) + { + throw new SocketException((int)SocketError.ConnectionReset); + } + } + } + + private bool RecvBytes(Socket tcp) + { + lock (bufferRecv) + { + byte[] buffer = bufferRecv; + + int received = tcp.Receive(buffer); + //received = tcp.ReceiveAsync.Receive(buffer); + + byte[] bytesReceived = PackHelper.DecodeBytes(buffer, 1, received - 2); + int rightSize = HeadPack.PackSize + ServerAnswerPack.PackSize + 1; + if (bytesReceived.Length != rightSize) + { + log.WarnFormat("返回消息长度不正确:" + bytesReceived.Length + "!=" + rightSize); + } + + ServerAnswerPack pack = new ServerAnswerPack(); + RawFormatter.Instance.Bytes2Struct(pack, bytesReceived, HeadPack.PackSize, ServerAnswerPack.PackSize); + + if (pack.Result != 0) + { + log.WarnFormat("发送失败:" + pack.Result.ToString()); + } + if(waitReceive && receiveLogPrint) + { + Console.WriteLine("SeqNO:{0} MessageId:{1} Result:{2}", pack.SeqNO,pack.MessageId,pack.Result); + } + return pack.Result == 0; + } + } + + static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + log.Error(e.ExceptionObject); + } + } + + class LatlonBuilder + { + private double lat; + private double lon; + private double minLat; + private double maxLat; + private double minLon; + private double maxLon; + private int direction = 0; + private Random r = new Random(); + public LatlonBuilder(double lat, double lon, double minLat, double maxlat, double minLon, double maxLon) + { + this.lat = lat; + this.lon = lon; + this.minLat = minLat; + this.maxLat = maxlat; + this.minLon = minLon; + this.maxLon = maxLon; + + this.direction = r.Next(360); + } + + public bool GetNextLatlon(int speed, out double lat, out double lon) + { + direction = (direction + (r.Next(30) - 15)) % 360; + double angle = Math.PI * this.direction / 180.0; + double latAdd = speed / 1000.0 * Math.Sin(angle); + double lonAdd = speed / 1000.0 * Math.Cos(angle); + + this.lat = lat = this.lat + latAdd; + this.lon = lon = this.lon + lonAdd; + + if (lat < minLat || lat > maxLat || lon < minLon || lon > maxLon) + { + direction = (direction + 180) % 360; + return GetNextLatlon(speed, out lat, out lon); + } + + + return true; + } + } + + class ProcessCounter + { + private long current = 0, failedCounter = 0; + private Thread thread; + private AutoResetEvent evtUpdateUI = new AutoResetEvent(false); + private long updatePerCount; + private long lastUpdateVal; + public ProcessCounter(long max, Action updateUI) + { + this.Max = max; + this.updatePerCount = max / 100; + this.thread = new Thread(new ThreadStart(() => + { + while (true) + { + try + { + evtUpdateUI.WaitOne(500); + this.lastUpdateVal = Interlocked.Read(ref current); + updateUI(this); + } + catch (ThreadAbortException) + { + return; + } + catch (Exception exp) + { + Console.WriteLine(exp.Message); + } + } + })); + this.thread.IsBackground = true; + this.thread.Start(); + + } + + public long Max { get; set; } + + + internal void IncrSuccess() + { + lock (this) + Incr(); + } + internal void IncrFailed() + { + lock (this) + { + Incr(); + Interlocked.Increment(ref failedCounter); + } + } + + private void Incr() + { + var val = Interlocked.Increment(ref current); + if (val - lastUpdateVal > this.updatePerCount) + { + this.evtUpdateUI.Set(); + } + + if (val == Max) + { + Console.WriteLine("Done"); + } + } + + public override string ToString() + { + long curr = Interlocked.Read(ref current); + float g = Convert.ToSingle(curr / (Max / 100.0)); + string ret = string.Concat(curr, "/", Max, "=>", g.ToString("##.00"), "%"); + + long failed = Interlocked.Read(ref failedCounter); + if (failed > 0) + ret = string.Concat(ret, "(Success:" + (curr - failed), ", Failed:", failed, ")"); + + return ret; + } + + + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0153980 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("GT808ClientTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GT808ClientTest")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("13ae5af7-0f7a-4428-88fe-e41cf030f0a2")] + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 内部版本号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TcpPack.cs b/TcpPack.cs new file mode 100644 index 0000000..e175391 --- /dev/null +++ b/TcpPack.cs @@ -0,0 +1,903 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics.Contracts; +using System.Net; +using Gps.Plugin.Common.Helpers; +using System.IO; +using System.Collections; + +namespace Gps.Plugin.Tcp.GT808 +{ + public class PackHelper + { + public static byte[] ToBytes(string deviceId, MessageIds messageId, ushort seqNO, byte[] bodyBytesReturn) + { + + HeadPack head = new HeadPack() + { + BodyProp = 0, + MessageId = (ushort)messageId, + SeqNO = seqNO + }; + + head.SetDeviceId(deviceId); + //BodyPropertyHelper.SetMessageLength(ref head.BodyProp,(ushort)bodyBytesReturn.Length); + + BodyPropertyHelper.SetMessageLength(ref head.BodyProp, (ushort)bodyBytesReturn.Length); + + + return RawFormatter.Instance.Struct2Bytes(head).Concat(bodyBytesReturn).ToArray(); + + } + + public static byte[] DecodeBytes(byte[] buffer) + { + return DecodeBytes(buffer, 0, buffer.Length); + } + + public static byte[] DecodeBytes(byte[] bytes, int offset, int length) + { + int index = 0; + int endOffset = Math.Min(length, bytes.Length - offset) + offset; + for (int i = offset; i < endOffset; ) + { + if (bytes[i] == 0x7d && bytes[i + 1] == 0x02) + { + bytes[index++] = 0x7e; + i += 2; + } + else if (bytes[i] == 0x7d && bytes[i + 1] == 0x01) + { + bytes[index++] = 0x7d; + i += 2; + } + else + { + bytes[index++] = bytes[i++]; + } + } + + return bytes.Take(index).ToArray(); + } + + + public static byte[] EncodeBytes(IEnumerable bytes) + { + MemoryStream ms = new MemoryStream(); + foreach (var b in bytes) + { + if (b == 0x7e) + { + ms.WriteByte(0x7d); + ms.WriteByte(0x02); + } + else if (b == 0x7d) + { + ms.WriteByte(0x7d); + ms.WriteByte(0x01); + } + else + { + ms.WriteByte(b); + } + + } + + return ms.ToArray(); + } + + /// + /// 计算校验位 + /// + /// + /// + /// + /// + public static byte CalcCheckByte(byte[] bytes, int offset, int count) + { + if (count == 0) + return 0; + + byte ret = bytes[offset]; + for (int i = offset + 1; i < offset + count; ++i) + { + ret ^= bytes[i]; + } + + return ret; + } + + /// + /// 计算校验位 + /// + /// + public static void CalcCheckByte(byte[] bytes) + { + if (bytes.Length == 0) + return; + + bytes[bytes.Length - 1] = CalcCheckByte(bytes, 0, bytes.Length - 1); + } + + + } + + + /* + 车载GPS定位器通信协议(GT808)(TCP_6004).pdf + P2 + * + * 7E-01-02-00-06-00-20-47-05-52-32-00-00-30-31-32-33-34-35-06-7E + */ + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class HeadPack + { + public static byte FixPrefix = 0x7e; + + + + + public static Int32 PackSize = Marshal.SizeOf(typeof(HeadPack)); + + /// + /// 消息 ID + /// + public BigEndianUInt16 MessageId; + + /// + /// 消息体属性 + /// + public BigEndianUInt16 BodyProp; + + /// + /// 终端手机号 + /// + protected BCD8421_6BytesString DeviceId; + + + /// + /// 自增一序列号 + /// + public BigEndianUInt16 SeqNO; + + + public string GetDeviceId() + { + return string.Concat("460", DeviceId); + } + + public void SetDeviceId(string value) + { + if (value.Length > 12) + { + DeviceId = value.Substring(value.Length - 12, 12); + } + else + { + DeviceId = value.PadLeft(12, '0'); + } + } + + } + + + public static class BodyPropertyHelper + { + /// + /// 9-0 BIT + /// + /// + /// + public static Int16 GetMessageLength(BigEndianUInt16 val) + { + return (Int16)((UInt16)val & 0x03ff); + } + + /// + /// 9-0 BIT + /// + /// + /// + public static void SetMessageLength(ref BigEndianUInt16 val, UInt16 length) + { + val = (UInt16)(((UInt16)val & (~0x03ff)) + length); + } + + /// + /// 12-10 BIT + /// + /// + /// + public static Byte GetEncodeType(BigEndianUInt16 val) + { + return (Byte)((val >> 10) & 0x03); + } + + + public static void SetEncodeType(ref BigEndianUInt16 val, byte encType) + { + ushort v = val; + + v = (ushort)(v & ~(0x03 << 10) + encType << 10); + + val = v; + } + + /// + /// 13 BIT + /// + /// + /// + public static bool IsMutliPack(this BigEndianUInt16 val) + { + return ((val >> 13) & 0x01) == 0x0001; + } + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class PackProperty + { + public static Int32 PackSize = Marshal.SizeOf(typeof(PackProperty)); + + public BigEndianUInt16 Total; + public BigEndianUInt16 Index; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class ServerAnswerPack + { + public static Int32 PackSize = Marshal.SizeOf(typeof(ServerAnswerPack)); + + + /// + /// 流水 + /// + public BigEndianUInt16 SeqNO; + + /// + /// 消息ID + /// + public BigEndianUInt16 MessageId; + + + /// + /// 结果 0:成功/确认 1:失败 2:消息有误 3:不支持 4:报警处理确认 + /// + public byte Result; + } + + /// + /// 终端通用应答 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class ClientAnswerPack + { + public static Int32 PackSize = Marshal.SizeOf(typeof(ServerAnswerPack)); + + + /// + /// 流水 + /// + public BigEndianUInt16 SeqNO; + + /// + /// 消息ID + /// + public BigEndianUInt16 MessageId; + + + /// + /// 结果 0:成功/确认 1:失败 2:消息有误 3:不支持 + /// + public byte Result; + } + + /// + /// 终端注册 最后是GBK字串,车牌号 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class ClientRegistPack + { + public static Int32 PackSize = Marshal.SizeOf(typeof(ClientRegistPack)); + + /// + /// 省 + /// + public BigEndianUInt16 Province; + + /// + /// 市 + /// + public BigEndianUInt16 City; + + /// + /// 制造商 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] Manufacturer; + + /// + /// 终端型号 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] DeviceModel; + + + /// + /// 终端ID + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] DeviceId; + + + /// + /// 车牌颜色 + /// + public byte CarColor; + + + //最后是GBK字串,车牌号 + + + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class ClientRegistReturnPack + { + /// + /// 自增一序列号 + /// + public BigEndianUInt16 SeqNum; + + /// + /// 0成功, 1车辆已经注册, 2数据库中无此车辆, 3终端已经被注册, 4数据库中无该终端 + /// + public Byte Result; + } + + /// + /// 位置包汇报 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class PositionReportPack + { + public static Int32 PackSize = Marshal.SizeOf(typeof(PositionReportPack)); + + /// + /// 报警标志 + /// + public BigEndianUInt32 AlermFlags; + + + /// + /// 状态 + /// + public BigEndianUInt32 State; + + + + /// + /// 纬度 度*10^6 + /// + public BigEndianUInt32 Latitude; + + /// + /// 经度 度*10^6 + /// + public BigEndianUInt32 Longitude; + + /// + /// 高程 单位为米 + /// + public BigEndianUInt16 Altitude; + + /// + /// 速度 1/10KM/H + /// + public BigEndianUInt16 Speed; + + + /// + /// 方向 0~359 正北为0 顺时针 + /// + public BigEndianUInt16 Direction; + + /// + /// 时间 + /// + public BCD8421_6BytesString Time; + + + + } + + /// + /// 立即拍照命令 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class CmdPhotographePack + { + /// + /// 通道ID > 0 + /// + public Byte Channel; + + /// + /// 拍摄命令 0表示停止拍摄;0xffff表示录像;其它表示拍摄张数 + /// + public BigEndianUInt16 Cmd; + + /// + /// 拍照间隔,录像时间。 单位为秒,0表示最小间隔拍照或者一直录像 + /// + public BigEndianUInt16 Interval; + + /// + /// 保存标志 1保存 0立即上传 + /// + public byte Deal; + + /// + /// 图像分辨率 0x01:320*240 0x02:640*480 0x03:800*600 0x04:1024*768 + /// 0x05:176*144(Qcif) 0x06:352*288(Cif) 0x07:704*288(HALF D1) 0x08:704*546(D1) + /// + public byte Resolution; + + /// + /// 图像质量 1 ~ 10 1表示质量损失最小, 10表示压缩最大 + /// + public byte Quality; + + /// + /// 亮度 0 ~ 255 + /// + public byte Brightness; + + /// + /// 对比度 0 ~ 127 + /// + public byte Contrast; + + /// + /// 饱和度 0 ~ 127 + /// + public byte Saturation; + + + /// + /// 色度 0 ~ 255 + /// + public byte Chroma; + + + + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class CmdSendTextPack + { + public byte Flag; + + + /// + /// 紧急 + /// + public bool IsUrgent + { + get { return (Flag & 0x01) == 0x01; } + set { Flag = (byte)(Flag | 0x01); } + } + + /// + /// 终端显示器显示 + /// + public bool IsDisplay + { + get { return (Flag & 0x04) == 0x04; } + set { Flag = (byte)(Flag | 0x04); } + } + /// + /// 终端显示器显示 + /// + public bool IsTTS + { + get { return (Flag & 0x08) == 0x08; } + set { Flag = (byte)(Flag | 0x08); } + } + + /// + /// 终端显示器显示 + /// + public bool IsAD + { + get { return (Flag & 0x10) == 0x10; } + set { Flag = (byte)(Flag | 0x10); } + } + + //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)] + //public byte[] MessageBytes; + } + + + /// + /// 多媒体数据上传 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class GpsMultimediaUploadPack + { + public static Int32 PackSize = Marshal.SizeOf(typeof(GpsMultimediaUploadPack)); + + /// + /// 多媒体ID >0 + /// + public BigEndianUInt32 ID; + + /// + /// 多媒体类型 0:图像 1:音频 2:视频 + /// + public Byte Type; + + /// + /// 多媒体格式编码 0:JPEG 1:TIF 2:MP3 3:WAV 4:WMV + /// + public byte Format; + + /// + /// 事件项编码 0:平台下发指令 1:定时动作 2:抢劫报警触发 3:碰撞侧翻触发报警 4:保留 + /// + public byte EventCode; + + /// + /// 通道ID > 0 + /// + public Byte Channel; + + + + } + + /// + /// 多媒体数据上传 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public class GpsMultimediaReUploadPack + { + public static Int32 PackSize = Marshal.SizeOf(typeof(GpsMultimediaReUploadPack)); + + /// + /// 多媒体ID >0 + /// + public BigEndianUInt32 ID; + + /// + /// 多媒体类型 0:图像 1:音频 2:视频 + /// + public Byte Count; + + ///// + ///// 要求重发的下一个包 + ///// + //public Byte NextIndex; + + + + } + + + public class BitValueState + { + private BitArray bitArray; + public BitValueState(ushort state) + { + this.bitArray = new BitArray(BitConverter.GetBytes(state)); + } + + /// + /// ACC 开关 + /// + bool ACC + { + get + { + return bitArray[0]; + } + set + { + bitArray[0] = value; + } + } + + /// + /// 是否定位 + /// + //Position = 0x0002, + bool Position + { + get + { + return bitArray[1]; + } + set + { + bitArray[1] = value; + } + } + + /// + /// 0北纬 1南纬 + /// + //NorthOrSouth = 0x0004, + bool IsSouth + { + get + { + return bitArray[2]; + } + set + { + bitArray[2] = value; + } + } + /// + /// 0东经 1西经 + /// + //EastOrWest = 0x0008, + bool IsWest + { + get + { + return bitArray[3]; + } + set + { + bitArray[3] = value; + } + } + /// + /// 0运营状态 1停运 + /// + //OperationState = 0x0010, + bool OperationStoped + { + get + { + return bitArray[4]; + } + set + { + bitArray[4] = value; + } + } + /// + /// 经纬度是否加密 + /// + //EncodeLongitudeLatitude = 0x0020, + bool EncodeLongitudeLatitude + { + get + { + return bitArray[5]; + } + set + { + bitArray[5] = value; + } + } + /// + /// 0车辆油路正常 1断开 + /// + //CarOilchannel = 0x0400, + bool CarOilchannelBreaked + { + get + { + return bitArray[10]; + } + set + { + bitArray[10] = value; + } + } + /// + /// 0车辆电子正常 1断开 + /// + //CarCircuit = 0x0800, + bool CarCircuitBreaked + { + get + { + return bitArray[11]; + } + set + { + bitArray[11] = value; + } + } + /// + /// 0车辆车门解锁 1加锁 + /// + //CarDoorLock = 0x1000 + bool CarDoorLocked + { + get + { + return bitArray[12]; + } + set + { + bitArray[12] = value; + } + } + } + + public class BitValueAlerm + { + //private uint data; + private BitArray bitArray; + public BitValueAlerm(UInt32 alerm) + { + //this.data = alerm; + bitArray = new BitArray(new int[] { (int)alerm }); + } + + /// + /// 紧急报警, 触动报警开关后触发 收到答应后清除 + /// + bool Urgent + { + get + { + return bitArray[0]; + } + set + { + bitArray[0] = value; + } + + } + + /// + /// 超速报警 标志维持到报警条件解除 + /// + bool Speeding + { + get + { + return bitArray[1]; + } + set + { + bitArray[1] = value; + } + + } + + + /// + /// 疲劳驾驶 标志维持到报警条件解除 + /// + bool Fatigue + { + get + { + return bitArray[2]; + } + set + { + bitArray[2] = value; + } + + } + + /// + /// 预警 收到答应后清除 + /// + bool Forewarning + { + get + { + return bitArray[3]; + } + set + { + bitArray[3] = value; + } + + } + + //TODO:未完, 以后用到添加 + + } + + + + + public enum MessageIds : ushort + { + + /// + /// 终端通用应答 + /// + ClientAnswer = 0x0001, + + + + /// + /// 终端心跳 + /// + ClientPump = 0x0002, + + /// + /// 终端注销 + /// + ClientUnregist = 0x0003, + + + /// + /// 终端注册 + /// + ClientRegist = 0x0100, + + + /// + /// 终端鉴权 + /// + ClientAuth = 0x0102, + + /// + /// 位置信息汇报 + /// + PositionReport = 0x0200, + + /// + /// 多媒体事件信息上传 + /// + MultimediaEventUpload = 0x0800, + + /// + /// 多媒体数据上传 + /// + MultimediaUpload = 0x0801, + + /// + /// 多媒体数据上传 + /// + MultimediaUploadAnswer = 0x8800, + + /// + /// 平台通用应答 + /// + ServerAnswer = 0x8001, + + + /// + /// 终端注册应答 + /// + ClientRegistReturn = 0x8100, + + /// + /// 立即拍照 + /// + Photographe = 0x8801, + + /// + /// 下发文本 + /// + SendTextMessage = 0x8300 + + + + } + + + + + +} diff --git a/app.config b/app.config new file mode 100644 index 0000000..a8c2a3d --- /dev/null +++ b/app.config @@ -0,0 +1,85 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dll/Plugin.Common.dll b/dll/Plugin.Common.dll new file mode 100644 index 0000000..255f322 Binary files /dev/null and b/dll/Plugin.Common.dll differ diff --git a/dll/log4net.dll b/dll/log4net.dll new file mode 100644 index 0000000..ffc57e1 Binary files /dev/null and b/dll/log4net.dll differ