gis:ks102 设备解码
与ks108同一个项目,ks102为编写手持gps模块,个人、宠物使用
1
#
-- coding:utf-8 --
2 # TK102 解码器定义
3 # 这个设备没有包头包尾格式定义,假定一次读取一个完整数据包
4
5 # from aobject import *
6 import os,os.path,sys,time,datetime,copy,struct,array,traceback
7 # import codec
8
9 # MediaCodecType = MediaDataType
10 class MediaDataType:
11 GPS = 1 << 0
12 AUDIO = 1 << 1
13 VIDEO = 1 << 2
14 IMAGE = 1 << 3
15 TEXT = 1 << 4
16 IODATA = 1 << 5
17 RAWBLOB = 1 << 6
18 COMMAND = 1 << 7 # 通用命令
19 ALARM = 1 << 8 # 报警信息
20 UNDEFINED = 0xff
21
22
23 AOCTRL_CMD_SHAKE_ACK = 1 # 应答握手信号信息
24 AOCTRL_CMD_REG_ACK = 2 # 终端注册响应消息
25 AOCTRL_CMD_SAMPLING_TIMESET = 3 # 等时连续回传设置
26 AOCTRL_CMD_ALARM_ACK = 4 # 应答报警消息
27 AOCTRL_CMD_NAMED = 5 # 一次点名消息
28 AOCTRL_CMD_SPEEDSET = 6 # 设置车速上下限
29 AOCTRL_CMD_POWER_ONOFF = 7 # 电路控制信号
30 AOCTRL_CMD_OIL_ONOFF = 8 # 油路控制信号
31 AOCTRL_CMD_REBOOT = 9 # 控制设备重启消息
32 AOCTRL_CMD_ACC_ON_TIME = 10 # 设置ACC开发送数据间隔
33 AOCTRL_CMD_ACC_OFF_TIME = 11 # 设置ACC关发送数据间隔
34 AOCTRL_CMD_BARRIER_SET = 12 # 设置电子围栏消息
35 AOCTRL_CMD_GETLOCATION = 13 # 应答获取终端所在位置消息
36 AOCTRL_CMD_LISTEN_START = 14 # 监听命令
37 AOCTRL_CMD_COMMADDR_SET = 15 # 设置终端IP地址和端口
38 AOCTRL_CMD_APN_SET = 16 # 设置APN消息
39 AOCTRL_CMD_GET_VERSION = 17 # 读取终端版本消息
40 AOCTRL_CMD_CLEAR_ALARMS = 18 # 取消所有报警消息
41 AOCTRL_CMD_CLEAR_MILES = 19 # 里程清零消息
42 AOCTRL_CMD_INIT_MILES = 20 # 里程初始化消息
43 AOCTRL_CMD_UPDATING = 21 # 启动升级消息
44
45 AOCTRL_CMD_SHACK_REQ = 31 # 握手信号消息
46 AOCTRL_CMD_REG_REQ = 32 # 终端注册信息
47 AOCTRL_CMD_SAMPLING_TIMESET_ACK = 32 # 应答等时连续回传设置
48 AOCTRL_CMD_ALARM_REQ = 33 # 警报消息
49 AOCTRL_CMD_NAMED_ACK = 34 # 应答点名信息
50 AOCTRL_CMD_SIMPLING_GPSDATA = 35 # 等时连续回传消息
51 AOCTRL_CMD_SIMPLING_END = 36 # 连续回传结束消息
52 AOCTRL_CMD_SPEEDSET_ACK = 37 # 应答设置车速上下限
53 AOCTRL_CMD_POWERCTRL_ACK = 38 # 应答电路控制
54 AOCTRL_CMD_OILCTRL_ACK = 39 # 应答油路控制
55 AOCTRL_CMD_REBOOT_ACK = 40 # 应答设备重启消息
56 AOCTRL_CMD_ACCON_TIMESET_ACK = 41 # 应答设置ACC开发送数据间隔
57 AOCTRL_CMD_ACCOFF_TIMESET_ACK = 42 # 应答设置ACC关发送数据间隔
58 AOCTRL_CMD_BARRIER_SET_ACK = 43 # 应答设置电子围栏消息
59 AOCTRL_CMD_GETLOCATION_ACK = 44 # 获取终端所在位置消息
60 AOCTRL_CMD_LISTEN_ACK = 45 # 应答监听命令
61 AOCTRL_CMD_COMMADDR_SET_ACK = 46 # 应答设置终端IP地址和端口
62 AOCTRL_CMD_APN_SET_ACK = 47 # 应答设置APN消息
63 AOCTRL_CMD_GETVERSION_ACK = 48 # 应答读取终端版本消息
64 AOCTRL_CMD_CLEAR_ALARMS_ACK = 49 # 应答取消所有报警消息
65 AOCTRL_CMD_CLEAR_MILES_ACK = 50 # 应答里程清零消息
66 AOCTRL_CMD_UPDATING_ACK = 61 # 应答启动升级消息
67 AOCTRL_CMD_INIT_MILES_ACK = 62 # 应答初始化里程消息
68
69 AOCTRL_CMD_LIST = {
70 AOCTRL_CMD_SHAKE_ACK:u ' 应答握手信号信息 ' ,
71 AOCTRL_CMD_REG_ACK:u ' 终端注册响应消息 ' ,
72 AOCTRL_CMD_SAMPLING_TIMESET:u ' 等时连续回传设置 ' ,
73 AOCTRL_CMD_ALARM_ACK:u ' 应答报警消息 ' ,
74 AOCTRL_CMD_NAMED:u ' 一次点名消息 ' ,
75 AOCTRL_CMD_SPEEDSET:u ' 设置车速上下限 ' ,
76
77 AOCTRL_CMD_POWER_ONOFF:u ' 电路控制信号 ' ,
78 AOCTRL_CMD_OIL_ONOFF:u ' 油路控制信号 ' ,
79 AOCTRL_CMD_REBOOT:u ' 控制设备重启消息 ' ,
80 AOCTRL_CMD_ACC_ON_TIME :u ' 设置ACC开发送数据间隔 ' ,
81 AOCTRL_CMD_ACC_OFF_TIME :u ' 设置ACC关发送数据间隔 ' ,
82 AOCTRL_CMD_BARRIER_SET :u ' 设置电子围栏消息 ' ,
83 AOCTRL_CMD_GETLOCATION :u ' 应答获取终端所在位置消息 ' ,
84 AOCTRL_CMD_LISTEN_START :u ' 监听命令 ' ,
85 AOCTRL_CMD_COMMADDR_SET :u ' 设置终端IP地址和端口 ' ,
86 AOCTRL_CMD_APN_SET :u ' 设置APN消息 ' ,
87 AOCTRL_CMD_GET_VERSION :u ' 读取终端版本消息 ' ,
88 AOCTRL_CMD_CLEAR_ALARMS :u ' 取消所有报警消息 ' ,
89 AOCTRL_CMD_CLEAR_MILES :u ' 里程清零消息 ' ,
90 AOCTRL_CMD_INIT_MILES :u ' 里程初始化消息 ' ,
91 AOCTRL_CMD_UPDATING :u ' 启动升级消息 ' ,
92
93 AOCTRL_CMD_SHACK_REQ :u ' 握手信号消息 ' ,
94 AOCTRL_CMD_REG_REQ :u ' 终端注册信息 ' ,
95 AOCTRL_CMD_SAMPLING_TIMESET_ACK :u ' 应答等时连续回传设置 ' ,
96 AOCTRL_CMD_ALARM_REQ :u ' 警报消息 ' ,
97 AOCTRL_CMD_NAMED_ACK :u ' 应答点名信息 ' ,
98 AOCTRL_CMD_SIMPLING_GPSDATA :u ' 等时连续回传消息 ' ,
99 AOCTRL_CMD_SIMPLING_END :u ' 连续回传结束消息 ' ,
100 AOCTRL_CMD_SPEEDSET_ACK :u ' 应答设置车速上下限 ' ,
101 AOCTRL_CMD_POWERCTRL_ACK :u ' 应答电路控制 ' ,
102 AOCTRL_CMD_OILCTRL_ACK :u ' 应答油路控制 ' ,
103 AOCTRL_CMD_REBOOT_ACK :u ' 应答设备重启消息 ' ,
104 AOCTRL_CMD_ACCON_TIMESET_ACK :u ' 应答设置ACC开发送数据间隔 ' ,
105 AOCTRL_CMD_ACCOFF_TIMESET_ACK:u ' 应答设置ACC关发送数据间隔 ' ,
106 AOCTRL_CMD_BARRIER_SET_ACK :u ' 应答设置电子围栏消息 ' ,
107 AOCTRL_CMD_GETLOCATION_ACK :u ' 获取终端所在位置消息 ' ,
108 AOCTRL_CMD_LISTEN_ACK :u ' 应答监听命令 ' ,
109 AOCTRL_CMD_COMMADDR_SET_ACK:u ' 应答设置终端IP地址和端口 ' ,
110 AOCTRL_CMD_APN_SET_ACK:u ' 应答设置APN消息 ' ,
111 AOCTRL_CMD_GETVERSION_ACK:u ' 应答读取终端版本消息 ' ,
112 AOCTRL_CMD_CLEAR_ALARMS_ACK:u ' 应答取消所有报警消息 ' ,
113 AOCTRL_CMD_CLEAR_MILES_ACK:u ' 应答里程清零消息 ' ,
114 AOCTRL_CMD_UPDATING_ACK :u ' 应答启动升级消息 ' ,
115 AOCTRL_CMD_INIT_MILES_ACK :u ' 应答初始化里程消息 ' ,
116 }
117
118
119 ALARM_TYPELIST = {
120 0:u ' 车辆断电 ' ,
121 1 :u ' 电子围栏入界报警 ' ,
122 2 :u ' 车辆劫警(SOS求助) ' ,
123 3 :u ' 车辆防盗器警报 ' ,
124 4 :u ' 车辆低速报警 ' ,
125 5 :u ' 车辆超速报警 ' ,
126 6 :u ' 电子围栏出界报警 '
127 }
128
129
130 def parseTime(dmy,hms):
131 d,mon,y = map(int, map(float,[dmy[: 2 ],dmy[ 2 : 4 ],dmy[ 4 :]]) )
132 h,min,s = map(int, map(float,[hms[: 2 ],hms[ 2 : 4 ],hms[ 4 :]]) )
133 print d,mon,y,h,min,s
134 return time.mktime(( 2000 + y,mon,d,h,min,s,0,0,0))
135
136 def parseDegree(v):
137 pp = v.split( ' . ' )
138 mm1 = pp[0][ - 2 :]
139 mm2 = ' 0 '
140 if len(pp) > 1 :
141 mm2 = pp[ 1 ]
142 dd = pp[0][: - 2 ]
143 mm = mm1 + " . " + mm2
144 degree = float(dd) + float(mm) / 60.0
145 return degree
146
147 # 1节等于每小时 1海里,也就是每小时行驶1.852千米(公里)
148 def parseSpeed(s):
149 km = 0
150 km = float(s) * 1.852
151 return km
152
153
154 # 简单的模拟gps接收解码器
155 # gps接收程序解析之后连接本地的TcpService端口,并传送过来
156 # 只有简单的gps数据,模拟端口打开
157 class MediaCodec_KS102:
158 def __init__ (self):
159 self.buf = ''
160 self.conn = None
161 self.errtimes = 0 # 解析出错次数达到指定数则断开连接
162
163
164
165 # parse - codec 必须实现
166 # 对于某些设备的请求消息,这里必须进行默认的应答
167 # 如果出现大量数据包的要发送回设备的情况,考虑建立队列,用工作线程
168 # 慢慢发送,因为parse还在socket接收线程中
169 def parse(self,aom,d):
170 pass
171
172 def crc_16_result(self,d):
173 # struct.unpack('I')
174 print d
175 i = 0
176 j = 0
177 c = 0
178 treat = 0
179 bcrc = 0
180 crc = 0
181 s = array.array( ' B ' )
182 s.fromstring(d)
183 # print len(s)
184 for i in range(len(s)):
185 c = s[i]
186 for j in range( 8 ):
187 treat = c & 0x80
188 c = (c << 1 ) & 0xff
189
190 bcrc = ( crc >> 8 ) & 0xff
191 bcrc = bcrc & 0x80
192 # print crc
193 crc = (crc << 1 ) & 0xffff
194 # print crc
195 if treat != bcrc:
196 crc = (crc ^ 0x1021 ) & 0xffff
197 # print '..',crc
198
199 return crc
200
201
202 def decode(self,s,conn):
203 # @return: packets,retry
204 # 解码出多个消息包,并返回是否
205 # imei 视为设备唯一编号 mid
206 self.conn = conn
207 msglist = []
208 retry = True
209 print s
210 try :
211 p = s.find( ' , ' )
212 d = s[p + 1 : - 2 ]
213 crc = s[ - 2 :]
214 sum, = struct.unpack( ' H ' ,crc)
215 if self.crc_16_result(d) != sum:
216 print ' crc error '
217 return (),True
218 # 13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114
219 print d
220 # print d.split(',')[-1]
221 # tel,gprmc,hms,av,lat,ns,lon,ew,speed,angle,dmy,p1,p2,mode,FL,battery,imei,msglen, = d.split(',')
222 tel,gprmc,hms,av,lat,ns,lon,ew,speed,angle,dmy,p1,p2,mode,FL,imei,msglen, = d.split( ' , ' )
223 imei = imei.split( ' : ' )[ 1 ]
224 angle = float(angle)
225 speed = float(speed) * 1.852 # 节到km转换
226 lon = parseDegree(lon)
227 lat = parseDegree(lat)
228 time = parseTime(dmy,hms) + 3600 * 8 # 时间加上GMT8
229 gps = {
230 ' time ' :time,
231 ' lon ' :lon,
232 ' lat ' :lat,
233 ' speed ' :speed,
234 ' angle ' :angle,
235 ' power ' :0,
236 ' acc ' :0,
237 ' miles ' :0
238 }
239 msg = {
240 ' mid ' :imei,
241 ' cmd ' :AOCTRL_CMD_SIMPLING_GPSDATA,
242 ' gps ' :gps,
243 }
244 msglist.append(msg)
245 except :
246 traceback.print_exc()
247 msglist = ()
248 retry = True
249 self.errtimes += 1
250 if self.errtimes > 4 : # 解析错误次数过多,断开连接
251 return (),False
252 return msglist,retry
253
254
255
256 # 执行设备命令
257 def command(self,aom,msg):
258 # cmd - object (json decoded)
259 # @return: 返回命令控制消息
260 cmd = msg[ ' cmd ' ]
261 code = ''
262 params = ''
263 if not msg.has_key( ' seq ' ):
264 msg[ ' seq ' ] = ' 0 ' * 12
265
266 if cmd == AOCTRL_CMD_REG_ACK: # 注册响应
267 code = " (%sAP05) " % (msg[ ' seq ' ])
268
269 # save to ctrl log
270 log = aom.gm.AO_CtrlLog()
271 log.ao = aom.ao.dbobj
272 log.cmd = cmd
273 log.time = datetime.datetime.now()
274 text = " %s: %s " % (AOCTRL_CMD_LIST[log.cmd],params)
275 log.comment = text[: 200 ]
276 log.save()
277
278 return code
279
280 # 将d数据写入db中
281 # 根据不同的数据进行hash分派 目前之后gps和告警信息进行分派
282 def save(self,aom,d):
283 # log = aom.gm.AO_CtrlLog()
284 # log.ao = aom.ao.dbobj
285 # log.cmd = d['cmd']
286 # log.time = datetime.datetime.now()
287 # text = "%s: %s"%(AOCTRL_CMD_LIST[log.cmd],d['params'])
288 # log.comment = text[:200]
289 # log.save()
290 # 以下存储gps数据和设备状态数据
291 print ' save: ' ,d
292 gps = d[ ' gps ' ]
293 if True:
294 # save to db
295 timestamp = gps[ ' time ' ]
296 g = aom.gm.AOMData_Gps()
297 g.ao = aom.ao.dbobj
298 g.savetime = datetime.datetime.fromtimestamp(timestamp)
299 g.lon = gps[ ' lon ' ]
300 g.lat = gps[ ' lat ' ]
301 g.speed = gps[ ' speed ' ]
302 g.angle = gps[ ' angle ' ]
303 g.power = 0
304 g.acc = 0
305 g.miles = 0
306 g.save()
307 # for dispatch
308 t = timestamp # time.mktime(g.savetime.timetuple())
309 s = { ' type ' :MediaDataType.GPS, ' hwid ' :aom.id,
310 ' lon ' :g.lon, ' lat ' :g.lat,
311 ' speed ' :g.speed, ' angle ' :g.angle,
312 ' satenum ' :0, ' sateused ' :0,
313 ' time ' :t,
314 ' power ' :g.power,
315 ' acc ' :g.acc,
316 ' miles ' :g.miles}
317 aom.dispatch(s) # 分派到 cached server
318
319
320 '''
321 TK102方案GPRS通讯协议
322 上传数据
323 “1003040220,13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114迁”
324
325 19个,分隔数据段
326
327 数据解析
328 “1003040220”
329 时间流水号: 2010年03月04日02时22分
330
331 “13145826175”
332 手机号码:授权情况下为授权号码,否则为最后操作tracker的手机号码,或则为空.
333 “GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*
334 6F”
335 GPRMC数据:GPS模块数据完整数据,单片机没有对其进行修改.
336
337 “F” 当前GPS是否有信号: F,表示有,L表示没有
338 “battery” 报警信息:【SOS报警:”help me”;电子砸烂报警:” Stockade”;移位报警:” move”;超速报警;” speed”;低电报警;” bat:”】,非报警数据此位置为空.
339 “imei:354776030402512” GPRS 模块IMEI号
340 “114” 数据长度【13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,】,括号内部的数据的长度,单位字节.
341 “迁” CRC检验:这是两个字节的十六进制数据,有时显示为乱码,又是显示为空,因为他是十六进制。
342 计算范围【13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114】
343 算法如下:
344 注意:此系统unsigned int 为16bits,对于PC软件,需要对结果做 &0XFFFF运算。
345 unsigned int CRC_16(unsigned char *buf, unsigned int datalen)
346 {
347 unsigned int i;
348 unsigned char j;
349 unsigned char c, treat, bcrc;
350 unsigned int crc = 0;
351
352 for (i = 0; i < datalen; i++)
353 {
354 c = buf[i];
355 for (j = 0; j < 8; j++)
356 {
357 treat = c & 0x80;
358 c <<= 1;
359 bcrc = (crc >> 8);
360 bcrc &= 0x80;
361 crc <<= 1;
362 if (treat != bcrc)
363 crc ^= 0x1021;
364 }
365 }
366 return crc;
367 }
368
369 附:GPS模块数据解释说明:
370
371 $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
372 <1> UTC时间,hhmmss.sss(时分秒.毫秒)格式
373 <2> 定位状态,A=有效定位,V=无效定位
374 <3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
375 <4> 纬度半球N(北半球)或S(南半球)
376 <5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
377 <6> 经度半球E(东经)或W(西经)
378 <7> 地面速率(000.0~999.9节,前面的0也将被传输)
379 <8> 地面航向(000.0~359.9度,以正北为参考基准,前面的0也将被传输)
380 <9> UTC日期,ddmmyy(日月年)格式
381 <10> 磁偏角(000.0~180.0度,前面的0也将被传输)
382 <11> 磁偏角方向,E(东)或W(西)
383 <12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
384
385 '''
386 # c = MediaCodec_KS102()
387 # d="1106160039,13916624477,GPRMC,163905.000,A,3104.2062,N,12130.0542,E,0.33,347.69,150611,,,D*6C,F,imei:354779033883985,105"
388 # d="13916624477,GPRMC,163905.000,A,3104.2062,N,12130.0542,E,0.33,347.69,150611,,,D*6C,F,imei:354779033883985,105"
389 #
390 # log = open('ks102_data.txt','rb')
391 # s = log.read()
392 # print c.decode(s,None)
393
394
2 # TK102 解码器定义
3 # 这个设备没有包头包尾格式定义,假定一次读取一个完整数据包
4
5 # from aobject import *
6 import os,os.path,sys,time,datetime,copy,struct,array,traceback
7 # import codec
8
9 # MediaCodecType = MediaDataType
10 class MediaDataType:
11 GPS = 1 << 0
12 AUDIO = 1 << 1
13 VIDEO = 1 << 2
14 IMAGE = 1 << 3
15 TEXT = 1 << 4
16 IODATA = 1 << 5
17 RAWBLOB = 1 << 6
18 COMMAND = 1 << 7 # 通用命令
19 ALARM = 1 << 8 # 报警信息
20 UNDEFINED = 0xff
21
22
23 AOCTRL_CMD_SHAKE_ACK = 1 # 应答握手信号信息
24 AOCTRL_CMD_REG_ACK = 2 # 终端注册响应消息
25 AOCTRL_CMD_SAMPLING_TIMESET = 3 # 等时连续回传设置
26 AOCTRL_CMD_ALARM_ACK = 4 # 应答报警消息
27 AOCTRL_CMD_NAMED = 5 # 一次点名消息
28 AOCTRL_CMD_SPEEDSET = 6 # 设置车速上下限
29 AOCTRL_CMD_POWER_ONOFF = 7 # 电路控制信号
30 AOCTRL_CMD_OIL_ONOFF = 8 # 油路控制信号
31 AOCTRL_CMD_REBOOT = 9 # 控制设备重启消息
32 AOCTRL_CMD_ACC_ON_TIME = 10 # 设置ACC开发送数据间隔
33 AOCTRL_CMD_ACC_OFF_TIME = 11 # 设置ACC关发送数据间隔
34 AOCTRL_CMD_BARRIER_SET = 12 # 设置电子围栏消息
35 AOCTRL_CMD_GETLOCATION = 13 # 应答获取终端所在位置消息
36 AOCTRL_CMD_LISTEN_START = 14 # 监听命令
37 AOCTRL_CMD_COMMADDR_SET = 15 # 设置终端IP地址和端口
38 AOCTRL_CMD_APN_SET = 16 # 设置APN消息
39 AOCTRL_CMD_GET_VERSION = 17 # 读取终端版本消息
40 AOCTRL_CMD_CLEAR_ALARMS = 18 # 取消所有报警消息
41 AOCTRL_CMD_CLEAR_MILES = 19 # 里程清零消息
42 AOCTRL_CMD_INIT_MILES = 20 # 里程初始化消息
43 AOCTRL_CMD_UPDATING = 21 # 启动升级消息
44
45 AOCTRL_CMD_SHACK_REQ = 31 # 握手信号消息
46 AOCTRL_CMD_REG_REQ = 32 # 终端注册信息
47 AOCTRL_CMD_SAMPLING_TIMESET_ACK = 32 # 应答等时连续回传设置
48 AOCTRL_CMD_ALARM_REQ = 33 # 警报消息
49 AOCTRL_CMD_NAMED_ACK = 34 # 应答点名信息
50 AOCTRL_CMD_SIMPLING_GPSDATA = 35 # 等时连续回传消息
51 AOCTRL_CMD_SIMPLING_END = 36 # 连续回传结束消息
52 AOCTRL_CMD_SPEEDSET_ACK = 37 # 应答设置车速上下限
53 AOCTRL_CMD_POWERCTRL_ACK = 38 # 应答电路控制
54 AOCTRL_CMD_OILCTRL_ACK = 39 # 应答油路控制
55 AOCTRL_CMD_REBOOT_ACK = 40 # 应答设备重启消息
56 AOCTRL_CMD_ACCON_TIMESET_ACK = 41 # 应答设置ACC开发送数据间隔
57 AOCTRL_CMD_ACCOFF_TIMESET_ACK = 42 # 应答设置ACC关发送数据间隔
58 AOCTRL_CMD_BARRIER_SET_ACK = 43 # 应答设置电子围栏消息
59 AOCTRL_CMD_GETLOCATION_ACK = 44 # 获取终端所在位置消息
60 AOCTRL_CMD_LISTEN_ACK = 45 # 应答监听命令
61 AOCTRL_CMD_COMMADDR_SET_ACK = 46 # 应答设置终端IP地址和端口
62 AOCTRL_CMD_APN_SET_ACK = 47 # 应答设置APN消息
63 AOCTRL_CMD_GETVERSION_ACK = 48 # 应答读取终端版本消息
64 AOCTRL_CMD_CLEAR_ALARMS_ACK = 49 # 应答取消所有报警消息
65 AOCTRL_CMD_CLEAR_MILES_ACK = 50 # 应答里程清零消息
66 AOCTRL_CMD_UPDATING_ACK = 61 # 应答启动升级消息
67 AOCTRL_CMD_INIT_MILES_ACK = 62 # 应答初始化里程消息
68
69 AOCTRL_CMD_LIST = {
70 AOCTRL_CMD_SHAKE_ACK:u ' 应答握手信号信息 ' ,
71 AOCTRL_CMD_REG_ACK:u ' 终端注册响应消息 ' ,
72 AOCTRL_CMD_SAMPLING_TIMESET:u ' 等时连续回传设置 ' ,
73 AOCTRL_CMD_ALARM_ACK:u ' 应答报警消息 ' ,
74 AOCTRL_CMD_NAMED:u ' 一次点名消息 ' ,
75 AOCTRL_CMD_SPEEDSET:u ' 设置车速上下限 ' ,
76
77 AOCTRL_CMD_POWER_ONOFF:u ' 电路控制信号 ' ,
78 AOCTRL_CMD_OIL_ONOFF:u ' 油路控制信号 ' ,
79 AOCTRL_CMD_REBOOT:u ' 控制设备重启消息 ' ,
80 AOCTRL_CMD_ACC_ON_TIME :u ' 设置ACC开发送数据间隔 ' ,
81 AOCTRL_CMD_ACC_OFF_TIME :u ' 设置ACC关发送数据间隔 ' ,
82 AOCTRL_CMD_BARRIER_SET :u ' 设置电子围栏消息 ' ,
83 AOCTRL_CMD_GETLOCATION :u ' 应答获取终端所在位置消息 ' ,
84 AOCTRL_CMD_LISTEN_START :u ' 监听命令 ' ,
85 AOCTRL_CMD_COMMADDR_SET :u ' 设置终端IP地址和端口 ' ,
86 AOCTRL_CMD_APN_SET :u ' 设置APN消息 ' ,
87 AOCTRL_CMD_GET_VERSION :u ' 读取终端版本消息 ' ,
88 AOCTRL_CMD_CLEAR_ALARMS :u ' 取消所有报警消息 ' ,
89 AOCTRL_CMD_CLEAR_MILES :u ' 里程清零消息 ' ,
90 AOCTRL_CMD_INIT_MILES :u ' 里程初始化消息 ' ,
91 AOCTRL_CMD_UPDATING :u ' 启动升级消息 ' ,
92
93 AOCTRL_CMD_SHACK_REQ :u ' 握手信号消息 ' ,
94 AOCTRL_CMD_REG_REQ :u ' 终端注册信息 ' ,
95 AOCTRL_CMD_SAMPLING_TIMESET_ACK :u ' 应答等时连续回传设置 ' ,
96 AOCTRL_CMD_ALARM_REQ :u ' 警报消息 ' ,
97 AOCTRL_CMD_NAMED_ACK :u ' 应答点名信息 ' ,
98 AOCTRL_CMD_SIMPLING_GPSDATA :u ' 等时连续回传消息 ' ,
99 AOCTRL_CMD_SIMPLING_END :u ' 连续回传结束消息 ' ,
100 AOCTRL_CMD_SPEEDSET_ACK :u ' 应答设置车速上下限 ' ,
101 AOCTRL_CMD_POWERCTRL_ACK :u ' 应答电路控制 ' ,
102 AOCTRL_CMD_OILCTRL_ACK :u ' 应答油路控制 ' ,
103 AOCTRL_CMD_REBOOT_ACK :u ' 应答设备重启消息 ' ,
104 AOCTRL_CMD_ACCON_TIMESET_ACK :u ' 应答设置ACC开发送数据间隔 ' ,
105 AOCTRL_CMD_ACCOFF_TIMESET_ACK:u ' 应答设置ACC关发送数据间隔 ' ,
106 AOCTRL_CMD_BARRIER_SET_ACK :u ' 应答设置电子围栏消息 ' ,
107 AOCTRL_CMD_GETLOCATION_ACK :u ' 获取终端所在位置消息 ' ,
108 AOCTRL_CMD_LISTEN_ACK :u ' 应答监听命令 ' ,
109 AOCTRL_CMD_COMMADDR_SET_ACK:u ' 应答设置终端IP地址和端口 ' ,
110 AOCTRL_CMD_APN_SET_ACK:u ' 应答设置APN消息 ' ,
111 AOCTRL_CMD_GETVERSION_ACK:u ' 应答读取终端版本消息 ' ,
112 AOCTRL_CMD_CLEAR_ALARMS_ACK:u ' 应答取消所有报警消息 ' ,
113 AOCTRL_CMD_CLEAR_MILES_ACK:u ' 应答里程清零消息 ' ,
114 AOCTRL_CMD_UPDATING_ACK :u ' 应答启动升级消息 ' ,
115 AOCTRL_CMD_INIT_MILES_ACK :u ' 应答初始化里程消息 ' ,
116 }
117
118
119 ALARM_TYPELIST = {
120 0:u ' 车辆断电 ' ,
121 1 :u ' 电子围栏入界报警 ' ,
122 2 :u ' 车辆劫警(SOS求助) ' ,
123 3 :u ' 车辆防盗器警报 ' ,
124 4 :u ' 车辆低速报警 ' ,
125 5 :u ' 车辆超速报警 ' ,
126 6 :u ' 电子围栏出界报警 '
127 }
128
129
130 def parseTime(dmy,hms):
131 d,mon,y = map(int, map(float,[dmy[: 2 ],dmy[ 2 : 4 ],dmy[ 4 :]]) )
132 h,min,s = map(int, map(float,[hms[: 2 ],hms[ 2 : 4 ],hms[ 4 :]]) )
133 print d,mon,y,h,min,s
134 return time.mktime(( 2000 + y,mon,d,h,min,s,0,0,0))
135
136 def parseDegree(v):
137 pp = v.split( ' . ' )
138 mm1 = pp[0][ - 2 :]
139 mm2 = ' 0 '
140 if len(pp) > 1 :
141 mm2 = pp[ 1 ]
142 dd = pp[0][: - 2 ]
143 mm = mm1 + " . " + mm2
144 degree = float(dd) + float(mm) / 60.0
145 return degree
146
147 # 1节等于每小时 1海里,也就是每小时行驶1.852千米(公里)
148 def parseSpeed(s):
149 km = 0
150 km = float(s) * 1.852
151 return km
152
153
154 # 简单的模拟gps接收解码器
155 # gps接收程序解析之后连接本地的TcpService端口,并传送过来
156 # 只有简单的gps数据,模拟端口打开
157 class MediaCodec_KS102:
158 def __init__ (self):
159 self.buf = ''
160 self.conn = None
161 self.errtimes = 0 # 解析出错次数达到指定数则断开连接
162
163
164
165 # parse - codec 必须实现
166 # 对于某些设备的请求消息,这里必须进行默认的应答
167 # 如果出现大量数据包的要发送回设备的情况,考虑建立队列,用工作线程
168 # 慢慢发送,因为parse还在socket接收线程中
169 def parse(self,aom,d):
170 pass
171
172 def crc_16_result(self,d):
173 # struct.unpack('I')
174 print d
175 i = 0
176 j = 0
177 c = 0
178 treat = 0
179 bcrc = 0
180 crc = 0
181 s = array.array( ' B ' )
182 s.fromstring(d)
183 # print len(s)
184 for i in range(len(s)):
185 c = s[i]
186 for j in range( 8 ):
187 treat = c & 0x80
188 c = (c << 1 ) & 0xff
189
190 bcrc = ( crc >> 8 ) & 0xff
191 bcrc = bcrc & 0x80
192 # print crc
193 crc = (crc << 1 ) & 0xffff
194 # print crc
195 if treat != bcrc:
196 crc = (crc ^ 0x1021 ) & 0xffff
197 # print '..',crc
198
199 return crc
200
201
202 def decode(self,s,conn):
203 # @return: packets,retry
204 # 解码出多个消息包,并返回是否
205 # imei 视为设备唯一编号 mid
206 self.conn = conn
207 msglist = []
208 retry = True
209 print s
210 try :
211 p = s.find( ' , ' )
212 d = s[p + 1 : - 2 ]
213 crc = s[ - 2 :]
214 sum, = struct.unpack( ' H ' ,crc)
215 if self.crc_16_result(d) != sum:
216 print ' crc error '
217 return (),True
218 # 13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114
219 print d
220 # print d.split(',')[-1]
221 # tel,gprmc,hms,av,lat,ns,lon,ew,speed,angle,dmy,p1,p2,mode,FL,battery,imei,msglen, = d.split(',')
222 tel,gprmc,hms,av,lat,ns,lon,ew,speed,angle,dmy,p1,p2,mode,FL,imei,msglen, = d.split( ' , ' )
223 imei = imei.split( ' : ' )[ 1 ]
224 angle = float(angle)
225 speed = float(speed) * 1.852 # 节到km转换
226 lon = parseDegree(lon)
227 lat = parseDegree(lat)
228 time = parseTime(dmy,hms) + 3600 * 8 # 时间加上GMT8
229 gps = {
230 ' time ' :time,
231 ' lon ' :lon,
232 ' lat ' :lat,
233 ' speed ' :speed,
234 ' angle ' :angle,
235 ' power ' :0,
236 ' acc ' :0,
237 ' miles ' :0
238 }
239 msg = {
240 ' mid ' :imei,
241 ' cmd ' :AOCTRL_CMD_SIMPLING_GPSDATA,
242 ' gps ' :gps,
243 }
244 msglist.append(msg)
245 except :
246 traceback.print_exc()
247 msglist = ()
248 retry = True
249 self.errtimes += 1
250 if self.errtimes > 4 : # 解析错误次数过多,断开连接
251 return (),False
252 return msglist,retry
253
254
255
256 # 执行设备命令
257 def command(self,aom,msg):
258 # cmd - object (json decoded)
259 # @return: 返回命令控制消息
260 cmd = msg[ ' cmd ' ]
261 code = ''
262 params = ''
263 if not msg.has_key( ' seq ' ):
264 msg[ ' seq ' ] = ' 0 ' * 12
265
266 if cmd == AOCTRL_CMD_REG_ACK: # 注册响应
267 code = " (%sAP05) " % (msg[ ' seq ' ])
268
269 # save to ctrl log
270 log = aom.gm.AO_CtrlLog()
271 log.ao = aom.ao.dbobj
272 log.cmd = cmd
273 log.time = datetime.datetime.now()
274 text = " %s: %s " % (AOCTRL_CMD_LIST[log.cmd],params)
275 log.comment = text[: 200 ]
276 log.save()
277
278 return code
279
280 # 将d数据写入db中
281 # 根据不同的数据进行hash分派 目前之后gps和告警信息进行分派
282 def save(self,aom,d):
283 # log = aom.gm.AO_CtrlLog()
284 # log.ao = aom.ao.dbobj
285 # log.cmd = d['cmd']
286 # log.time = datetime.datetime.now()
287 # text = "%s: %s"%(AOCTRL_CMD_LIST[log.cmd],d['params'])
288 # log.comment = text[:200]
289 # log.save()
290 # 以下存储gps数据和设备状态数据
291 print ' save: ' ,d
292 gps = d[ ' gps ' ]
293 if True:
294 # save to db
295 timestamp = gps[ ' time ' ]
296 g = aom.gm.AOMData_Gps()
297 g.ao = aom.ao.dbobj
298 g.savetime = datetime.datetime.fromtimestamp(timestamp)
299 g.lon = gps[ ' lon ' ]
300 g.lat = gps[ ' lat ' ]
301 g.speed = gps[ ' speed ' ]
302 g.angle = gps[ ' angle ' ]
303 g.power = 0
304 g.acc = 0
305 g.miles = 0
306 g.save()
307 # for dispatch
308 t = timestamp # time.mktime(g.savetime.timetuple())
309 s = { ' type ' :MediaDataType.GPS, ' hwid ' :aom.id,
310 ' lon ' :g.lon, ' lat ' :g.lat,
311 ' speed ' :g.speed, ' angle ' :g.angle,
312 ' satenum ' :0, ' sateused ' :0,
313 ' time ' :t,
314 ' power ' :g.power,
315 ' acc ' :g.acc,
316 ' miles ' :g.miles}
317 aom.dispatch(s) # 分派到 cached server
318
319
320 '''
321 TK102方案GPRS通讯协议
322 上传数据
323 “1003040220,13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114迁”
324
325 19个,分隔数据段
326
327 数据解析
328 “1003040220”
329 时间流水号: 2010年03月04日02时22分
330
331 “13145826175”
332 手机号码:授权情况下为授权号码,否则为最后操作tracker的手机号码,或则为空.
333 “GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*
334 6F”
335 GPRMC数据:GPS模块数据完整数据,单片机没有对其进行修改.
336
337 “F” 当前GPS是否有信号: F,表示有,L表示没有
338 “battery” 报警信息:【SOS报警:”help me”;电子砸烂报警:” Stockade”;移位报警:” move”;超速报警;” speed”;低电报警;” bat:”】,非报警数据此位置为空.
339 “imei:354776030402512” GPRS 模块IMEI号
340 “114” 数据长度【13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,】,括号内部的数据的长度,单位字节.
341 “迁” CRC检验:这是两个字节的十六进制数据,有时显示为乱码,又是显示为空,因为他是十六进制。
342 计算范围【13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114】
343 算法如下:
344 注意:此系统unsigned int 为16bits,对于PC软件,需要对结果做 &0XFFFF运算。
345 unsigned int CRC_16(unsigned char *buf, unsigned int datalen)
346 {
347 unsigned int i;
348 unsigned char j;
349 unsigned char c, treat, bcrc;
350 unsigned int crc = 0;
351
352 for (i = 0; i < datalen; i++)
353 {
354 c = buf[i];
355 for (j = 0; j < 8; j++)
356 {
357 treat = c & 0x80;
358 c <<= 1;
359 bcrc = (crc >> 8);
360 bcrc &= 0x80;
361 crc <<= 1;
362 if (treat != bcrc)
363 crc ^= 0x1021;
364 }
365 }
366 return crc;
367 }
368
369 附:GPS模块数据解释说明:
370
371 $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
372 <1> UTC时间,hhmmss.sss(时分秒.毫秒)格式
373 <2> 定位状态,A=有效定位,V=无效定位
374 <3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
375 <4> 纬度半球N(北半球)或S(南半球)
376 <5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
377 <6> 经度半球E(东经)或W(西经)
378 <7> 地面速率(000.0~999.9节,前面的0也将被传输)
379 <8> 地面航向(000.0~359.9度,以正北为参考基准,前面的0也将被传输)
380 <9> UTC日期,ddmmyy(日月年)格式
381 <10> 磁偏角(000.0~180.0度,前面的0也将被传输)
382 <11> 磁偏角方向,E(东)或W(西)
383 <12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
384
385 '''
386 # c = MediaCodec_KS102()
387 # d="1106160039,13916624477,GPRMC,163905.000,A,3104.2062,N,12130.0542,E,0.33,347.69,150611,,,D*6C,F,imei:354779033883985,105"
388 # d="13916624477,GPRMC,163905.000,A,3104.2062,N,12130.0542,E,0.33,347.69,150611,,,D*6C,F,imei:354779033883985,105"
389 #
390 # log = open('ks102_data.txt','rb')
391 # s = log.read()
392 # print c.decode(s,None)
393
394