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