1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2008-01-09 $'.split()[1]
5 __author__ = 'xmlbinmsg'
6
7 __doc__='''
8
9 Autogenerated python functions to serialize/deserialize binary messages.
10
11 Generated by: ./aisxmlbinmsg2py.py
12
13 Need to then wrap these functions with the outer AIS packet and then
14 convert the whole binary blob to a NMEA string. Those functions are
15 not currently provided in this file.
16
17 serialize: python to ais binary
18 deserialize: ais binary to python
19
20 The generated code uses translators.py, binary.py, and aisstring.py
21 which should be packaged with the resulting files.
22
23
24 @requires: U{epydoc<http://epydoc.sourceforge.net/>} > 3.0alpha3
25 @requires: U{BitVector<http://cheeseshop.python.org/pypi/BitVector>}
26
27 @author: '''+__author__+'''
28 @version: ''' + __version__ +'''
29 @var __date__: Date of last svn commit
30 @undocumented: __version__ __author__ __doc__ parser
31 @status: under development
32 @license: Generated code has no license
33 @todo: FIX: put in a description of the message here with fields and types.
34 '''
35
36 import sys
37 from decimal import Decimal
38 from BitVector import BitVector
39
40 import binary, aisstring
41
42
43 TrueBV = BitVector(bitstring="1")
44 "Why always rebuild the True bit? This should speed things up a bunch"
45 FalseBV = BitVector(bitstring="0")
46 "Why always rebuild the False bit? This should speed things up a bunch"
47
48
49 fieldList = (
50 'MessageID',
51 'RepeatIndicator',
52 'UserID',
53 'AISversion',
54 'IMOnumber',
55 'callsign',
56 'name',
57 'shipandcargo',
58 'dimA',
59 'dimB',
60 'dimC',
61 'dimD',
62 'fixtype',
63 'ETAminute',
64 'ETAhour',
65 'ETAday',
66 'ETAmonth',
67 'draught',
68 'destination',
69 'dte',
70 'Spare',
71 )
72
73 fieldListPostgres = (
74 'MessageID',
75 'RepeatIndicator',
76 'UserID',
77 'AISversion',
78 'IMOnumber',
79 'callsign',
80 'name',
81 'shipandcargo',
82 'dimA',
83 'dimB',
84 'dimC',
85 'dimD',
86 'fixtype',
87 'ETAminute',
88 'ETAhour',
89 'ETAday',
90 'ETAmonth',
91 'draught',
92 'destination',
93 'dte',
94 'Spare',
95 )
96
97 toPgFields = {
98 }
99 '''
100 Go to the Postgis field names from the straight field name
101 '''
102
103 fromPgFields = {
104 }
105 '''
106 Go from the Postgis field names to the straight field name
107 '''
108
109 pgTypes = {
110 }
111 '''
112 Lookup table for each postgis field name to get its type.
113 '''
114
115 -def encode(params, validate=False):
116 '''Create a shipdata binary message payload to pack into an AIS Msg shipdata.
117
118 Fields in params:
119 - MessageID(uint): AIS message number. Must be 5 (field automatically set to "5")
120 - RepeatIndicator(uint): Indicated how many times a message has been repeated
121 - UserID(uint): Unique ship identification number (MMSI)
122 - AISversion(uint): Compliant with what edition. 0 is the first edition.
123 - IMOnumber(uint): vessel identification number (different than mmsi)
124 - callsign(aisstr6): Ship radio call sign
125 - name(aisstr6): Vessel name
126 - shipandcargo(uint): what
127 - dimA(uint): Distance from bow to reference position
128 - dimB(uint): Distance from reference position to stern
129 - dimC(uint): Distance from port side to reference position
130 - dimD(uint): Distance from reference position to starboard side
131 - fixtype(uint): Method used for positioning
132 - ETAminute(uint): Estimated time of arrival - minutes
133 - ETAhour(uint): Estimated time of arrival - hour
134 - ETAday(uint): Estimated time of arrival - day
135 - ETAmonth(uint): Estimated time of arrival - month
136 - draught(udecimal): Maximum present static draught
137 - destination(aisstr6): Where is the vessel going
138 - dte(uint): Data terminal ready
139 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
140 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing
141 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
142 @rtype: BitVector
143 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8
144 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits.
145 '''
146
147 bvList = []
148 bvList.append(binary.setBitVectorSize(BitVector(intVal=5),6))
149 if 'RepeatIndicator' in params:
150 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2))
151 else:
152 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
153 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30))
154 if 'AISversion' in params:
155 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['AISversion']),2))
156 else:
157 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
158 if 'IMOnumber' in params:
159 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['IMOnumber']),30))
160 else:
161 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),30))
162 if 'callsign' in params:
163 bvList.append(aisstring.encode(params['callsign'],42))
164 else:
165 bvList.append(aisstring.encode('@@@@@@@',42))
166 if 'name' in params:
167 bvList.append(aisstring.encode(params['name'],120))
168 else:
169 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120))
170 if 'shipandcargo' in params:
171 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['shipandcargo']),8))
172 else:
173 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8))
174 if 'dimA' in params:
175 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimA']),9))
176 else:
177 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),9))
178 if 'dimB' in params:
179 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimB']),9))
180 else:
181 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),9))
182 if 'dimC' in params:
183 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimC']),6))
184 else:
185 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),6))
186 if 'dimD' in params:
187 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimD']),6))
188 else:
189 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),6))
190 if 'fixtype' in params:
191 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['fixtype']),4))
192 else:
193 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4))
194 if 'ETAminute' in params:
195 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAminute']),6))
196 else:
197 bvList.append(binary.setBitVectorSize(BitVector(intVal=60),6))
198 if 'ETAhour' in params:
199 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAhour']),5))
200 else:
201 bvList.append(binary.setBitVectorSize(BitVector(intVal=24),5))
202 if 'ETAday' in params:
203 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAday']),5))
204 else:
205 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),5))
206 if 'ETAmonth' in params:
207 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAmonth']),4))
208 else:
209 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4))
210 if 'draught' in params:
211 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['draught'])*Decimal('10')))),8))
212 else:
213 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(0)),8))
214 if 'destination' in params:
215 bvList.append(aisstring.encode(params['destination'],120))
216 else:
217 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120))
218 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dte']),1))
219 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),1))
220
221 return binary.joinBV(bvList)
222
223 -def decode(bv, validate=False):
224 '''Unpack a shipdata message
225
226 Fields in params:
227 - MessageID(uint): AIS message number. Must be 5 (field automatically set to "5")
228 - RepeatIndicator(uint): Indicated how many times a message has been repeated
229 - UserID(uint): Unique ship identification number (MMSI)
230 - AISversion(uint): Compliant with what edition. 0 is the first edition.
231 - IMOnumber(uint): vessel identification number (different than mmsi)
232 - callsign(aisstr6): Ship radio call sign
233 - name(aisstr6): Vessel name
234 - shipandcargo(uint): what
235 - dimA(uint): Distance from bow to reference position
236 - dimB(uint): Distance from reference position to stern
237 - dimC(uint): Distance from port side to reference position
238 - dimD(uint): Distance from reference position to starboard side
239 - fixtype(uint): Method used for positioning
240 - ETAminute(uint): Estimated time of arrival - minutes
241 - ETAhour(uint): Estimated time of arrival - hour
242 - ETAday(uint): Estimated time of arrival - day
243 - ETAmonth(uint): Estimated time of arrival - month
244 - draught(udecimal): Maximum present static draught
245 - destination(aisstr6): Where is the vessel going
246 - dte(uint): Data terminal ready
247 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
248 @type bv: BitVector
249 @param bv: Bits defining a message
250 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
251 @rtype: dict
252 @return: params
253 '''
254
255
256
257
258 r = {}
259 r['MessageID']=5
260 r['RepeatIndicator']=int(bv[6:8])
261 r['UserID']=int(bv[8:38])
262 r['AISversion']=int(bv[38:40])
263 r['IMOnumber']=int(bv[40:70])
264 r['callsign']=aisstring.decode(bv[70:112])
265 r['name']=aisstring.decode(bv[112:232])
266 r['shipandcargo']=int(bv[232:240])
267 r['dimA']=int(bv[240:249])
268 r['dimB']=int(bv[249:258])
269 r['dimC']=int(bv[258:264])
270 r['dimD']=int(bv[264:270])
271 r['fixtype']=int(bv[270:274])
272 r['ETAminute']=int(bv[274:280])
273 r['ETAhour']=int(bv[280:285])
274 r['ETAday']=int(bv[285:290])
275 r['ETAmonth']=int(bv[290:294])
276 r['draught']=Decimal(int(bv[294:302]))/Decimal('10')
277 r['destination']=aisstring.decode(bv[302:422])
278 r['dte']=int(bv[422:423])
279 r['Spare']=0
280 return r
281
284
287
290
292 return int(bv[38:40])
293
295 return int(bv[40:70])
296
299
302
304 return int(bv[232:240])
305
307 return int(bv[240:249])
308
310 return int(bv[249:258])
311
313 return int(bv[258:264])
314
316 return int(bv[264:270])
317
319 return int(bv[270:274])
320
322 return int(bv[274:280])
323
325 return int(bv[280:285])
326
328 return int(bv[285:290])
329
331 return int(bv[290:294])
332
334 return Decimal(int(bv[294:302]))/Decimal('10')
335
338
340 return int(bv[422:423])
341
344
345
347 out.write("<h3>shipdata</h3>\n")
348 out.write("<table border=\"1\">\n")
349 out.write("<tr bgcolor=\"orange\">\n")
350 out.write("<th align=\"left\">Field Name</th>\n")
351 out.write("<th align=\"left\">Type</th>\n")
352 out.write("<th align=\"left\">Value</th>\n")
353 out.write("<th align=\"left\">Value in Lookup Table</th>\n")
354 out.write("<th align=\"left\">Units</th>\n")
355 out.write("\n")
356 out.write("<tr>\n")
357 out.write("<td>MessageID</td>\n")
358 out.write("<td>uint</td>\n")
359 if 'MessageID' in params:
360 out.write(" <td>"+str(params['MessageID'])+"</td>\n")
361 out.write(" <td>"+str(params['MessageID'])+"</td>\n")
362 out.write("</tr>\n")
363 out.write("\n")
364 out.write("<tr>\n")
365 out.write("<td>RepeatIndicator</td>\n")
366 out.write("<td>uint</td>\n")
367 if 'RepeatIndicator' in params:
368 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n")
369 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut:
370 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>")
371 else:
372 out.write("<td><i>Missing LUT entry</i></td>")
373 out.write("</tr>\n")
374 out.write("\n")
375 out.write("<tr>\n")
376 out.write("<td>UserID</td>\n")
377 out.write("<td>uint</td>\n")
378 if 'UserID' in params:
379 out.write(" <td>"+str(params['UserID'])+"</td>\n")
380 out.write(" <td>"+str(params['UserID'])+"</td>\n")
381 out.write("</tr>\n")
382 out.write("\n")
383 out.write("<tr>\n")
384 out.write("<td>AISversion</td>\n")
385 out.write("<td>uint</td>\n")
386 if 'AISversion' in params:
387 out.write(" <td>"+str(params['AISversion'])+"</td>\n")
388 out.write(" <td>"+str(params['AISversion'])+"</td>\n")
389 out.write("</tr>\n")
390 out.write("\n")
391 out.write("<tr>\n")
392 out.write("<td>IMOnumber</td>\n")
393 out.write("<td>uint</td>\n")
394 if 'IMOnumber' in params:
395 out.write(" <td>"+str(params['IMOnumber'])+"</td>\n")
396 out.write(" <td>"+str(params['IMOnumber'])+"</td>\n")
397 out.write("</tr>\n")
398 out.write("\n")
399 out.write("<tr>\n")
400 out.write("<td>callsign</td>\n")
401 out.write("<td>aisstr6</td>\n")
402 if 'callsign' in params:
403 out.write(" <td>"+str(params['callsign'])+"</td>\n")
404 out.write(" <td>"+str(params['callsign'])+"</td>\n")
405 out.write("</tr>\n")
406 out.write("\n")
407 out.write("<tr>\n")
408 out.write("<td>name</td>\n")
409 out.write("<td>aisstr6</td>\n")
410 if 'name' in params:
411 out.write(" <td>"+str(params['name'])+"</td>\n")
412 out.write(" <td>"+str(params['name'])+"</td>\n")
413 out.write("</tr>\n")
414 out.write("\n")
415 out.write("<tr>\n")
416 out.write("<td>shipandcargo</td>\n")
417 out.write("<td>uint</td>\n")
418 if 'shipandcargo' in params:
419 out.write(" <td>"+str(params['shipandcargo'])+"</td>\n")
420 if str(params['shipandcargo']) in shipandcargoDecodeLut:
421 out.write("<td>"+shipandcargoDecodeLut[str(params['shipandcargo'])]+"</td>")
422 else:
423 out.write("<td><i>Missing LUT entry</i></td>")
424 out.write("</tr>\n")
425 out.write("\n")
426 out.write("<tr>\n")
427 out.write("<td>dimA</td>\n")
428 out.write("<td>uint</td>\n")
429 if 'dimA' in params:
430 out.write(" <td>"+str(params['dimA'])+"</td>\n")
431 out.write(" <td>"+str(params['dimA'])+"</td>\n")
432 out.write("<td>m</td>\n")
433 out.write("</tr>\n")
434 out.write("\n")
435 out.write("<tr>\n")
436 out.write("<td>dimB</td>\n")
437 out.write("<td>uint</td>\n")
438 if 'dimB' in params:
439 out.write(" <td>"+str(params['dimB'])+"</td>\n")
440 out.write(" <td>"+str(params['dimB'])+"</td>\n")
441 out.write("<td>m</td>\n")
442 out.write("</tr>\n")
443 out.write("\n")
444 out.write("<tr>\n")
445 out.write("<td>dimC</td>\n")
446 out.write("<td>uint</td>\n")
447 if 'dimC' in params:
448 out.write(" <td>"+str(params['dimC'])+"</td>\n")
449 if str(params['dimC']) in dimCDecodeLut:
450 out.write("<td>"+dimCDecodeLut[str(params['dimC'])]+"</td>")
451 else:
452 out.write("<td><i>Missing LUT entry</i></td>")
453 out.write("<td>m</td>\n")
454 out.write("</tr>\n")
455 out.write("\n")
456 out.write("<tr>\n")
457 out.write("<td>dimD</td>\n")
458 out.write("<td>uint</td>\n")
459 if 'dimD' in params:
460 out.write(" <td>"+str(params['dimD'])+"</td>\n")
461 if str(params['dimD']) in dimDDecodeLut:
462 out.write("<td>"+dimDDecodeLut[str(params['dimD'])]+"</td>")
463 else:
464 out.write("<td><i>Missing LUT entry</i></td>")
465 out.write("<td>m</td>\n")
466 out.write("</tr>\n")
467 out.write("\n")
468 out.write("<tr>\n")
469 out.write("<td>fixtype</td>\n")
470 out.write("<td>uint</td>\n")
471 if 'fixtype' in params:
472 out.write(" <td>"+str(params['fixtype'])+"</td>\n")
473 if str(params['fixtype']) in fixtypeDecodeLut:
474 out.write("<td>"+fixtypeDecodeLut[str(params['fixtype'])]+"</td>")
475 else:
476 out.write("<td><i>Missing LUT entry</i></td>")
477 out.write("</tr>\n")
478 out.write("\n")
479 out.write("<tr>\n")
480 out.write("<td>ETAminute</td>\n")
481 out.write("<td>uint</td>\n")
482 if 'ETAminute' in params:
483 out.write(" <td>"+str(params['ETAminute'])+"</td>\n")
484 out.write(" <td>"+str(params['ETAminute'])+"</td>\n")
485 out.write("</tr>\n")
486 out.write("\n")
487 out.write("<tr>\n")
488 out.write("<td>ETAhour</td>\n")
489 out.write("<td>uint</td>\n")
490 if 'ETAhour' in params:
491 out.write(" <td>"+str(params['ETAhour'])+"</td>\n")
492 out.write(" <td>"+str(params['ETAhour'])+"</td>\n")
493 out.write("</tr>\n")
494 out.write("\n")
495 out.write("<tr>\n")
496 out.write("<td>ETAday</td>\n")
497 out.write("<td>uint</td>\n")
498 if 'ETAday' in params:
499 out.write(" <td>"+str(params['ETAday'])+"</td>\n")
500 out.write(" <td>"+str(params['ETAday'])+"</td>\n")
501 out.write("</tr>\n")
502 out.write("\n")
503 out.write("<tr>\n")
504 out.write("<td>ETAmonth</td>\n")
505 out.write("<td>uint</td>\n")
506 if 'ETAmonth' in params:
507 out.write(" <td>"+str(params['ETAmonth'])+"</td>\n")
508 out.write(" <td>"+str(params['ETAmonth'])+"</td>\n")
509 out.write("</tr>\n")
510 out.write("\n")
511 out.write("<tr>\n")
512 out.write("<td>draught</td>\n")
513 out.write("<td>udecimal</td>\n")
514 if 'draught' in params:
515 out.write(" <td>"+str(params['draught'])+"</td>\n")
516 if str(params['draught']) in draughtDecodeLut:
517 out.write("<td>"+draughtDecodeLut[str(params['draught'])]+"</td>")
518 else:
519 out.write("<td><i>Missing LUT entry</i></td>")
520 out.write("<td>m</td>\n")
521 out.write("</tr>\n")
522 out.write("\n")
523 out.write("<tr>\n")
524 out.write("<td>destination</td>\n")
525 out.write("<td>aisstr6</td>\n")
526 if 'destination' in params:
527 out.write(" <td>"+str(params['destination'])+"</td>\n")
528 out.write(" <td>"+str(params['destination'])+"</td>\n")
529 out.write("</tr>\n")
530 out.write("\n")
531 out.write("<tr>\n")
532 out.write("<td>dte</td>\n")
533 out.write("<td>uint</td>\n")
534 if 'dte' in params:
535 out.write(" <td>"+str(params['dte'])+"</td>\n")
536 if str(params['dte']) in dteDecodeLut:
537 out.write("<td>"+dteDecodeLut[str(params['dte'])]+"</td>")
538 else:
539 out.write("<td><i>Missing LUT entry</i></td>")
540 out.write("</tr>\n")
541 out.write("\n")
542 out.write("<tr>\n")
543 out.write("<td>Spare</td>\n")
544 out.write("<td>uint</td>\n")
545 if 'Spare' in params:
546 out.write(" <td>"+str(params['Spare'])+"</td>\n")
547 out.write(" <td>"+str(params['Spare'])+"</td>\n")
548 out.write("</tr>\n")
549 out.write("</table>\n")
550
551 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
552 '''Print a shipdata message to stdout.
553
554 Fields in params:
555 - MessageID(uint): AIS message number. Must be 5 (field automatically set to "5")
556 - RepeatIndicator(uint): Indicated how many times a message has been repeated
557 - UserID(uint): Unique ship identification number (MMSI)
558 - AISversion(uint): Compliant with what edition. 0 is the first edition.
559 - IMOnumber(uint): vessel identification number (different than mmsi)
560 - callsign(aisstr6): Ship radio call sign
561 - name(aisstr6): Vessel name
562 - shipandcargo(uint): what
563 - dimA(uint): Distance from bow to reference position
564 - dimB(uint): Distance from reference position to stern
565 - dimC(uint): Distance from port side to reference position
566 - dimD(uint): Distance from reference position to starboard side
567 - fixtype(uint): Method used for positioning
568 - ETAminute(uint): Estimated time of arrival - minutes
569 - ETAhour(uint): Estimated time of arrival - hour
570 - ETAday(uint): Estimated time of arrival - day
571 - ETAmonth(uint): Estimated time of arrival - month
572 - draught(udecimal): Maximum present static draught
573 - destination(aisstr6): Where is the vessel going
574 - dte(uint): Data terminal ready
575 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
576 @param params: Dictionary of field names/values.
577 @param out: File like object to write to
578 @rtype: stdout
579 @return: text to out
580 '''
581
582 if 'std'==format:
583 out.write("shipdata:\n")
584 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n")
585 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n")
586 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n")
587 if 'AISversion' in params: out.write(" AISversion: "+str(params['AISversion'])+"\n")
588 if 'IMOnumber' in params: out.write(" IMOnumber: "+str(params['IMOnumber'])+"\n")
589 if 'callsign' in params: out.write(" callsign: "+str(params['callsign'])+"\n")
590 if 'name' in params: out.write(" name: "+str(params['name'])+"\n")
591 if 'shipandcargo' in params: out.write(" shipandcargo: "+str(params['shipandcargo'])+"\n")
592 if 'dimA' in params: out.write(" dimA: "+str(params['dimA'])+"\n")
593 if 'dimB' in params: out.write(" dimB: "+str(params['dimB'])+"\n")
594 if 'dimC' in params: out.write(" dimC: "+str(params['dimC'])+"\n")
595 if 'dimD' in params: out.write(" dimD: "+str(params['dimD'])+"\n")
596 if 'fixtype' in params: out.write(" fixtype: "+str(params['fixtype'])+"\n")
597 if 'ETAminute' in params: out.write(" ETAminute: "+str(params['ETAminute'])+"\n")
598 if 'ETAhour' in params: out.write(" ETAhour: "+str(params['ETAhour'])+"\n")
599 if 'ETAday' in params: out.write(" ETAday: "+str(params['ETAday'])+"\n")
600 if 'ETAmonth' in params: out.write(" ETAmonth: "+str(params['ETAmonth'])+"\n")
601 if 'draught' in params: out.write(" draught: "+str(params['draught'])+"\n")
602 if 'destination' in params: out.write(" destination: "+str(params['destination'])+"\n")
603 if 'dte' in params: out.write(" dte: "+str(params['dte'])+"\n")
604 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n")
605 elif 'csv'==format:
606 if None == options.fieldList:
607 options.fieldList = fieldList
608 needComma = False;
609 for field in fieldList:
610 if needComma: out.write(',')
611 needComma = True
612 if field in params:
613 out.write(str(params[field]))
614
615 out.write("\n")
616 elif 'html'==format:
617 printHtml(params,out)
618 elif 'sql'==format:
619 sqlInsertStr(params,out,dbType=dbType)
620 else:
621 print "ERROR: unknown format:",format
622 assert False
623
624 return
625
626 RepeatIndicatorEncodeLut = {
627 'default':'0',
628 'do not repeat any more':'3',
629 }
630
631 RepeatIndicatorDecodeLut = {
632 '0':'default',
633 '3':'do not repeat any more',
634 }
635
636 shipandcargoEncodeLut = {
637 'Wing in ground (WIG), all ships of this type':'20',
638 'Wing in ground (WIG), Hazardous catagory A':'21',
639 'Wing in ground (WIG), Hazardous catagory B':'22',
640 'Wing in ground (WIG), Hazardous catagory C':'23',
641 'Wing in ground (WIG), Hazardous catagory D':'24',
642 'Wing in ground (WIG), Reserved for future use':'25',
643 'Wing in ground (WIG), Reserved for future use':'26',
644 'Wing in ground (WIG), Reserved for future use':'27',
645 'Wing in ground (WIG), Reserved for future use':'28',
646 'Wing in ground (WIG), No additional information':'29',
647 'fishing':'30',
648 'towing':'31',
649 'towing length exceeds 200m or breadth exceeds 25m':'32',
650 'dredging or underwater ops':'33',
651 'diving ops':'34',
652 'military ops':'35',
653 'sailing':'36',
654 'pleasure craft':'37',
655 'reserved':'38',
656 'reserved':'39',
657 'High speed craft (HSC), all ships of this type':'40',
658 'High speed craft (HSC), Hazardous catagory A':'41',
659 'High speed craft (HSC), Hazardous catagory B':'42',
660 'High speed craft (HSC), Hazardous catagory C':'43',
661 'High speed craft (HSC), Hazardous catagory D':'44',
662 'High speed craft (HSC), Reserved for future use':'45',
663 'High speed craft (HSC), Reserved for future use':'46',
664 'High speed craft (HSC), Reserved for future use':'47',
665 'High speed craft (HSC), Reserved for future use':'48',
666 'High speed craft (HSC), No additional information':'49',
667 'pilot vessel':'50',
668 'search and rescue vessel':'51',
669 'tug':'52',
670 'port tender':'53',
671 'anti-polution equipment':'54',
672 'law enforcement':'55',
673 'spare - local vessel':'56',
674 'spare - local vessel':'57',
675 'medical transport':'58',
676 'ship according to RR Resolution No. 18':'59',
677 'passenger, all ships of this type':'60',
678 'passenger, Hazardous catagory A':'61',
679 'passenger, Hazardous catagory B':'62',
680 'passenger, Hazardous catagory C':'63',
681 'passenger, Hazardous catagory D':'64',
682 'passenger, Reserved for future use':'65',
683 'passenger, Reserved for future use':'66',
684 'passenger, Reserved for future use':'67',
685 'passenger, Reserved for future use':'68',
686 'passenger, No additional information':'69',
687 'cargo, all ships of this type':'70',
688 'cargo, Hazardous catagory A':'71',
689 'cargo, Hazardous catagory B':'72',
690 'cargo, Hazardous catagory C':'73',
691 'cargo, Hazardous catagory D':'74',
692 'cargo, Reserved for future use':'75',
693 'cargo, Reserved for future use':'76',
694 'cargo, Reserved for future use':'77',
695 'cargo, Reserved for future use':'78',
696 'cargo, No additional information':'79',
697 'tanker, all ships of this type':'80',
698 'tanker, Hazardous catagory A':'81',
699 'tanker, Hazardous catagory B':'82',
700 'tanker, Hazardous catagory C':'83',
701 'tanker, Hazardous catagory D':'84',
702 'tanker, Reserved for future use':'85',
703 'tanker, Reserved for future use':'86',
704 'tanker, Reserved for future use':'87',
705 'tanker, Reserved for future use':'88',
706 'tanker, No additional information':'89',
707 'other type, all ships of this type':'90',
708 'other type, Hazardous catagory A':'91',
709 'other type, Hazardous catagory B':'92',
710 'other type, Hazardous catagory C':'93',
711 'other type, Hazardous catagory D':'94',
712 'other type, Reserved for future use':'95',
713 'other type, Reserved for future use':'96',
714 'other type, Reserved for future use':'97',
715 'other type, Reserved for future use':'98',
716 'other type, No additional information':'99',
717 }
718
719 shipandcargoDecodeLut = {
720 '20':'Wing in ground (WIG), all ships of this type',
721 '21':'Wing in ground (WIG), Hazardous catagory A',
722 '22':'Wing in ground (WIG), Hazardous catagory B',
723 '23':'Wing in ground (WIG), Hazardous catagory C',
724 '24':'Wing in ground (WIG), Hazardous catagory D',
725 '25':'Wing in ground (WIG), Reserved for future use',
726 '26':'Wing in ground (WIG), Reserved for future use',
727 '27':'Wing in ground (WIG), Reserved for future use',
728 '28':'Wing in ground (WIG), Reserved for future use',
729 '29':'Wing in ground (WIG), No additional information',
730 '30':'fishing',
731 '31':'towing',
732 '32':'towing length exceeds 200m or breadth exceeds 25m',
733 '33':'dredging or underwater ops',
734 '34':'diving ops',
735 '35':'military ops',
736 '36':'sailing',
737 '37':'pleasure craft',
738 '38':'reserved',
739 '39':'reserved',
740 '40':'High speed craft (HSC), all ships of this type',
741 '41':'High speed craft (HSC), Hazardous catagory A',
742 '42':'High speed craft (HSC), Hazardous catagory B',
743 '43':'High speed craft (HSC), Hazardous catagory C',
744 '44':'High speed craft (HSC), Hazardous catagory D',
745 '45':'High speed craft (HSC), Reserved for future use',
746 '46':'High speed craft (HSC), Reserved for future use',
747 '47':'High speed craft (HSC), Reserved for future use',
748 '48':'High speed craft (HSC), Reserved for future use',
749 '49':'High speed craft (HSC), No additional information',
750 '50':'pilot vessel',
751 '51':'search and rescue vessel',
752 '52':'tug',
753 '53':'port tender',
754 '54':'anti-polution equipment',
755 '55':'law enforcement',
756 '56':'spare - local vessel',
757 '57':'spare - local vessel',
758 '58':'medical transport',
759 '59':'ship according to RR Resolution No. 18',
760 '60':'passenger, all ships of this type',
761 '61':'passenger, Hazardous catagory A',
762 '62':'passenger, Hazardous catagory B',
763 '63':'passenger, Hazardous catagory C',
764 '64':'passenger, Hazardous catagory D',
765 '65':'passenger, Reserved for future use',
766 '66':'passenger, Reserved for future use',
767 '67':'passenger, Reserved for future use',
768 '68':'passenger, Reserved for future use',
769 '69':'passenger, No additional information',
770 '70':'cargo, all ships of this type',
771 '71':'cargo, Hazardous catagory A',
772 '72':'cargo, Hazardous catagory B',
773 '73':'cargo, Hazardous catagory C',
774 '74':'cargo, Hazardous catagory D',
775 '75':'cargo, Reserved for future use',
776 '76':'cargo, Reserved for future use',
777 '77':'cargo, Reserved for future use',
778 '78':'cargo, Reserved for future use',
779 '79':'cargo, No additional information',
780 '80':'tanker, all ships of this type',
781 '81':'tanker, Hazardous catagory A',
782 '82':'tanker, Hazardous catagory B',
783 '83':'tanker, Hazardous catagory C',
784 '84':'tanker, Hazardous catagory D',
785 '85':'tanker, Reserved for future use',
786 '86':'tanker, Reserved for future use',
787 '87':'tanker, Reserved for future use',
788 '88':'tanker, Reserved for future use',
789 '89':'tanker, No additional information',
790 '90':'other type, all ships of this type',
791 '91':'other type, Hazardous catagory A',
792 '92':'other type, Hazardous catagory B',
793 '93':'other type, Hazardous catagory C',
794 '94':'other type, Hazardous catagory D',
795 '95':'other type, Reserved for future use',
796 '96':'other type, Reserved for future use',
797 '97':'other type, Reserved for future use',
798 '98':'other type, Reserved for future use',
799 '99':'other type, No additional information',
800 }
801
802 dimCEncodeLut = {
803 '63 m or greater':'63',
804 }
805
806 dimCDecodeLut = {
807 '63':'63 m or greater',
808 }
809
810 dimDEncodeLut = {
811 '63 m or greater':'63',
812 }
813
814 dimDDecodeLut = {
815 '63':'63 m or greater',
816 }
817
818 fixtypeEncodeLut = {
819 'undefined':'0',
820 'GPS':'1',
821 'GLONASS':'2',
822 'combined GPS/GLONASS':'3',
823 'Loran-C':'4',
824 'Chayka':'5',
825 'integrated navigation system':'6',
826 'surveyed':'7',
827 }
828
829 fixtypeDecodeLut = {
830 '0':'undefined',
831 '1':'GPS',
832 '2':'GLONASS',
833 '3':'combined GPS/GLONASS',
834 '4':'Loran-C',
835 '5':'Chayka',
836 '6':'integrated navigation system',
837 '7':'surveyed',
838 }
839
840 draughtEncodeLut = {
841 '25.5 m or greater':'25.5',
842 }
843
844 draughtDecodeLut = {
845 '25.5':'25.5 m or greater',
846 }
847
848 dteEncodeLut = {
849 'available':'0',
850 'not available':'1',
851 }
852
853 dteDecodeLut = {
854 '0':'available',
855 '1':'not available',
856 }
857
858
859
860
861
862 dbTableName='shipdata'
863 'Database table name'
864
865 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None
866 ,addCoastGuardFields=True
867 ,dbType='postgres'
868 ):
869 '''
870 Return the SQL CREATE command for this message type
871 @param outfile: file like object to print to.
872 @param fields: which fields to put in the create. Defaults to all.
873 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
874 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
875 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
876 @type addCoastGuardFields: bool
877 @return: sql create string
878 @rtype: str
879
880 @see: sqlCreate
881 '''
882
883 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
884
885 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
886 '''
887 Return the sqlhelp object to create the table.
888
889 @param fields: which fields to put in the create. Defaults to all.
890 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
891 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
892 @type addCoastGuardFields: bool
893 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
894 @return: An object that can be used to generate a return
895 @rtype: sqlhelp.create
896 '''
897 if None == fields: fields = fieldList
898 import sqlhelp
899 c = sqlhelp.create('shipdata',dbType=dbType)
900 c.addPrimaryKey()
901 if 'MessageID' in fields: c.addInt ('MessageID')
902 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator')
903 if 'UserID' in fields: c.addInt ('UserID')
904 if 'AISversion' in fields: c.addInt ('AISversion')
905 if 'IMOnumber' in fields: c.addInt ('IMOnumber')
906 if 'callsign' in fields: c.addVarChar('callsign',7)
907 if 'name' in fields: c.addVarChar('name',20)
908 if 'shipandcargo' in fields: c.addInt ('shipandcargo')
909 if 'dimA' in fields: c.addInt ('dimA')
910 if 'dimB' in fields: c.addInt ('dimB')
911 if 'dimC' in fields: c.addInt ('dimC')
912 if 'dimD' in fields: c.addInt ('dimD')
913 if 'fixtype' in fields: c.addInt ('fixtype')
914 if 'ETAminute' in fields: c.addInt ('ETAminute')
915 if 'ETAhour' in fields: c.addInt ('ETAhour')
916 if 'ETAday' in fields: c.addInt ('ETAday')
917 if 'ETAmonth' in fields: c.addInt ('ETAmonth')
918 if 'draught' in fields: c.addDecimal('draught',3,1)
919 if 'destination' in fields: c.addVarChar('destination',20)
920 if 'dte' in fields: c.addInt ('dte')
921 if 'Spare' in fields: c.addInt ('Spare')
922
923 if addCoastGuardFields:
924
925
926
927
928
929 c.addVarChar('cg_r',15)
930 c.addInt('cg_sec')
931
932 c.addTimestamp('cg_timestamp')
933
934 return c
935
936 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
937 '''
938 Return the SQL INSERT command for this message type
939 @param params: dictionary of values keyed by field name
940 @param outfile: file like object to print to.
941 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
942 @return: sql create string
943 @rtype: str
944
945 @see: sqlCreate
946 '''
947 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
948
949
950 -def sqlInsert(params,extraParams=None,dbType='postgres'):
951 '''
952 Give the SQL INSERT statement
953 @param params: dict keyed by field name of values
954 @param extraParams: any extra fields that you have created beyond the normal ais message fields
955 @rtype: sqlhelp.insert
956 @return: insert class instance
957 @todo: allow optional type checking of params?
958 @warning: this will take invalid keys happily and do what???
959 '''
960 import sqlhelp
961 i = sqlhelp.insert('shipdata',dbType=dbType)
962
963 if dbType=='postgres':
964 finished = []
965 for key in params:
966 if key in finished:
967 continue
968
969 if key not in toPgFields and key not in fromPgFields:
970 if type(params[key])==Decimal: i.add(key,float(params[key]))
971 else: i.add(key,params[key])
972 else:
973 if key in fromPgFields:
974 val = params[key]
975
976 i.addPostGIS(key,val)
977 finished.append(key)
978 else:
979
980 pgName = toPgFields[key]
981
982 valStr=pgTypes[pgName]+'('
983 vals = []
984 for nonPgKey in fromPgFields[pgName]:
985 vals.append(str(params[nonPgKey]))
986 finished.append(nonPgKey)
987 valStr+=' '.join(vals)+')'
988 i.addPostGIS(pgName,valStr)
989 else:
990 for key in params:
991 if type(params[key])==Decimal: i.add(key,float(params[key]))
992 else: i.add(key,params[key])
993
994 if None != extraParams:
995 for key in extraParams:
996 i.add(key,extraParams[key])
997
998 return i
999
1000
1001
1002
1003
1006 '''
1007 Return the LaTeX definition table for this message type
1008 @param outfile: file like object to print to.
1009 @type outfile: file obj
1010 @return: LaTeX table string via the outfile
1011 @rtype: str
1012
1013 '''
1014 o = outfile
1015
1016 o.write('''
1017 \\begin{table}%[htb]
1018 \\centering
1019 \\begin{tabular}{|l|c|l|}
1020 \\hline
1021 Parameter & Number of bits & Description
1022 \\\\ \\hline\\hline
1023 MessageID & 6 & AIS message number. Must be 5 \\\\ \hline
1024 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline
1025 UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline
1026 AISversion & 2 & Compliant with what edition. 0 is the first edition. \\\\ \hline
1027 IMOnumber & 30 & vessel identification number (different than mmsi) \\\\ \hline
1028 callsign & 42 & Ship radio call sign \\\\ \hline
1029 name & 120 & Vessel name \\\\ \hline
1030 shipandcargo & 8 & Type of ship and cargo type \\\\ \hline
1031 dimA & 9 & Distance from bow to reference position \\\\ \hline
1032 dimB & 9 & Distance from reference position to stern \\\\ \hline
1033 dimC & 6 & Distance from port side to reference position \\\\ \hline
1034 dimD & 6 & Distance from reference position to starboard side \\\\ \hline
1035 fixtype & 4 & Method used for positioning \\\\ \hline
1036 ETAminute & 6 & Estimated time of arrival - minutes \\\\ \hline
1037 ETAhour & 5 & Estimated time of arrival - hour \\\\ \hline
1038 ETAday & 5 & Estimated time of arrival - day \\\\ \hline
1039 ETAmonth & 4 & Estimated time of arrival - month \\\\ \hline
1040 draught & 8 & Maximum present static draught \\\\ \hline
1041 destination & 120 & Where is the vessel going \\\\ \hline
1042 dte & 1 & Data terminal ready \\\\ \hline
1043 Spare & 1 & Reserved for definition by a regional authority.\\\\ \\hline \\hline
1044 Total bits & 424 & Appears to take 2 slots \\\\ \\hline
1045 \\end{tabular}
1046 \\caption{AIS message number 5: Class A vessel data report}
1047 \\label{tab:shipdata}
1048 \\end{table}
1049 ''')
1050
1051
1052
1053
1054
1055 -def textDefinitionTable(outfile=sys.stdout
1056 ,delim='\t'
1057 ):
1058 '''
1059 Return the text definition table for this message type
1060 @param outfile: file like object to print to.
1061 @type outfile: file obj
1062 @return: text table string via the outfile
1063 @rtype: str
1064
1065 '''
1066 o = outfile
1067 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description
1068 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 5
1069 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated
1070 UserID'''+delim+'''30'''+delim+'''Unique ship identification number (MMSI)
1071 AISversion'''+delim+'''2'''+delim+'''Compliant with what edition. 0 is the first edition.
1072 IMOnumber'''+delim+'''30'''+delim+'''vessel identification number (different than mmsi)
1073 callsign'''+delim+'''42'''+delim+'''Ship radio call sign
1074 name'''+delim+'''120'''+delim+'''Vessel name
1075 shipandcargo'''+delim+'''8'''+delim+'''Type of ship and cargo type
1076 dimA'''+delim+'''9'''+delim+'''Distance from bow to reference position
1077 dimB'''+delim+'''9'''+delim+'''Distance from reference position to stern
1078 dimC'''+delim+'''6'''+delim+'''Distance from port side to reference position
1079 dimD'''+delim+'''6'''+delim+'''Distance from reference position to starboard side
1080 fixtype'''+delim+'''4'''+delim+'''Method used for positioning
1081 ETAminute'''+delim+'''6'''+delim+'''Estimated time of arrival - minutes
1082 ETAhour'''+delim+'''5'''+delim+'''Estimated time of arrival - hour
1083 ETAday'''+delim+'''5'''+delim+'''Estimated time of arrival - day
1084 ETAmonth'''+delim+'''4'''+delim+'''Estimated time of arrival - month
1085 draught'''+delim+'''8'''+delim+'''Maximum present static draught
1086 destination'''+delim+'''120'''+delim+'''Where is the vessel going
1087 dte'''+delim+'''1'''+delim+'''Data terminal ready
1088 Spare'''+delim+'''1'''+delim+'''Reserved for definition by a regional authority.
1089 Total bits'''+delim+'''424'''+delim+'''Appears to take 2 slots''')
1090
1091
1092
1093
1094
1095 import unittest
1097 '''Return a params file base on the testvalue tags.
1098 @rtype: dict
1099 @return: params based on testvalue tags
1100 '''
1101 params = {}
1102 params['MessageID'] = 5
1103 params['RepeatIndicator'] = 1
1104 params['UserID'] = 1193046
1105 params['AISversion'] = 0
1106 params['IMOnumber'] = 3210
1107 params['callsign'] = 'PIRATE1'
1108 params['name'] = 'BLACK PEARL@@@@@@@@@'
1109 params['shipandcargo'] = 55
1110 params['dimA'] = 10
1111 params['dimB'] = 11
1112 params['dimC'] = 12
1113 params['dimD'] = 13
1114 params['fixtype'] = 1
1115 params['ETAminute'] = 54
1116 params['ETAhour'] = 9
1117 params['ETAday'] = 28
1118 params['ETAmonth'] = 2
1119 params['draught'] = Decimal('21.1')
1120 params['destination'] = 'NOWHERE@@@@@@@@@@@@@'
1121 params['dte'] = 0
1122 params['Spare'] = 0
1123
1124 return params
1125
1127 '''Use testvalue tag text from each type to build test case the shipdata message'''
1129
1130 params = testParams()
1131 bits = encode(params)
1132 r = decode(bits)
1133
1134
1135 self.failUnlessEqual(r['MessageID'],params['MessageID'])
1136 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
1137 self.failUnlessEqual(r['UserID'],params['UserID'])
1138 self.failUnlessEqual(r['AISversion'],params['AISversion'])
1139 self.failUnlessEqual(r['IMOnumber'],params['IMOnumber'])
1140 self.failUnlessEqual(r['callsign'],params['callsign'])
1141 self.failUnlessEqual(r['name'],params['name'])
1142 self.failUnlessEqual(r['shipandcargo'],params['shipandcargo'])
1143 self.failUnlessEqual(r['dimA'],params['dimA'])
1144 self.failUnlessEqual(r['dimB'],params['dimB'])
1145 self.failUnlessEqual(r['dimC'],params['dimC'])
1146 self.failUnlessEqual(r['dimD'],params['dimD'])
1147 self.failUnlessEqual(r['fixtype'],params['fixtype'])
1148 self.failUnlessEqual(r['ETAminute'],params['ETAminute'])
1149 self.failUnlessEqual(r['ETAhour'],params['ETAhour'])
1150 self.failUnlessEqual(r['ETAday'],params['ETAday'])
1151 self.failUnlessEqual(r['ETAmonth'],params['ETAmonth'])
1152 self.failUnlessAlmostEqual(r['draught'],params['draught'],1)
1153 self.failUnlessEqual(r['destination'],params['destination'])
1154 self.failUnlessEqual(r['dte'],params['dte'])
1155 self.failUnlessEqual(r['Spare'],params['Spare'])
1156
1158 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
1159 help='decode a "shipdata" AIS message')
1160 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
1161 help='encode a "shipdata" AIS message')
1162 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
1163 ,help='Field parameter value [default: %default]')
1164 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
1165 ,help='Field parameter value [default: %default]')
1166 parser.add_option('--AISversion-field', dest='AISversionField',default=0,metavar='uint',type='int'
1167 ,help='Field parameter value [default: %default]')
1168 parser.add_option('--IMOnumber-field', dest='IMOnumberField',default=0,metavar='uint',type='int'
1169 ,help='Field parameter value [default: %default]')
1170 parser.add_option('--callsign-field', dest='callsignField',default='@@@@@@@',metavar='aisstr6',type='string'
1171 ,help='Field parameter value [default: %default]')
1172 parser.add_option('--name-field', dest='nameField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string'
1173 ,help='Field parameter value [default: %default]')
1174 parser.add_option('--shipandcargo-field', dest='shipandcargoField',default=0,metavar='uint',type='int'
1175 ,help='Field parameter value [default: %default]')
1176 parser.add_option('--dimA-field', dest='dimAField',default=0,metavar='uint',type='int'
1177 ,help='Field parameter value [default: %default]')
1178 parser.add_option('--dimB-field', dest='dimBField',default=0,metavar='uint',type='int'
1179 ,help='Field parameter value [default: %default]')
1180 parser.add_option('--dimC-field', dest='dimCField',default=0,metavar='uint',type='int'
1181 ,help='Field parameter value [default: %default]')
1182 parser.add_option('--dimD-field', dest='dimDField',default=0,metavar='uint',type='int'
1183 ,help='Field parameter value [default: %default]')
1184 parser.add_option('--fixtype-field', dest='fixtypeField',default=0,metavar='uint',type='int'
1185 ,help='Field parameter value [default: %default]')
1186 parser.add_option('--ETAminute-field', dest='ETAminuteField',default=60,metavar='uint',type='int'
1187 ,help='Field parameter value [default: %default]')
1188 parser.add_option('--ETAhour-field', dest='ETAhourField',default=24,metavar='uint',type='int'
1189 ,help='Field parameter value [default: %default]')
1190 parser.add_option('--ETAday-field', dest='ETAdayField',default=0,metavar='uint',type='int'
1191 ,help='Field parameter value [default: %default]')
1192 parser.add_option('--ETAmonth-field', dest='ETAmonthField',default=0,metavar='uint',type='int'
1193 ,help='Field parameter value [default: %default]')
1194 parser.add_option('--draught-field', dest='draughtField',default=Decimal('0'),metavar='udecimal',type='string'
1195 ,help='Field parameter value [default: %default]')
1196 parser.add_option('--destination-field', dest='destinationField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string'
1197 ,help='Field parameter value [default: %default]')
1198 parser.add_option('--dte-field', dest='dteField',metavar='uint',type='int'
1199 ,help='Field parameter value [default: %default]')
1200
1201
1202 if __name__=='__main__':
1203
1204 from optparse import OptionParser
1205 parser = OptionParser(usage="%prog [options]",
1206 version="%prog "+__version__)
1207
1208 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
1209 help='run the documentation tests')
1210 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
1211 help='run the unit tests')
1212 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
1213 help='Make the test output verbose')
1214
1215
1216
1217 typeChoices = ('binary','nmeapayload','nmea')
1218 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
1219 ,default='nmeapayload'
1220 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]')
1221
1222
1223 outputChoices = ('std','html','csv','sql' )
1224 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
1225 ,default='std'
1226 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
1227
1228 parser.add_option('-o','--output',dest='outputFileName',default=None,
1229 help='Name of the python file to write [default: stdout]')
1230
1231 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
1232 choices=fieldList,
1233 help='Which fields to include in the output. Currently only for csv output [default: all]')
1234
1235 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
1236 help='Print the field name for csv')
1237
1238 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true',
1239 help='Print out an sql create command for the table.')
1240
1241 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true',
1242 help='Print a LaTeX table of the type')
1243
1244 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true',
1245 help='Print delimited table of the type (for Word table importing)')
1246 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t'
1247 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)')
1248
1249
1250 dbChoices = ('sqlite','postgres')
1251 parser.add_option('-D','--db-type',dest='dbType',default='postgres'
1252 ,choices=dbChoices,type='choice'
1253 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]')
1254
1255 addMsgOptions(parser)
1256
1257 (options,args) = parser.parse_args()
1258 success=True
1259
1260 if options.doctest:
1261 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
1262 sys.argv= [sys.argv[0]]
1263 if options.verbose: sys.argv.append('-v')
1264 import doctest
1265 numfail,numtests=doctest.testmod()
1266 if numfail==0: print 'ok'
1267 else:
1268 print 'FAILED'
1269 success=False
1270
1271 if not success: sys.exit('Something Failed')
1272 del success
1273
1274 if options.unittest:
1275 sys.argv = [sys.argv[0]]
1276 if options.verbose: sys.argv.append('-v')
1277 unittest.main()
1278
1279 outfile = sys.stdout
1280 if None!=options.outputFileName:
1281 outfile = file(options.outputFileName,'w')
1282
1283
1284 if options.doEncode:
1285
1286 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
1287 if None==options.UserIDField: parser.error("missing value for UserIDField")
1288 if None==options.AISversionField: parser.error("missing value for AISversionField")
1289 if None==options.IMOnumberField: parser.error("missing value for IMOnumberField")
1290 if None==options.callsignField: parser.error("missing value for callsignField")
1291 if None==options.nameField: parser.error("missing value for nameField")
1292 if None==options.shipandcargoField: parser.error("missing value for shipandcargoField")
1293 if None==options.dimAField: parser.error("missing value for dimAField")
1294 if None==options.dimBField: parser.error("missing value for dimBField")
1295 if None==options.dimCField: parser.error("missing value for dimCField")
1296 if None==options.dimDField: parser.error("missing value for dimDField")
1297 if None==options.fixtypeField: parser.error("missing value for fixtypeField")
1298 if None==options.ETAminuteField: parser.error("missing value for ETAminuteField")
1299 if None==options.ETAhourField: parser.error("missing value for ETAhourField")
1300 if None==options.ETAdayField: parser.error("missing value for ETAdayField")
1301 if None==options.ETAmonthField: parser.error("missing value for ETAmonthField")
1302 if None==options.draughtField: parser.error("missing value for draughtField")
1303 if None==options.destinationField: parser.error("missing value for destinationField")
1304 if None==options.dteField: parser.error("missing value for dteField")
1305 msgDict={
1306 'MessageID': '5',
1307 'RepeatIndicator': options.RepeatIndicatorField,
1308 'UserID': options.UserIDField,
1309 'AISversion': options.AISversionField,
1310 'IMOnumber': options.IMOnumberField,
1311 'callsign': options.callsignField,
1312 'name': options.nameField,
1313 'shipandcargo': options.shipandcargoField,
1314 'dimA': options.dimAField,
1315 'dimB': options.dimBField,
1316 'dimC': options.dimCField,
1317 'dimD': options.dimDField,
1318 'fixtype': options.fixtypeField,
1319 'ETAminute': options.ETAminuteField,
1320 'ETAhour': options.ETAhourField,
1321 'ETAday': options.ETAdayField,
1322 'ETAmonth': options.ETAmonthField,
1323 'draught': options.draughtField,
1324 'destination': options.destinationField,
1325 'dte': options.dteField,
1326 'Spare': '0',
1327 }
1328
1329 bits = encode(msgDict)
1330 if 'binary'==options.ioType: print str(bits)
1331 elif 'nmeapayload'==options.ioType:
1332
1333 print "bitLen",len(bits)
1334 bitLen=len(bits)
1335 if bitLen%6!=0:
1336 bits = bits + BitVector(size=(6 - (bitLen%6)))
1337 print "result:",binary.bitvectoais6(bits)[0]
1338
1339
1340
1341 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
1342 else: sys.exit('ERROR: unknown ioType. Help!')
1343
1344
1345 if options.sqlCreate:
1346 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType)
1347
1348 if options.latexDefinitionTable:
1349 latexDefinitionTable(outfile)
1350
1351
1352 if options.textDefinitionTable:
1353 textDefinitionTable(outfile,options.delimTextDefinitionTable)
1354
1355 if options.printCsvfieldList:
1356
1357 if None == options.fieldList: options.fieldList = fieldList
1358 import StringIO
1359 buf = StringIO.StringIO()
1360 for field in options.fieldList:
1361 buf.write(field+',')
1362 result = buf.getvalue()
1363 if result[-1] == ',': print result[:-1]
1364 else: print result
1365
1366 if options.doDecode:
1367 if len(args)==0: args = sys.stdin
1368 for msg in args:
1369 bv = None
1370
1371 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'):
1372
1373
1374 bv = binary.ais6tobitvec(msg.split(',')[5])
1375 else:
1376
1377 binaryMsg=True
1378 for c in msg:
1379 if c not in ('0','1'):
1380 binaryMsg=False
1381 break
1382 if binaryMsg:
1383 bv = BitVector(bitstring=msg)
1384 else:
1385 bv = binary.ais6tobitvec(msg)
1386
1387 printFields(decode(bv)
1388 ,out=outfile
1389 ,format=options.outputType
1390 ,fieldList=options.fieldList
1391 ,dbType=options.dbType
1392 )
1393