/// <summary> 解析基本车辆状态 /// 解析基本车辆状态 /// </summary> /// <param name="byt">待解析的状态数据字节数组</param> /// <param name="data">解析后的数据对象</param> private void GetVehicleState(byte[] byt, ref DiBiaoData data) { data.BaseData.PlunderState=1; //---------------------------------------------------byte1: byte byt0=byt[0]; //经度 if (Transfer.GetByteIndexValue(byt0, 0) == 1) { //东经 } else {//西经 } //纬度 if (Transfer.GetByteIndexValue(byt0, 1) == 1) {//北纬 } else {//南纬 } //紧急报警 if (Transfer.GetByteIndexValue(byt0, 2) == 1) {//报警 data.BaseData.PlunderState=0; } else {//正常 } //车辆控制 if (Transfer.GetByteIndexValue(byt0, 3) == 1) {//断油 data.BaseData.OilState=0; } else {//正常 data.BaseData.OilState=1; } //超速报警 if (Transfer.GetByteIndexValue(byt0, 4) == 1) {//报警 data.BaseData.PlunderState=23; } else{} //振动报警 if (Transfer.GetByteIndexValue(byt0, 5) == 1) { data.BaseData.PlunderState=2;//目前平台没有提示该功能。暂且标记为2 } else{} //主电源断电 if (Transfer.GetByteIndexValue(byt0, 6) == 1) { data.BaseData.PlunderState=16; } else{} //预留 //-----------------------------------------------------------byte2 byte byt1=byt[1]; //刹车 if (Transfer.GetByteIndexValue(byt1, 0) == 1) {//制动 } else {//正常 } //门边线 if (Transfer.GetByteIndexValue(byt1, 1) == 1) {//开门 data.BaseData.DoorStatus=1; } else {//关门 data.BaseData.DoorStatus=0; } //左转向灯 if (Transfer.GetByteIndexValue(byt1, 2) == 1) {//ON } else {//OFF } //右转向灯 if (Transfer.GetByteIndexValue(byt1, 3) == 1) {}//ON else {}//OFF //远光灯 if (Transfer.GetByteIndexValue(byt1, 4) == 1) {}//ON else {}//OFF //ACC if (Transfer.GetByteIndexValue(byt1, 5) == 1) { data.BaseData.ACCState=1; }//ON else { data.BaseData.ACCState=0; }//OFF //预留 //预留 //---------------------------------------------------------------byte3 byte byt2=byt[2]; //卫星定位锁定 if (Transfer.GetByteIndexValue(byt2, 0) == 1) { data.BaseData.IsLocatedData=true;//不知道该位是否表示已定位,暂且标记为已定位 }//锁定 else { data.BaseData.IsLocatedData = false; }//未锁定 //卫星定位天线 if (Transfer.GetByteIndexValue(byt2, 1) == 1) { data.BaseData.PlunderState=17; }//短路 else {}//正常 //卫星定位天线 if (Transfer.GetByteIndexValue(byt2, 2) == 1) { data.BaseData.PlunderState=18; }//开路 else {}//正常 //定位模块 if (Transfer.GetByteIndexValue(byt2, 3) == 1) {}//异常 else {}//正常 //通信模块 if (Transfer.GetByteIndexValue(byt2, 4) == 1) {}//异常 else {}//正常 //出区域越界 if (Transfer.GetByteIndexValue(byt2, 5) == 1) {}//越界 else {}//正常 //入区域越界 if (Transfer.GetByteIndexValue(byt2, 6) == 1) {}//越界 else {}//正常 //预留 //--------------------------------------------------------------byte4 byte byt3=byt[3]; //备用电池 if (Transfer.GetByteIndexValue(byt3, 0) == 1) {}//异常 else {}//正常 //地理栅栏 if (Transfer.GetByteIndexValue(byt3, 1) == 1) {}//越界 else {}//正常 //发动机 if (Transfer.GetByteIndexValue(byt3, 2) == 1) {}//ON else {}//OFF //疲劳驾驶 if (Transfer.GetByteIndexValue(byt3, 3) == 1) {}//报警 else {}//正常 //预留 //预留 //预留 //预留 //--------------------------------------------------byte5,//byte6,//byte7,//byte8预留 }
/// <summary> 解析上行数据 /// 解析上行数据(不包含帧头帧尾) /// </summary> /// <param name="byt"></param> /// <param name="data"></param> /// <param name="aResponseList"></param> /// <param name="gpscode"></param> private void DecodeUpData(byte[] byt, ref DiBiaoData data, out List<byte[]> aResponseList, out byte[] gpscode) { aResponseList = new List<byte[]>(); byte[] bytecode=new byte[2];//协议号 Array.Copy(byt,18,bytecode,0,2); byte bt=bytecode[1]; byte[] sourcedata = new byte[byt.Length - 22];//协议内容 Array.Copy(byt, 20, sourcedata, 0, sourcedata.Length); byte bytSequence = byt[1]; //流水号 byte[] bytgpscode = new byte[4];//GPSCODE Array.Copy(byt, 4, bytgpscode,0,4); gpscode = bytgpscode; data.BaseData.GPSCode = GetGpsCode(byt); data.FullGpsCode = base.CodePrefix + data.BaseData.GPSCode; switch (bt) { case 0x00: //00 上行 自动上传 按设置产生的卫星定位数据包 1条或多条 //00 上行 自动上传 多条卫星定位数据包 //00 上行 超速自动上传 1个卫星定位数据包 超速警情 //00 上行 区域报警自动上传 1个卫星定位数据包 超速警情,越界警情(告警时) //00 上行 道路报警自动上传 1个卫星定位数据包 超速警情,越界警情(告警时) //如何分包 未完成(有为不考虑分包) List<byte[]> datalists = new List<byte[]>(); //解析定位数据,返回数据对象(异常,补传数据的处理未完成) GetAnchorInfo(sourcedata, ref data); Logger.Trace("收到自动上传数据包"); break; case 0x01: //位置返回(查询当前位置的响应) 1个完整卫星定位数据包 每次只能返还一个卫星定位数据包 GetAnchorInfo(sourcedata, ref data); break; case 0x02: //02 上行 设置响应(定时监控设置的响应) 1个完整卫星定位数据包及发送参数 每次只能返还一个卫星定位数据包 GetAnchorInfo(sourcedata, ref data); Logger.Trace("定时监控设置确认"); break; case 0x03: //03 上行 查看参数响应 1条卫星定位数据包,采集定位数据时间间隔(1~FF)s,发送条数(0~FF),剩余发送包数(0~FFFF) break; case 0x04: //04 上行 设置响应(定距监控设置响应) 1个完整卫星定位数据包及发送参数 每次只能返还一个卫星定位数据包 break; case 0x05: //05 上行 查看参数响应(定距监控查看响应) 1条卫星定位数据包,采集定位数据距离间隔(50~9999)m,发送条数(0~FF),剩余发送包数(0~FFFF) 发送包数为FFFF时无包数限制 break; case 0x06: //06 上行 设置响应(速度监控设置响应) 1个完整卫星定位数据包 GetAnchorInfo(sourcedata, ref data); Logger.Trace("超速报警设置确认"); break; case 0x07: //07 上行 收到区域号总数,区域清单 例如6:23,45,34,26,12,66 break; case 0x08: //08 上行 区域设定总数N,第一区域编号X,第一区域点数M,经纬度1,经纬度2,…,经纬度M;第二区域编号X,…… break; case 0x09: //09 上行 回传设置成功,返回区域编号 应答 break; case 0x0a: //0a 上行 查看回应(区域监控查看回应) 区域设定总数N,区域编号1,限速设定(0~255)km/h),限速持续时间(0~FF)s,禁入禁出(四种情况,1字节),禁入禁出持续时间(0~FF)s 应答 break; case 0x0b: //0b 上行 设定响应(道路设定响应) 收到道路号总数,道路清单, break; case 0x0c: //0c 上行 设定响应(道路设定查看响应) 路段设定总数N,第一路段编号X,第一路段点数M,经纬度1,经纬度2,…,经纬度M;第二路段编号X,…… break; case 0x0d: //0d 上行 (道路监控) 设置成功,返回道路编号 应答 break; case 0x0e: //0e 上行 查看回应(道路监控查看) 路段设定总数N,第一路段编号X,限速设定((0~255)km/h) ,禁入禁出(四种情况,1字节),路段规定时间(时,分),偏离道路 x dam(10~2550m)第二路段编号X,…… 应答 break; case 0x0f: //0f 上行 (设备自检功能) 返回完整卫星定位数据包 break; case 0x10: //10 上行 (事故疑点数据) 返回停车序号,1,完整卫星定位数据包,2,完整卫星定位数据包,…,100,完整卫星定位数据包 break; case 0x11: //11 上行 (历史轨迹) N组数据,完整卫星定位数据包(至少平均速度) break; case 0x12: //12 上行 (驾驶员身份功能) 上传驾驶员身份信息(4个字节BCD),驾驶员驾驶时间(2个字节BCD) 6个字节BCD break; case 0x13: //13 上行 打印前上报 完整卫星定位数据包,打印前上报 break; case 0x14: //14 上行 (疲劳驾驶时限功能) 实际连续驾驶时间 break; case 0x15: //15 上行 (下发显示国标汉字信息) 返回完整卫星定位数据包及下发内容 break; case 0x16: //16 上行 上发国标汉字信息 发送完整卫星定位数据包及上发信息 break; case 0x17: //17 上行 紧急报警 返回完整卫星定位数据包 GetAnchorInfo(sourcedata, ref data); aResponseList.Add(SetDownDatagram("17", bytSequence, bytgpscode));//确认 Logger.Trace("报警确认"); aResponseList.Add(SetDownDatagram("18", bytSequence, bytgpscode));//解除 Logger.Trace("解除报警"); break; case 0x18: //18 上行 (紧急报警警情的解除) 返回完整卫星定位数据包 GetAnchorInfo(sourcedata, ref data); //aResponseList.Add(SetDownDatagram("18", bytSequence, bytgpscode));//解除报警 Logger.Trace("解除报警确认"); break; case 0x19: //19 上行 (远程断油控制) 返回完整卫星定位数据包及发出参数 GetAnchorInfo(sourcedata, ref data); Logger.Trace("油路控制确认"); break; case 0x1a: //1a 上行 (远程参数查看) 返回完整卫星定位数据包及发出参数 break; case 0x1b: //1b 上行 (远程参数设置) 返回完整卫星定位数据包及发出参数 break; case 0x1c: //1c 上行 (复位) 返回完整卫星定位数据包及发出参数 break; case 0x1d: //1d 上行 (加密钥报告) 1个完整卫星定位数据包+密钥 break; case 0xF8://F8 上行 有为增补协议 地标中有为增补的协议 break; } }
/// <summary> 解析基本定位数据 /// 解析基本定位数据 /// </summary> /// <param name="byt">待解析的基本定位数据字节数组</param> /// <param name="data">解析后的数据对象</param> private void GetAnchorInfo(byte[] byt, ref DiBiaoData data) { //时间6 byte[] time=new byte[6]; Array.Copy(byt,0,time,0,6); string strtime = Transfer.BCDtoDec(time, 6).ToString(); data.BaseData.ReportTime = GetTimeForstr(strtime); data.BaseData.ReceiveTime = DateTime.Now; //经度4 byte[] longitude=new byte[4]; Array.Copy(byt, 6, longitude, 0, 4); string strLongitude = Transfer.BCDtoDec(longitude, 4).ToString(); data.BaseData.Longitude = (decimal)GetLongiduteAndLatitudeForstr(strLongitude); //纬度4 byte[] Latitude=new byte[4]; Array.Copy(byt, 10, Latitude, 0, 4); string strLatitude = Transfer.BCDtoDec(Latitude, 4).ToString(); data.BaseData.Latitude = (decimal)GetLongiduteAndLatitudeForstr(strLatitude); Logger.Info("地标GPSCode:" + data.BaseData.GPSCode + ",Longitude:" + strLongitude+",Latitude:"+strLatitude); //速度1 byte[] speed=new byte[1]; Array.Copy(byt, 14, speed, 0, 1); data.BaseData.Speed = speed[0] & 0xff; //方向1 byte[] direction=new byte[1]; Array.Copy(byt,15,direction,0,1); data.BaseData.Direction = direction[0] & 0xff; //高度2 byte[] high=new byte[2]; Array.Copy(byt,16,high,0,2); data.High = ((high[0] & 0xff)<<8) + high[1] & 0xff; //里程4 byte[] mileage=new byte[4]; Array.Copy(byt,18,mileage,0,4); data.BaseData.StarkMileage = Transfer.BCDtoDec(mileage, 4) * 100; //状态8 byte[] state=new byte[8]; Array.Copy(byt,22,state,0,8); GetVehicleState(state,ref data); //处理异常漂移数据 data=CheckData(data); }
/// <summary> 判断是否需要发送定时监控,返回发送指令包 /// /// </summary> /// <param name="data"></param> /// <returns></returns> private byte[] RetuenAccTimeDatafram(DiBiaoData data) { byte[] byt = null; if (DicGPSTraceInterval.ContainsKey(data.BaseData.GPSCode))//若有特殊定时设置 { int second = DicGPSTraceInterval[data.BaseData.GPSCode].TimeAccOn; byt = SetAccTimeBytes(second); } else { int second = 15; byt = SetAccTimeBytes(second); } return byt; }
/// <summary> 分析GPS数据包 /// 分析GPS数据包 /// </summary> /// <param name="buf"></param> /// <param name="aDataStorage"></param> /// <param name="blnShouldResponse"></param> /// <param name="aResponseList"></param> /// <returns></returns> public List<GPSDataEntity> Parse(byte[] buf, out List<byte[]> aResponseList, out string gpsCode, string sessionID) { aResponseList = new List<byte[]>(); List<GPSDataEntity> lits = new List<GPSDataEntity>(); gpsCode = ""; try { //数据预处理,返回无帧头帧尾数据 byte[] buffer = Decode(buf); //gpsCode = GetGpsCode(buffer); //解析上传数据 byte[] bytgpsCode; DiBiaoData data = new DiBiaoData(); DecodeUpData(buffer, ref data, out aResponseList, out bytgpsCode); gpsCode = data.BaseData.GPSCode; #region 判断处理第一条数据 if (!String.IsNullOrEmpty(data.FullGpsCode)) { OnAddConnectionEvent(data.FullGpsCode, sessionID); } if (base.TransfersType== TransfersType.IsTcp) { //更新上一次数据 if (TCPConnList.Instance().IsFirstDataOfConn(sessionID)) { if (string.IsNullOrEmpty(data.FullGpsCode)) { Logger.Error("gpsData.FullGpsCode为空:" + data.BaseData.GPSCode, null); } //更改记录状态,标明以后的数据已不是第一点数据 TCPConnList.Instance().UpdateFirstDataRela(sessionID, 0); //定时监控 byte[] bytecontent = RetuenAccTimeDatafram(data); if (bytecontent != null) { Interlocked.Increment(ref SequenceNo); aResponseList.Add(SetDownDatagram("02", (byte)(SequenceNo & 0xff), bytgpsCode, bytecontent)); } } } else { //更新上一次数据 if (UDPConnList.Instance().IsFirstDataOfConn(sessionID)) { if (string.IsNullOrEmpty(data.FullGpsCode)) { Logger.Error("gpsData.FullGpsCode为空:" + data.BaseData.GPSCode, null); } //更改记录状态,标明以后的数据已不是第一点数据 UDPConnList.Instance().UpdateFirstDataRela(sessionID, 0); //定时监控 byte[] bytecontent = RetuenAccTimeDatafram(data); if (bytecontent != null) { Interlocked.Increment(ref SequenceNo); aResponseList.Add(SetDownDatagram("02", (byte)(SequenceNo & 0xff), bytgpsCode, bytecontent)); } } } #endregion lits.Add(data.BaseData); } catch (Exception ex) { Logger.Error(ex, null); } return lits; }
/// <summary> 检查异常漂移 /// 检查异常漂移,判断是否补传 /// </summary> ///<param name="obj">GPS信息</param> /// <param name="aPreviousValidGPSData">有效的上一点GPS数据</param> /// <param name="MaxSpeedMeterPerSecond">最大速度:米/秒</param> private bool ComputeMileAgeAndVerifyData(ref DiBiaoData DiBiaoData, GPSDataEntity aPreviousValidGPSData, double MaxSpeedMeterPerSecond) { bool flag = false; if (DiBiaoData.BaseData.IsLocatedData == false) { Logger.Fatal("未定位,GpsCode=" + DiBiaoData.FullGpsCode + " reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat)); return true; } //是否是第一个点 bool blnIsFirstGPSData = false; if (aPreviousValidGPSData == null) { blnIsFirstGPSData = true; } TimeSpan dtSpan; double dclMileage = 0; if (!blnIsFirstGPSData) { if (DateTime.Compare(DiBiaoData.BaseData.ReportTime, aPreviousValidGPSData.ReportTime) <= 0) { DiBiaoData.BaseData.IsFetchData = true; flag = true; Logger.Fatal("补传数据,GpsCode=" + DiBiaoData.FullGpsCode + " reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat) + " 上一点reporttime:" + aPreviousValidGPSData.ReportTime.ToString(strTimeFormat)); } //若当前数据时间大于服务器时间1小时,认为是异常数据,标记为无效数据 if (DiBiaoData.BaseData.ReportTime >= DateTime.Now.AddHours(1)) { DiBiaoData.BaseData.IsOverflowGPSData = true; flag = true; Logger.Fatal("当前数据时间大于服务器时间1小时,GpsCode=" + DiBiaoData.FullGpsCode + " reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat)); } double CurrentLatitude = Convert.ToDouble(DiBiaoData.BaseData.Latitude); double CurrentLongitude = Convert.ToDouble(DiBiaoData.BaseData.Longitude); double LastLatitude = Convert.ToDouble(aPreviousValidGPSData.Latitude); double LastLongitude = Convert.ToDouble(aPreviousValidGPSData.Longitude); if ((CurrentLatitude != LastLatitude) || (CurrentLongitude != LastLongitude)) { dclMileage = Transfer.GetDistance(LastLatitude, LastLongitude, CurrentLatitude, CurrentLongitude); } //计算当前点与其上一点之间的时间差 dtSpan = DiBiaoData.BaseData.ReportTime - aPreviousValidGPSData.ReportTime; //两点之间最大比较里程 double dclMaxMileage = Math.Abs(Convert.ToDouble(MaxSpeedMeterPerSecond * dtSpan.TotalSeconds)); //最大比较速度:换算为公里/每小时 double maxSpeed = MaxSpeedMeterPerSecond * 3.6; //速度过大或里程过大,均认为是漂移数据 if (dclMileage > dclMaxMileage || DiBiaoData.BaseData.Speed > (decimal)maxSpeed) { //异常:GPS漂移数据 DiBiaoData.BaseData.IsOverflowGPSData = true; flag = true; Logger.Fatal("漂移数据,GpsCode=" + DiBiaoData.FullGpsCode + " reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat) + " 上一点reporttime:" + aPreviousValidGPSData.ReportTime.ToString(strTimeFormat)); } } else//上一点数据为NULL,表明是第一点数据 { if (DiBiaoData.BaseData.ReportTime >= DateTime.Now.AddHours(1)) { DiBiaoData.BaseData.IsOverflowGPSData = true; flag = true; Logger.Fatal("第一点位置数据时间大于服务器时间1小时,GpsCode=" + DiBiaoData.BaseData.GPSCode + " reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat)); } else if (DiBiaoData.BaseData.ReportTime <= DateTime.Now.AddDays(-1)) { DiBiaoData.BaseData.IsOverflowGPSData = true; flag = true; Logger.Fatal("第一点位置数据时间小于服务器时间1天,GpsCode=" + DiBiaoData.BaseData.GPSCode + " reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat)); } else if (DiBiaoData.BaseData.Latitude < 1 || DiBiaoData.BaseData.Longitude < 1 || DiBiaoData.BaseData.Speed > 500) { DiBiaoData.BaseData.IsOverflowGPSData = true; flag = true; Logger.Fatal("第一点位置数据经纬度或速度异常。GpsCode=" + DiBiaoData.BaseData.GPSCode + ",Latitude="+DiBiaoData.BaseData.Latitude+",Longitude="+DiBiaoData.BaseData.Longitude+",Speed="+DiBiaoData.BaseData.Speed+", reporttime:" + DiBiaoData.BaseData.ReportTime.ToString(strTimeFormat)); } } return flag; }
/// <summary> 处理异常漂移补传数据 /// 处理异常漂移补传数据 /// </summary> /// <param name="currdata">当前点数据</param> /// <param name="StrCodePrefix">前缀</param> /// <param name="aConnection">数据库连接</param> /// <returns></returns> private DiBiaoData CheckData(DiBiaoData currdata) { return currdata; }