1 # -- coding:utf-8 --
2 #TK102 解碼器定義
3 #這個設(shè)備沒有包頭包尾格式定義,假定一次讀取一個完整數(shù)據(jù)包
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 #應(yīng)答握手信號信息
24 AOCTRL_CMD_REG_ACK= 2 #終端注冊響應(yīng)消息
25 AOCTRL_CMD_SAMPLING_TIMESET = 3 #等時連續(xù)回傳設(shè)置
26 AOCTRL_CMD_ALARM_ACK = 4 #應(yīng)答報警消息
27 AOCTRL_CMD_NAMED = 5 #一次點名消息
28 AOCTRL_CMD_SPEEDSET = 6 #設(shè)置車速上下限
29 AOCTRL_CMD_POWER_ONOFF = 7 #電路控制信號
30 AOCTRL_CMD_OIL_ONOFF = 8 #油路控制信號
31 AOCTRL_CMD_REBOOT = 9 #控制設(shè)備重啟消息
32 AOCTRL_CMD_ACC_ON_TIME = 10 #設(shè)置ACC開發(fā)送數(shù)據(jù)間隔
33 AOCTRL_CMD_ACC_OFF_TIME = 11 #設(shè)置ACC關(guān)發(fā)送數(shù)據(jù)間隔
34 AOCTRL_CMD_BARRIER_SET = 12 #設(shè)置電子圍欄消息
35 AOCTRL_CMD_GETLOCATION = 13 #應(yīng)答獲取終端所在位置消息
36 AOCTRL_CMD_LISTEN_START = 14 #監(jiān)聽命令
37 AOCTRL_CMD_COMMADDR_SET = 15 #設(shè)置終端IP地址和端口
38 AOCTRL_CMD_APN_SET = 16 # 設(shè)置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 #應(yīng)答等時連續(xù)回傳設(shè)置
48 AOCTRL_CMD_ALARM_REQ = 33 #警報消息
49 AOCTRL_CMD_NAMED_ACK = 34 #應(yīng)答點名信息
50 AOCTRL_CMD_SIMPLING_GPSDATA = 35 #等時連續(xù)回傳消息
51 AOCTRL_CMD_SIMPLING_END = 36 #連續(xù)回傳結(jié)束消息
52 AOCTRL_CMD_SPEEDSET_ACK = 37 #應(yīng)答設(shè)置車速上下限
53 AOCTRL_CMD_POWERCTRL_ACK = 38 #應(yīng)答電路控制
54 AOCTRL_CMD_OILCTRL_ACK = 39 #應(yīng)答油路控制
55 AOCTRL_CMD_REBOOT_ACK = 40 #應(yīng)答設(shè)備重啟消息
56 AOCTRL_CMD_ACCON_TIMESET_ACK = 41 #應(yīng)答設(shè)置ACC開發(fā)送數(shù)據(jù)間隔
57 AOCTRL_CMD_ACCOFF_TIMESET_ACK=42 #應(yīng)答設(shè)置ACC關(guān)發(fā)送數(shù)據(jù)間隔
58 AOCTRL_CMD_BARRIER_SET_ACK = 43 #應(yīng)答設(shè)置電子圍欄消息
59 AOCTRL_CMD_GETLOCATION_ACK = 44 #獲取終端所在位置消息
60 AOCTRL_CMD_LISTEN_ACK = 45 #應(yīng)答監(jiān)聽命令
61 AOCTRL_CMD_COMMADDR_SET_ACK=46 #應(yīng)答設(shè)置終端IP地址和端口
62 AOCTRL_CMD_APN_SET_ACK=47 #應(yīng)答設(shè)置APN消息
63 AOCTRL_CMD_GETVERSION_ACK=48 #應(yīng)答讀取終端版本消息
64 AOCTRL_CMD_CLEAR_ALARMS_ACK=49 #應(yīng)答取消所有報警消息
65 AOCTRL_CMD_CLEAR_MILES_ACK=50 #應(yīng)答里程清零消息
66 AOCTRL_CMD_UPDATING_ACK = 61 #應(yīng)答啟動升級消息
67 AOCTRL_CMD_INIT_MILES_ACK = 62 #應(yīng)答初始化里程消息
68
69 AOCTRL_CMD_LIST={
70 AOCTRL_CMD_SHAKE_ACK:u'應(yīng)答握手信號信息',
71 AOCTRL_CMD_REG_ACK:u'終端注冊響應(yīng)消息',
72 AOCTRL_CMD_SAMPLING_TIMESET:u'等時連續(xù)回傳設(shè)置',
73 AOCTRL_CMD_ALARM_ACK:u'應(yīng)答報警消息',
74 AOCTRL_CMD_NAMED:u'一次點名消息',
75 AOCTRL_CMD_SPEEDSET:u'設(shè)置車速上下限',
76
77 AOCTRL_CMD_POWER_ONOFF:u'電路控制信號',
78 AOCTRL_CMD_OIL_ONOFF:u'油路控制信號',
79 AOCTRL_CMD_REBOOT:u'控制設(shè)備重啟消息',
80 AOCTRL_CMD_ACC_ON_TIME :u'設(shè)置ACC開發(fā)送數(shù)據(jù)間隔',
81 AOCTRL_CMD_ACC_OFF_TIME :u'設(shè)置ACC關(guān)發(fā)送數(shù)據(jù)間隔',
82 AOCTRL_CMD_BARRIER_SET :u'設(shè)置電子圍欄消息',
83 AOCTRL_CMD_GETLOCATION :u'應(yīng)答獲取終端所在位置消息',
84 AOCTRL_CMD_LISTEN_START :u'監(jiān)聽命令',
85 AOCTRL_CMD_COMMADDR_SET :u'設(shè)置終端IP地址和端口',
86 AOCTRL_CMD_APN_SET :u'設(shè)置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'應(yīng)答等時連續(xù)回傳設(shè)置',
96 AOCTRL_CMD_ALARM_REQ :u'警報消息',
97 AOCTRL_CMD_NAMED_ACK :u'應(yīng)答點名信息',
98 AOCTRL_CMD_SIMPLING_GPSDATA :u'等時連續(xù)回傳消息',
99 AOCTRL_CMD_SIMPLING_END :u'連續(xù)回傳結(jié)束消息',
100 AOCTRL_CMD_SPEEDSET_ACK :u'應(yīng)答設(shè)置車速上下限',
101 AOCTRL_CMD_POWERCTRL_ACK :u'應(yīng)答電路控制',
102 AOCTRL_CMD_OILCTRL_ACK :u'應(yīng)答油路控制',
103 AOCTRL_CMD_REBOOT_ACK :u'應(yīng)答設(shè)備重啟消息',
104 AOCTRL_CMD_ACCON_TIMESET_ACK :u'應(yīng)答設(shè)置ACC開發(fā)送數(shù)據(jù)間隔',
105 AOCTRL_CMD_ACCOFF_TIMESET_ACK:u'應(yīng)答設(shè)置ACC關(guān)發(fā)送數(shù)據(jù)間隔',
106 AOCTRL_CMD_BARRIER_SET_ACK :u'應(yīng)答設(shè)置電子圍欄消息',
107 AOCTRL_CMD_GETLOCATION_ACK :u'獲取終端所在位置消息',
108 AOCTRL_CMD_LISTEN_ACK :u'應(yīng)答監(jiān)聽命令',
109 AOCTRL_CMD_COMMADDR_SET_ACK:u'應(yīng)答設(shè)置終端IP地址和端口',
110 AOCTRL_CMD_APN_SET_ACK:u'應(yīng)答設(shè)置APN消息',
111 AOCTRL_CMD_GETVERSION_ACK:u'應(yīng)答讀取終端版本消息',
112 AOCTRL_CMD_CLEAR_ALARMS_ACK:u'應(yīng)答取消所有報警消息',
113 AOCTRL_CMD_CLEAR_MILES_ACK:u'應(yīng)答里程清零消息',
114 AOCTRL_CMD_UPDATING_ACK :u'應(yīng)答啟動升級消息',
115 AOCTRL_CMD_INIT_MILES_ACK :u'應(yīng)答初始化里程消息',
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節(jié)等于每小時 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數(shù)據(jù),模擬端口打開
157 class MediaCodec_KS102:
158 def __init__(self):
159 self.buf =''
160 self.conn = None
161 self.errtimes=0 #解析出錯次數(shù)達到指定數(shù)則斷開連接
162
163
164
165 # parse - codec 必須實現(xiàn)
166 #對于某些設(shè)備的請求消息,這里必須進行默認的應(yīng)答
167 #如果出現(xiàn)大量數(shù)據(jù)包的要發(fā)送回設(shè)備的情況,考慮建立隊列,用工作線程
168 # 慢慢發(fā)送,因為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 視為設(shè)備唯一編號 mid
206 self.conn = conn
207 msglist=[]
208 retry = True
209 try:
210 p = s.find(',')
211 d = s[p+1:-2]
212 crc = s[-2:]
213 sum, = struct.unpack('H',crc)
214 if self.crc_16_result(d) != sum:
215 print 'crc error'
216 return (),True
217 #13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114
218 print d
219 #print d.split(',')[-1]
220 #tel,gprmc,hms,av,lat,ns,lon,ew,speed,angle,dmy,p1,p2,mode,FL,battery,imei,msglen, = d.split(',')
221 tel,gprmc,hms,av,lat,ns,lon,ew,speed,angle,dmy,p1,p2,mode,FL,imei,msglen, = d.split(',')
222 imei = imei.split(':')[1]
223 angle = float(angle)
224 speed = float(speed)*1.852 # 節(jié)到km轉(zhuǎn)換
225 lon = parseDegree(lon)
226 lat = parseDegree(lat)
227 time = parseTime(dmy,hms)+3600*8 #時間加上GMT8
228 gps = {
229 'time':time,
230 'lon':lon,
231 'lat':lat,
232 'speed':speed,
233 'angle':angle
234 }
235 msg = {
236 'mid':imei,
237 'cmd':AOCTRL_CMD_SIMPLING_GPSDATA,
238 'gps':gps,
239 }
240 msglist.append(msg)
241 except:
242 traceback.print_exc()
243 msglist=()
244 retry = True
245 self.errtimes+=1
246 if self.errtimes > 4: #解析錯誤次數(shù)過多,斷開連接
247 return (),False
248 return msglist,retry
249
250
251
252 #執(zhí)行設(shè)備命令
253 def command(self,aom,msg):
254 # cmd - object (json decoded)
255 #@return: 返回命令控制消息
256 cmd = msg['cmd']
257 code=''
258 params=''
259 if not msg.has_key('seq'):
260 msg['seq'] = '0'*12
261
262 if cmd == AOCTRL_CMD_REG_ACK: #注冊響應(yīng)
263 code = "(%sAP05)"%(msg['seq'])
264
265 #save to ctrl log
266 log = aom.gm.AO_CtrlLog()
267 log.ao = aom.ao.dbobj
268 log.cmd = cmd
269 log.time = datetime.datetime.now()
270 text = "%s: %s"%(AOCTRL_CMD_LIST[log.cmd],params)
271 log.comment = text[:200]
272 log.save()
273
274 return code
275
276 #將d數(shù)據(jù)寫入db中
277 # 根據(jù)不同的數(shù)據(jù)進行hash分派 目前之后gps和告警信息進行分派
278 def save(self,aom,d):
279 #log = aom.gm.AO_CtrlLog()
280 #log.ao = aom.ao.dbobj
281 #log.cmd = d['cmd']
282 #log.time = datetime.datetime.now()
283 #text = "%s: %s"%(AOCTRL_CMD_LIST[log.cmd],d['params'])
284 #log.comment = text[:200]
285 #log.save()
286 #以下存儲gps數(shù)據(jù)和設(shè)備狀態(tài)數(shù)據(jù)
287 if True:
288 # save to db
289 timestamp = gps['time']
290 g = aom.gm.AOMData_Gps()
291 g.ao = aom.ao.dbobj
292 g.savetime = datetime.datetime.fromtimestamp(timestamp)
293 g.lon = gps['lon']
294 g.lat = gps['lat']
295 g.speed = gps['speed']
296 g.angle = gps['angle']
297 g.power = 0
298 g.acc = 0
299 g.miles = 0
300 g.save()
301 #for dispatch
302 t = timestamp #time.mktime(g.savetime.timetuple())
303 s = {'type':MediaDataType.GPS,'hwid':aom.id,
304 'lon':g.lon,'lat':g.lat,
305 'speed':g.speed,'angle':g.angle,
306 'satenum':0,'sateused':0,
307 'time':t,
308 'power':g.power,
309 'acc':g.acc,
310 'miles':g.miles}
311 aom.dispatch(s) #分派到 cached server
312
313
314 '''
315 TK102方案GPRS通訊協(xié)議
316 上傳數(shù)據(jù)
317 “1003040220,13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114遷”
318
319 19個,分隔數(shù)據(jù)段
320
321 數(shù)據(jù)解析
322 “1003040220”
323 時間流水號: 2010年03月04日02時22分
324
325 “13145826175”
326 手機號碼:授權(quán)情況下為授權(quán)號碼,否則為最后操作tracker的手機號碼,或則為空.
327 “GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*
328 6F”
329 GPRMC數(shù)據(jù):GPS模塊數(shù)據(jù)完整數(shù)據(jù),單片機沒有對其進行修改.
330
331 “F” 當(dāng)前GPS是否有信號: F,表示有,L表示沒有
332 “battery” 報警信息:【SOS報警:”help me”;電子砸爛報警:” Stockade”;移位報警:” move”;超速報警;” speed”;低電報警;” bat:”】,非報警數(shù)據(jù)此位置為空.
333 “imei:354776030402512” GPRS 模塊IMEI號
334 “114” 數(shù)據(jù)長度【13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,】,括號內(nèi)部的數(shù)據(jù)的長度,單位字節(jié).
335 “遷” CRC檢驗:這是兩個字節(jié)的十六進制數(shù)據(jù),有時顯示為亂碼,又是顯示為空,因為他是十六進制。
336 計算范圍【13145826175,GPRMC,022011.000,A,2234.0200,N,11403.0754,E,0.00,189.47,040310,,,A*6F,F, battery,imei:354776030402512,114】
337 算法如下:
338 注意:此系統(tǒng)unsigned int 為16bits,對于PC軟件,需要對結(jié)果做 &0XFFFF運算。
339 unsigned int CRC_16(unsigned char *buf, unsigned int datalen)
340 {
341 unsigned int i;
342 unsigned char j;
343 unsigned char c, treat, bcrc;
344 unsigned int crc = 0;
345
346 for (i = 0; i < datalen; i++)
347 {
348 c = buf[i];
349 for (j = 0; j < 8; j++)
350 {
351 treat = c & 0x80;
352 c <<= 1;
353 bcrc = (crc >> 8);
354 bcrc &= 0x80;
355 crc <<= 1;
356 if (treat != bcrc)
357 crc ^= 0x1021;
358 }
359 }
360 return crc;
361 }
362
363 附:GPS模塊數(shù)據(jù)解釋說明:
364
365 $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
366 <1> UTC時間,hhmmss.sss(時分秒.毫秒)格式
367 <2> 定位狀態(tài),A=有效定位,V=無效定位
368 <3> 緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)
369 <4> 緯度半球N(北半球)或S(南半球)
370 <5> 經(jīng)度dddmm.mmmm(度分)格式(前面的0也將被傳輸)
371 <6> 經(jīng)度半球E(東經(jīng))或W(西經(jīng))
372 <7> 地面速率(000.0~999.9節(jié),前面的0也將被傳輸)
373 <8> 地面航向(000.0~359.9度,以正北為參考基準(zhǔn),前面的0也將被傳輸)
374 <9> UTC日期,ddmmyy(日月年)格式
375 <10> 磁偏角(000.0~180.0度,前面的0也將被傳輸)
376 <11> 磁偏角方向,E(東)或W(西)
377 <12> 模式指示(僅NMEA0183 3.00版本輸出,A=自主定位,D=差分,E=估算,N=數(shù)據(jù)無效)
378
379 '''
380 c = MediaCodec_KS102()
381 d="1106160039,13916624477,GPRMC,163905.000,A,3104.2062,N,12130.0542,E,0.33,347.69,150611,,,D*6C,F,imei:354779033883985,105"
382 d="13916624477,GPRMC,163905.000,A,3104.2062,N,12130.0542,E,0.33,347.69,150611,,,D*6C,F,imei:354779033883985,105"
383 #print len(d)
384 #a = c.crc_16_result(d)
385 log = open('ks102_data.txt','rb')
386 s = log.read()
387 print c.decode(s,None)
388
389