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 'Spare',
54 'dac',
55 'fid',
56 'efid',
57 'numreports',
58 'stationid1',
59 'time1_day',
60 'time1_hour',
61 'time1_min',
62 'center1_longitude',
63 'center1_latitude',
64 'timetoexpire1',
65 'radius1',
66 'stationid2',
67 'time2_day',
68 'time2_hour',
69 'time2_min',
70 'center2_longitude',
71 'center2_latitude',
72 'timetoexpire2',
73 'radius2',
74 'stationid3',
75 'time3_day',
76 'time3_hour',
77 'time3_min',
78 'center3_longitude',
79 'center3_latitude',
80 'timetoexpire3',
81 'radius3',
82 'Spare2',
83 )
84
85 fieldListPostgres = (
86 'MessageID',
87 'RepeatIndicator',
88 'UserID',
89 'Spare',
90 'dac',
91 'fid',
92 'efid',
93 'numreports',
94 'stationid1',
95 'time1_day',
96 'time1_hour',
97 'time1_min',
98 'center1',
99 'timetoexpire1',
100 'radius1',
101 'stationid2',
102 'time2_day',
103 'time2_hour',
104 'time2_min',
105 'center2',
106 'timetoexpire2',
107 'radius2',
108 'stationid3',
109 'time3_day',
110 'time3_hour',
111 'time3_min',
112 'center3',
113 'timetoexpire3',
114 'radius3',
115 'Spare2',
116 )
117
118 toPgFields = {
119 'center1_longitude':'center1',
120 'center1_latitude':'center1',
121 'center2_longitude':'center2',
122 'center2_latitude':'center2',
123 'center3_longitude':'center3',
124 'center3_latitude':'center3',
125 }
126 '''
127 Go to the Postgis field names from the straight field name
128 '''
129
130 fromPgFields = {
131 'center1':('center1_longitude','center1_latitude',),
132 'center2':('center2_longitude','center2_latitude',),
133 'center3':('center3_longitude','center3_latitude',),
134 }
135 '''
136 Go from the Postgis field names to the straight field name
137 '''
138
139 pgTypes = {
140 'center1':'POINT',
141 'center2':'POINT',
142 'center3':'POINT',
143 }
144 '''
145 Lookup table for each postgis field name to get its type.
146 '''
147
148 -def encode(params, validate=False):
149 '''Create a whalenotice binary message payload to pack into an AIS Msg whalenotice.
150
151 Fields in params:
152 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8")
153 - RepeatIndicator(uint): Indicated how many times a message has been repeated
154 - UserID(uint): Unique ship identification number (MMSI)
155 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
156 - dac(uint): Designated Area Code - 366 for the United States (field automatically set to "366")
157 - fid(uint): Functional IDentifier - 63 for the Whale Notice (field automatically set to "63")
158 - efid(uint): Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type) (field automatically set to "1")
159 - numreports(uint): Number of detection reports filled out in this message
160 - stationid1(uint): Identifier of the station that recorded the whale. Usually a number.
161 - time1_day(uint): Time of most recent whale detection. UTC day of the month 1..31
162 - time1_hour(uint): Time of most recent whale detection. UTC hours 0..23
163 - time1_min(uint): Time of most recent whale detection. UTC minutes
164 - center1_longitude(decimal): Center of the detection zone. East West location
165 - center1_latitude(decimal): Center of the detection zone. North South location
166 - timetoexpire1(uint): Seconds from the detection time until the notice expires
167 - radius1(uint): Distance from center of detection zone (lat/lon above)
168 - stationid2(uint): Identifier of the station that recorded the whale. Usually a number.
169 - time2_day(uint): Time of most recent whale detection. UTC day of the month 1..31
170 - time2_hour(uint): Time of most recent whale detection. UTC hours 0..23
171 - time2_min(uint): Time of most recent whale detection. UTC minutes
172 - center2_longitude(decimal): Center of the detection zone. East West location
173 - center2_latitude(decimal): Center of the detection zone. North South location
174 - timetoexpire2(uint): Seconds from the detection time until the notice expires
175 - radius2(uint): Distance from center of detection zone (lat/lon above)
176 - stationid3(uint): Identifier of the station that recorded the whale. Usually a number.
177 - time3_day(uint): Time of most recent whale detection. UTC day of the month 1..31
178 - time3_hour(uint): Time of most recent whale detection. UTC hours 0..23
179 - time3_min(uint): Time of most recent whale detection. UTC minutes
180 - center3_longitude(decimal): Center of the detection zone. East West location
181 - center3_latitude(decimal): Center of the detection zone. North South location
182 - timetoexpire3(uint): Seconds from the detection time until the notice expires
183 - radius3(uint): Distance from center of detection zone (lat/lon above)
184 - Spare2(uint): Not used. Should be set to zero. (field automatically set to "0")
185 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing
186 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
187 @rtype: BitVector
188 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8
189 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits.
190 '''
191
192 bvList = []
193 bvList.append(binary.setBitVectorSize(BitVector(intVal=8),6))
194 if 'RepeatIndicator' in params:
195 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2))
196 else:
197 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
198 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30))
199 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
200 bvList.append(binary.setBitVectorSize(BitVector(intVal=366),10))
201 bvList.append(binary.setBitVectorSize(BitVector(intVal=63),6))
202 bvList.append(binary.setBitVectorSize(BitVector(intVal=1),12))
203 if 'numreports' in params:
204 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['numreports']),2))
205 else:
206 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
207 if 'stationid1' in params:
208 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['stationid1']),8))
209 else:
210 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8))
211 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time1_day']),5))
212 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time1_hour']),5))
213 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time1_min']),6))
214 if 'center1_longitude' in params:
215 bvList.append(binary.bvFromSignedInt(int(Decimal(params['center1_longitude'])*Decimal('600000')),28))
216 else:
217 bvList.append(binary.bvFromSignedInt(108600000,28))
218 if 'center1_latitude' in params:
219 bvList.append(binary.bvFromSignedInt(int(Decimal(params['center1_latitude'])*Decimal('600000')),27))
220 else:
221 bvList.append(binary.bvFromSignedInt(54600000,27))
222 if 'timetoexpire1' in params:
223 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetoexpire1']),16))
224 else:
225 bvList.append(binary.setBitVectorSize(BitVector(intVal=65535),16))
226 if 'radius1' in params:
227 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['radius1']),16))
228 else:
229 bvList.append(binary.setBitVectorSize(BitVector(intVal=65534),16))
230 if 'stationid2' in params:
231 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['stationid2']),8))
232 else:
233 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8))
234 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time2_day']),5))
235 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time2_hour']),5))
236 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time2_min']),6))
237 if 'center2_longitude' in params:
238 bvList.append(binary.bvFromSignedInt(int(Decimal(params['center2_longitude'])*Decimal('600000')),28))
239 else:
240 bvList.append(binary.bvFromSignedInt(108600000,28))
241 if 'center2_latitude' in params:
242 bvList.append(binary.bvFromSignedInt(int(Decimal(params['center2_latitude'])*Decimal('600000')),27))
243 else:
244 bvList.append(binary.bvFromSignedInt(54600000,27))
245 if 'timetoexpire2' in params:
246 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetoexpire2']),16))
247 else:
248 bvList.append(binary.setBitVectorSize(BitVector(intVal=65535),16))
249 if 'radius2' in params:
250 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['radius2']),16))
251 else:
252 bvList.append(binary.setBitVectorSize(BitVector(intVal=65534),16))
253 if 'stationid3' in params:
254 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['stationid3']),8))
255 else:
256 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8))
257 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time3_day']),5))
258 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time3_hour']),5))
259 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time3_min']),6))
260 if 'center3_longitude' in params:
261 bvList.append(binary.bvFromSignedInt(int(Decimal(params['center3_longitude'])*Decimal('600000')),28))
262 else:
263 bvList.append(binary.bvFromSignedInt(108600000,28))
264 if 'center3_latitude' in params:
265 bvList.append(binary.bvFromSignedInt(int(Decimal(params['center3_latitude'])*Decimal('600000')),27))
266 else:
267 bvList.append(binary.bvFromSignedInt(54600000,27))
268 if 'timetoexpire3' in params:
269 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetoexpire3']),16))
270 else:
271 bvList.append(binary.setBitVectorSize(BitVector(intVal=65535),16))
272 if 'radius3' in params:
273 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['radius3']),16))
274 else:
275 bvList.append(binary.setBitVectorSize(BitVector(intVal=65534),16))
276 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),21))
277
278 return binary.joinBV(bvList)
279
280 -def decode(bv, validate=False):
281 '''Unpack a whalenotice message
282
283 Fields in params:
284 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8")
285 - RepeatIndicator(uint): Indicated how many times a message has been repeated
286 - UserID(uint): Unique ship identification number (MMSI)
287 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
288 - dac(uint): Designated Area Code - 366 for the United States (field automatically set to "366")
289 - fid(uint): Functional IDentifier - 63 for the Whale Notice (field automatically set to "63")
290 - efid(uint): Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type) (field automatically set to "1")
291 - numreports(uint): Number of detection reports filled out in this message
292 - stationid1(uint): Identifier of the station that recorded the whale. Usually a number.
293 - time1_day(uint): Time of most recent whale detection. UTC day of the month 1..31
294 - time1_hour(uint): Time of most recent whale detection. UTC hours 0..23
295 - time1_min(uint): Time of most recent whale detection. UTC minutes
296 - center1_longitude(decimal): Center of the detection zone. East West location
297 - center1_latitude(decimal): Center of the detection zone. North South location
298 - timetoexpire1(uint): Seconds from the detection time until the notice expires
299 - radius1(uint): Distance from center of detection zone (lat/lon above)
300 - stationid2(uint): Identifier of the station that recorded the whale. Usually a number.
301 - time2_day(uint): Time of most recent whale detection. UTC day of the month 1..31
302 - time2_hour(uint): Time of most recent whale detection. UTC hours 0..23
303 - time2_min(uint): Time of most recent whale detection. UTC minutes
304 - center2_longitude(decimal): Center of the detection zone. East West location
305 - center2_latitude(decimal): Center of the detection zone. North South location
306 - timetoexpire2(uint): Seconds from the detection time until the notice expires
307 - radius2(uint): Distance from center of detection zone (lat/lon above)
308 - stationid3(uint): Identifier of the station that recorded the whale. Usually a number.
309 - time3_day(uint): Time of most recent whale detection. UTC day of the month 1..31
310 - time3_hour(uint): Time of most recent whale detection. UTC hours 0..23
311 - time3_min(uint): Time of most recent whale detection. UTC minutes
312 - center3_longitude(decimal): Center of the detection zone. East West location
313 - center3_latitude(decimal): Center of the detection zone. North South location
314 - timetoexpire3(uint): Seconds from the detection time until the notice expires
315 - radius3(uint): Distance from center of detection zone (lat/lon above)
316 - Spare2(uint): Not used. Should be set to zero. (field automatically set to "0")
317 @type bv: BitVector
318 @param bv: Bits defining a message
319 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
320 @rtype: dict
321 @return: params
322 '''
323
324
325
326
327 r = {}
328 r['MessageID']=8
329 r['RepeatIndicator']=int(bv[6:8])
330 r['UserID']=int(bv[8:38])
331 r['Spare']=0
332 r['dac']=366
333 r['fid']=63
334 r['efid']=1
335 r['numreports']=int(bv[68:70])
336 r['stationid1']=int(bv[70:78])
337 r['time1_day']=int(bv[78:83])
338 r['time1_hour']=int(bv[83:88])
339 r['time1_min']=int(bv[88:94])
340 r['center1_longitude']=Decimal(binary.signedIntFromBV(bv[94:122]))/Decimal('600000')
341 r['center1_latitude']=Decimal(binary.signedIntFromBV(bv[122:149]))/Decimal('600000')
342 r['timetoexpire1']=int(bv[149:165])
343 r['radius1']=int(bv[165:181])
344 r['stationid2']=int(bv[181:189])
345 r['time2_day']=int(bv[189:194])
346 r['time2_hour']=int(bv[194:199])
347 r['time2_min']=int(bv[199:205])
348 r['center2_longitude']=Decimal(binary.signedIntFromBV(bv[205:233]))/Decimal('600000')
349 r['center2_latitude']=Decimal(binary.signedIntFromBV(bv[233:260]))/Decimal('600000')
350 r['timetoexpire2']=int(bv[260:276])
351 r['radius2']=int(bv[276:292])
352 r['stationid3']=int(bv[292:300])
353 r['time3_day']=int(bv[300:305])
354 r['time3_hour']=int(bv[305:310])
355 r['time3_min']=int(bv[310:316])
356 r['center3_longitude']=Decimal(binary.signedIntFromBV(bv[316:344]))/Decimal('600000')
357 r['center3_latitude']=Decimal(binary.signedIntFromBV(bv[344:371]))/Decimal('600000')
358 r['timetoexpire3']=int(bv[371:387])
359 r['radius3']=int(bv[387:403])
360 r['Spare2']=0
361 return r
362
365
368
371
374
377
380
383
385 return int(bv[68:70])
386
388 return int(bv[70:78])
389
391 return int(bv[78:83])
392
394 return int(bv[83:88])
395
397 return int(bv[88:94])
398
401
404
406 return int(bv[149:165])
407
409 return int(bv[165:181])
410
412 return int(bv[181:189])
413
415 return int(bv[189:194])
416
418 return int(bv[194:199])
419
421 return int(bv[199:205])
422
425
428
430 return int(bv[260:276])
431
433 return int(bv[276:292])
434
436 return int(bv[292:300])
437
439 return int(bv[300:305])
440
442 return int(bv[305:310])
443
445 return int(bv[310:316])
446
449
452
454 return int(bv[371:387])
455
457 return int(bv[387:403])
458
461
462
464 out.write("<h3>whalenotice</h3>\n")
465 out.write("<table border=\"1\">\n")
466 out.write("<tr bgcolor=\"orange\">\n")
467 out.write("<th align=\"left\">Field Name</th>\n")
468 out.write("<th align=\"left\">Type</th>\n")
469 out.write("<th align=\"left\">Value</th>\n")
470 out.write("<th align=\"left\">Value in Lookup Table</th>\n")
471 out.write("<th align=\"left\">Units</th>\n")
472 out.write("\n")
473 out.write("<tr>\n")
474 out.write("<td>MessageID</td>\n")
475 out.write("<td>uint</td>\n")
476 if 'MessageID' in params:
477 out.write(" <td>"+str(params['MessageID'])+"</td>\n")
478 out.write(" <td>"+str(params['MessageID'])+"</td>\n")
479 out.write("</tr>\n")
480 out.write("\n")
481 out.write("<tr>\n")
482 out.write("<td>RepeatIndicator</td>\n")
483 out.write("<td>uint</td>\n")
484 if 'RepeatIndicator' in params:
485 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n")
486 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut:
487 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>")
488 else:
489 out.write("<td><i>Missing LUT entry</i></td>")
490 out.write("</tr>\n")
491 out.write("\n")
492 out.write("<tr>\n")
493 out.write("<td>UserID</td>\n")
494 out.write("<td>uint</td>\n")
495 if 'UserID' in params:
496 out.write(" <td>"+str(params['UserID'])+"</td>\n")
497 out.write(" <td>"+str(params['UserID'])+"</td>\n")
498 out.write("</tr>\n")
499 out.write("\n")
500 out.write("<tr>\n")
501 out.write("<td>Spare</td>\n")
502 out.write("<td>uint</td>\n")
503 if 'Spare' in params:
504 out.write(" <td>"+str(params['Spare'])+"</td>\n")
505 out.write(" <td>"+str(params['Spare'])+"</td>\n")
506 out.write("</tr>\n")
507 out.write("\n")
508 out.write("<tr>\n")
509 out.write("<td>dac</td>\n")
510 out.write("<td>uint</td>\n")
511 if 'dac' in params:
512 out.write(" <td>"+str(params['dac'])+"</td>\n")
513 out.write(" <td>"+str(params['dac'])+"</td>\n")
514 out.write("</tr>\n")
515 out.write("\n")
516 out.write("<tr>\n")
517 out.write("<td>fid</td>\n")
518 out.write("<td>uint</td>\n")
519 if 'fid' in params:
520 out.write(" <td>"+str(params['fid'])+"</td>\n")
521 out.write(" <td>"+str(params['fid'])+"</td>\n")
522 out.write("</tr>\n")
523 out.write("\n")
524 out.write("<tr>\n")
525 out.write("<td>efid</td>\n")
526 out.write("<td>uint</td>\n")
527 if 'efid' in params:
528 out.write(" <td>"+str(params['efid'])+"</td>\n")
529 out.write(" <td>"+str(params['efid'])+"</td>\n")
530 out.write("</tr>\n")
531 out.write("\n")
532 out.write("<tr>\n")
533 out.write("<td>numreports</td>\n")
534 out.write("<td>uint</td>\n")
535 if 'numreports' in params:
536 out.write(" <td>"+str(params['numreports'])+"</td>\n")
537 out.write(" <td>"+str(params['numreports'])+"</td>\n")
538 out.write("</tr>\n")
539 out.write("\n")
540 out.write("<tr>\n")
541 out.write("<td>stationid1</td>\n")
542 out.write("<td>uint</td>\n")
543 if 'stationid1' in params:
544 out.write(" <td>"+str(params['stationid1'])+"</td>\n")
545 out.write(" <td>"+str(params['stationid1'])+"</td>\n")
546 out.write("</tr>\n")
547 out.write("\n")
548 out.write("<tr>\n")
549 out.write("<td>time1_day</td>\n")
550 out.write("<td>uint</td>\n")
551 if 'time1_day' in params:
552 out.write(" <td>"+str(params['time1_day'])+"</td>\n")
553 out.write(" <td>"+str(params['time1_day'])+"</td>\n")
554 out.write("</tr>\n")
555 out.write("\n")
556 out.write("<tr>\n")
557 out.write("<td>time1_hour</td>\n")
558 out.write("<td>uint</td>\n")
559 if 'time1_hour' in params:
560 out.write(" <td>"+str(params['time1_hour'])+"</td>\n")
561 out.write(" <td>"+str(params['time1_hour'])+"</td>\n")
562 out.write("</tr>\n")
563 out.write("\n")
564 out.write("<tr>\n")
565 out.write("<td>time1_min</td>\n")
566 out.write("<td>uint</td>\n")
567 if 'time1_min' in params:
568 out.write(" <td>"+str(params['time1_min'])+"</td>\n")
569 out.write(" <td>"+str(params['time1_min'])+"</td>\n")
570 out.write("</tr>\n")
571 out.write("\n")
572 out.write("<tr>\n")
573 out.write("<td>center1_longitude</td>\n")
574 out.write("<td>decimal</td>\n")
575 if 'center1_longitude' in params:
576 out.write(" <td>"+str(params['center1_longitude'])+"</td>\n")
577 out.write(" <td>"+str(params['center1_longitude'])+"</td>\n")
578 out.write("<td>degrees</td>\n")
579 out.write("</tr>\n")
580 out.write("\n")
581 out.write("<tr>\n")
582 out.write("<td>center1_latitude</td>\n")
583 out.write("<td>decimal</td>\n")
584 if 'center1_latitude' in params:
585 out.write(" <td>"+str(params['center1_latitude'])+"</td>\n")
586 out.write(" <td>"+str(params['center1_latitude'])+"</td>\n")
587 out.write("<td>degrees</td>\n")
588 out.write("</tr>\n")
589 out.write("\n")
590 out.write("<tr>\n")
591 out.write("<td>timetoexpire1</td>\n")
592 out.write("<td>uint</td>\n")
593 if 'timetoexpire1' in params:
594 out.write(" <td>"+str(params['timetoexpire1'])+"</td>\n")
595 if str(params['timetoexpire1']) in timetoexpire1DecodeLut:
596 out.write("<td>"+timetoexpire1DecodeLut[str(params['timetoexpire1'])]+"</td>")
597 else:
598 out.write("<td><i>Missing LUT entry</i></td>")
599 out.write("<td>seconds</td>\n")
600 out.write("</tr>\n")
601 out.write("\n")
602 out.write("<tr>\n")
603 out.write("<td>radius1</td>\n")
604 out.write("<td>uint</td>\n")
605 if 'radius1' in params:
606 out.write(" <td>"+str(params['radius1'])+"</td>\n")
607 out.write(" <td>"+str(params['radius1'])+"</td>\n")
608 out.write("<td>m</td>\n")
609 out.write("</tr>\n")
610 out.write("\n")
611 out.write("<tr>\n")
612 out.write("<td>stationid2</td>\n")
613 out.write("<td>uint</td>\n")
614 if 'stationid2' in params:
615 out.write(" <td>"+str(params['stationid2'])+"</td>\n")
616 out.write(" <td>"+str(params['stationid2'])+"</td>\n")
617 out.write("</tr>\n")
618 out.write("\n")
619 out.write("<tr>\n")
620 out.write("<td>time2_day</td>\n")
621 out.write("<td>uint</td>\n")
622 if 'time2_day' in params:
623 out.write(" <td>"+str(params['time2_day'])+"</td>\n")
624 out.write(" <td>"+str(params['time2_day'])+"</td>\n")
625 out.write("</tr>\n")
626 out.write("\n")
627 out.write("<tr>\n")
628 out.write("<td>time2_hour</td>\n")
629 out.write("<td>uint</td>\n")
630 if 'time2_hour' in params:
631 out.write(" <td>"+str(params['time2_hour'])+"</td>\n")
632 out.write(" <td>"+str(params['time2_hour'])+"</td>\n")
633 out.write("</tr>\n")
634 out.write("\n")
635 out.write("<tr>\n")
636 out.write("<td>time2_min</td>\n")
637 out.write("<td>uint</td>\n")
638 if 'time2_min' in params:
639 out.write(" <td>"+str(params['time2_min'])+"</td>\n")
640 out.write(" <td>"+str(params['time2_min'])+"</td>\n")
641 out.write("</tr>\n")
642 out.write("\n")
643 out.write("<tr>\n")
644 out.write("<td>center2_longitude</td>\n")
645 out.write("<td>decimal</td>\n")
646 if 'center2_longitude' in params:
647 out.write(" <td>"+str(params['center2_longitude'])+"</td>\n")
648 out.write(" <td>"+str(params['center2_longitude'])+"</td>\n")
649 out.write("<td>degrees</td>\n")
650 out.write("</tr>\n")
651 out.write("\n")
652 out.write("<tr>\n")
653 out.write("<td>center2_latitude</td>\n")
654 out.write("<td>decimal</td>\n")
655 if 'center2_latitude' in params:
656 out.write(" <td>"+str(params['center2_latitude'])+"</td>\n")
657 out.write(" <td>"+str(params['center2_latitude'])+"</td>\n")
658 out.write("<td>degrees</td>\n")
659 out.write("</tr>\n")
660 out.write("\n")
661 out.write("<tr>\n")
662 out.write("<td>timetoexpire2</td>\n")
663 out.write("<td>uint</td>\n")
664 if 'timetoexpire2' in params:
665 out.write(" <td>"+str(params['timetoexpire2'])+"</td>\n")
666 if str(params['timetoexpire2']) in timetoexpire2DecodeLut:
667 out.write("<td>"+timetoexpire2DecodeLut[str(params['timetoexpire2'])]+"</td>")
668 else:
669 out.write("<td><i>Missing LUT entry</i></td>")
670 out.write("<td>seconds</td>\n")
671 out.write("</tr>\n")
672 out.write("\n")
673 out.write("<tr>\n")
674 out.write("<td>radius2</td>\n")
675 out.write("<td>uint</td>\n")
676 if 'radius2' in params:
677 out.write(" <td>"+str(params['radius2'])+"</td>\n")
678 out.write(" <td>"+str(params['radius2'])+"</td>\n")
679 out.write("<td>m</td>\n")
680 out.write("</tr>\n")
681 out.write("\n")
682 out.write("<tr>\n")
683 out.write("<td>stationid3</td>\n")
684 out.write("<td>uint</td>\n")
685 if 'stationid3' in params:
686 out.write(" <td>"+str(params['stationid3'])+"</td>\n")
687 out.write(" <td>"+str(params['stationid3'])+"</td>\n")
688 out.write("</tr>\n")
689 out.write("\n")
690 out.write("<tr>\n")
691 out.write("<td>time3_day</td>\n")
692 out.write("<td>uint</td>\n")
693 if 'time3_day' in params:
694 out.write(" <td>"+str(params['time3_day'])+"</td>\n")
695 out.write(" <td>"+str(params['time3_day'])+"</td>\n")
696 out.write("</tr>\n")
697 out.write("\n")
698 out.write("<tr>\n")
699 out.write("<td>time3_hour</td>\n")
700 out.write("<td>uint</td>\n")
701 if 'time3_hour' in params:
702 out.write(" <td>"+str(params['time3_hour'])+"</td>\n")
703 out.write(" <td>"+str(params['time3_hour'])+"</td>\n")
704 out.write("</tr>\n")
705 out.write("\n")
706 out.write("<tr>\n")
707 out.write("<td>time3_min</td>\n")
708 out.write("<td>uint</td>\n")
709 if 'time3_min' in params:
710 out.write(" <td>"+str(params['time3_min'])+"</td>\n")
711 out.write(" <td>"+str(params['time3_min'])+"</td>\n")
712 out.write("</tr>\n")
713 out.write("\n")
714 out.write("<tr>\n")
715 out.write("<td>center3_longitude</td>\n")
716 out.write("<td>decimal</td>\n")
717 if 'center3_longitude' in params:
718 out.write(" <td>"+str(params['center3_longitude'])+"</td>\n")
719 out.write(" <td>"+str(params['center3_longitude'])+"</td>\n")
720 out.write("<td>degrees</td>\n")
721 out.write("</tr>\n")
722 out.write("\n")
723 out.write("<tr>\n")
724 out.write("<td>center3_latitude</td>\n")
725 out.write("<td>decimal</td>\n")
726 if 'center3_latitude' in params:
727 out.write(" <td>"+str(params['center3_latitude'])+"</td>\n")
728 out.write(" <td>"+str(params['center3_latitude'])+"</td>\n")
729 out.write("<td>degrees</td>\n")
730 out.write("</tr>\n")
731 out.write("\n")
732 out.write("<tr>\n")
733 out.write("<td>timetoexpire3</td>\n")
734 out.write("<td>uint</td>\n")
735 if 'timetoexpire3' in params:
736 out.write(" <td>"+str(params['timetoexpire3'])+"</td>\n")
737 if str(params['timetoexpire3']) in timetoexpire3DecodeLut:
738 out.write("<td>"+timetoexpire3DecodeLut[str(params['timetoexpire3'])]+"</td>")
739 else:
740 out.write("<td><i>Missing LUT entry</i></td>")
741 out.write("<td>seconds</td>\n")
742 out.write("</tr>\n")
743 out.write("\n")
744 out.write("<tr>\n")
745 out.write("<td>radius3</td>\n")
746 out.write("<td>uint</td>\n")
747 if 'radius3' in params:
748 out.write(" <td>"+str(params['radius3'])+"</td>\n")
749 out.write(" <td>"+str(params['radius3'])+"</td>\n")
750 out.write("<td>m</td>\n")
751 out.write("</tr>\n")
752 out.write("\n")
753 out.write("<tr>\n")
754 out.write("<td>Spare2</td>\n")
755 out.write("<td>uint</td>\n")
756 if 'Spare2' in params:
757 out.write(" <td>"+str(params['Spare2'])+"</td>\n")
758 out.write(" <td>"+str(params['Spare2'])+"</td>\n")
759 out.write("</tr>\n")
760 out.write("</table>\n")
761
762
764 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer'''
765 out.write("\ <Placemark>\n")
766 out.write("\t <name>"+str(params['stationsid'])+"</name>\n")
767 out.write("\t\t<description>\n")
768 import StringIO
769 buf = StringIO.StringIO()
770 printHtml(params,buf)
771 import cgi
772 out.write(cgi.escape(buf.getvalue()))
773 out.write("\t\t</description>\n")
774 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n")
775 out.write("\t\t<Point>\n")
776 out.write("\t\t\t<coordinates>")
777 out.write(str(params['center1_longitude']))
778 out.write(',')
779 out.write(str(params['center1_latitude']))
780 out.write(",0</coordinates>\n")
781 out.write("\t\t</Point>\n")
782 out.write("\t</Placemark>\n")
783
784 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
785 '''Print a whalenotice message to stdout.
786
787 Fields in params:
788 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8")
789 - RepeatIndicator(uint): Indicated how many times a message has been repeated
790 - UserID(uint): Unique ship identification number (MMSI)
791 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
792 - dac(uint): Designated Area Code - 366 for the United States (field automatically set to "366")
793 - fid(uint): Functional IDentifier - 63 for the Whale Notice (field automatically set to "63")
794 - efid(uint): Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type) (field automatically set to "1")
795 - numreports(uint): Number of detection reports filled out in this message
796 - stationid1(uint): Identifier of the station that recorded the whale. Usually a number.
797 - time1_day(uint): Time of most recent whale detection. UTC day of the month 1..31
798 - time1_hour(uint): Time of most recent whale detection. UTC hours 0..23
799 - time1_min(uint): Time of most recent whale detection. UTC minutes
800 - center1_longitude(decimal): Center of the detection zone. East West location
801 - center1_latitude(decimal): Center of the detection zone. North South location
802 - timetoexpire1(uint): Seconds from the detection time until the notice expires
803 - radius1(uint): Distance from center of detection zone (lat/lon above)
804 - stationid2(uint): Identifier of the station that recorded the whale. Usually a number.
805 - time2_day(uint): Time of most recent whale detection. UTC day of the month 1..31
806 - time2_hour(uint): Time of most recent whale detection. UTC hours 0..23
807 - time2_min(uint): Time of most recent whale detection. UTC minutes
808 - center2_longitude(decimal): Center of the detection zone. East West location
809 - center2_latitude(decimal): Center of the detection zone. North South location
810 - timetoexpire2(uint): Seconds from the detection time until the notice expires
811 - radius2(uint): Distance from center of detection zone (lat/lon above)
812 - stationid3(uint): Identifier of the station that recorded the whale. Usually a number.
813 - time3_day(uint): Time of most recent whale detection. UTC day of the month 1..31
814 - time3_hour(uint): Time of most recent whale detection. UTC hours 0..23
815 - time3_min(uint): Time of most recent whale detection. UTC minutes
816 - center3_longitude(decimal): Center of the detection zone. East West location
817 - center3_latitude(decimal): Center of the detection zone. North South location
818 - timetoexpire3(uint): Seconds from the detection time until the notice expires
819 - radius3(uint): Distance from center of detection zone (lat/lon above)
820 - Spare2(uint): Not used. Should be set to zero. (field automatically set to "0")
821 @param params: Dictionary of field names/values.
822 @param out: File like object to write to
823 @rtype: stdout
824 @return: text to out
825 '''
826
827 if 'std'==format:
828 out.write("whalenotice:\n")
829 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n")
830 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n")
831 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n")
832 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n")
833 if 'dac' in params: out.write(" dac: "+str(params['dac'])+"\n")
834 if 'fid' in params: out.write(" fid: "+str(params['fid'])+"\n")
835 if 'efid' in params: out.write(" efid: "+str(params['efid'])+"\n")
836 if 'numreports' in params: out.write(" numreports: "+str(params['numreports'])+"\n")
837 if 'stationid1' in params: out.write(" stationid1: "+str(params['stationid1'])+"\n")
838 if 'time1_day' in params: out.write(" time1_day: "+str(params['time1_day'])+"\n")
839 if 'time1_hour' in params: out.write(" time1_hour: "+str(params['time1_hour'])+"\n")
840 if 'time1_min' in params: out.write(" time1_min: "+str(params['time1_min'])+"\n")
841 if 'center1_longitude' in params: out.write(" center1_longitude: "+str(params['center1_longitude'])+"\n")
842 if 'center1_latitude' in params: out.write(" center1_latitude: "+str(params['center1_latitude'])+"\n")
843 if 'timetoexpire1' in params: out.write(" timetoexpire1: "+str(params['timetoexpire1'])+"\n")
844 if 'radius1' in params: out.write(" radius1: "+str(params['radius1'])+"\n")
845 if 'stationid2' in params: out.write(" stationid2: "+str(params['stationid2'])+"\n")
846 if 'time2_day' in params: out.write(" time2_day: "+str(params['time2_day'])+"\n")
847 if 'time2_hour' in params: out.write(" time2_hour: "+str(params['time2_hour'])+"\n")
848 if 'time2_min' in params: out.write(" time2_min: "+str(params['time2_min'])+"\n")
849 if 'center2_longitude' in params: out.write(" center2_longitude: "+str(params['center2_longitude'])+"\n")
850 if 'center2_latitude' in params: out.write(" center2_latitude: "+str(params['center2_latitude'])+"\n")
851 if 'timetoexpire2' in params: out.write(" timetoexpire2: "+str(params['timetoexpire2'])+"\n")
852 if 'radius2' in params: out.write(" radius2: "+str(params['radius2'])+"\n")
853 if 'stationid3' in params: out.write(" stationid3: "+str(params['stationid3'])+"\n")
854 if 'time3_day' in params: out.write(" time3_day: "+str(params['time3_day'])+"\n")
855 if 'time3_hour' in params: out.write(" time3_hour: "+str(params['time3_hour'])+"\n")
856 if 'time3_min' in params: out.write(" time3_min: "+str(params['time3_min'])+"\n")
857 if 'center3_longitude' in params: out.write(" center3_longitude: "+str(params['center3_longitude'])+"\n")
858 if 'center3_latitude' in params: out.write(" center3_latitude: "+str(params['center3_latitude'])+"\n")
859 if 'timetoexpire3' in params: out.write(" timetoexpire3: "+str(params['timetoexpire3'])+"\n")
860 if 'radius3' in params: out.write(" radius3: "+str(params['radius3'])+"\n")
861 if 'Spare2' in params: out.write(" Spare2: "+str(params['Spare2'])+"\n")
862 elif 'csv'==format:
863 if None == options.fieldList:
864 options.fieldList = fieldList
865 needComma = False;
866 for field in fieldList:
867 if needComma: out.write(',')
868 needComma = True
869 if field in params:
870 out.write(str(params[field]))
871
872 out.write("\n")
873 elif 'html'==format:
874 printHtml(params,out)
875 elif 'sql'==format:
876 sqlInsertStr(params,out,dbType=dbType)
877 elif 'kml'==format:
878 printKml(params,out)
879 elif 'kml-full'==format:
880 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
881 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n")
882 out.write("<Document>\n")
883 out.write(" <name>whalenotice</name>\n")
884 printKml(params,out)
885 out.write("</Document>\n")
886 out.write("</kml>\n")
887 else:
888 print "ERROR: unknown format:",format
889 assert False
890
891 return
892
893 RepeatIndicatorEncodeLut = {
894 'default':'0',
895 'do not repeat any more':'3',
896 }
897
898 RepeatIndicatorDecodeLut = {
899 '0':'default',
900 '3':'do not repeat any more',
901 }
902
903 timetoexpire1EncodeLut = {
904 'No detection/notice active in region':'0',
905 }
906
907 timetoexpire1DecodeLut = {
908 '0':'No detection/notice active in region',
909 }
910
911 timetoexpire2EncodeLut = {
912 'No detection/notice active in region':'0',
913 }
914
915 timetoexpire2DecodeLut = {
916 '0':'No detection/notice active in region',
917 }
918
919 timetoexpire3EncodeLut = {
920 'No detection/notice active in region':'0',
921 }
922
923 timetoexpire3DecodeLut = {
924 '0':'No detection/notice active in region',
925 }
926
927
928
929
930
931 dbTableName='whalenotice'
932 'Database table name'
933
934 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None
935 ,addCoastGuardFields=True
936 ,dbType='postgres'
937 ):
938 '''
939 Return the SQL CREATE command for this message type
940 @param outfile: file like object to print to.
941 @param fields: which fields to put in the create. Defaults to all.
942 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
943 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
944 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
945 @type addCoastGuardFields: bool
946 @return: sql create string
947 @rtype: str
948
949 @see: sqlCreate
950 '''
951
952 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
953
954 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
955 '''
956 Return the sqlhelp object to create the table.
957
958 @param fields: which fields to put in the create. Defaults to all.
959 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
960 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
961 @type addCoastGuardFields: bool
962 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
963 @return: An object that can be used to generate a return
964 @rtype: sqlhelp.create
965 '''
966 if None == fields: fields = fieldList
967 import sqlhelp
968 c = sqlhelp.create('whalenotice',dbType=dbType)
969 c.addPrimaryKey()
970 if 'MessageID' in fields: c.addInt ('MessageID')
971 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator')
972 if 'UserID' in fields: c.addInt ('UserID')
973 if 'Spare' in fields: c.addInt ('Spare')
974 if 'dac' in fields: c.addInt ('dac')
975 if 'fid' in fields: c.addInt ('fid')
976 if 'efid' in fields: c.addInt ('efid')
977 if 'numreports' in fields: c.addInt ('numreports')
978 if 'stationid1' in fields: c.addInt ('stationid1')
979 if 'time1_day' in fields: c.addInt ('time1_day')
980 if 'time1_hour' in fields: c.addInt ('time1_hour')
981 if 'time1_min' in fields: c.addInt ('time1_min')
982 if dbType != 'postgres':
983 if 'center1_longitude' in fields: c.addDecimal('center1_longitude',8,5)
984 if dbType != 'postgres':
985 if 'center1_latitude' in fields: c.addDecimal('center1_latitude',8,5)
986 if 'timetoexpire1' in fields: c.addInt ('timetoexpire1')
987 if 'radius1' in fields: c.addInt ('radius1')
988 if 'stationid2' in fields: c.addInt ('stationid2')
989 if 'time2_day' in fields: c.addInt ('time2_day')
990 if 'time2_hour' in fields: c.addInt ('time2_hour')
991 if 'time2_min' in fields: c.addInt ('time2_min')
992 if dbType != 'postgres':
993 if 'center2_longitude' in fields: c.addDecimal('center2_longitude',8,5)
994 if dbType != 'postgres':
995 if 'center2_latitude' in fields: c.addDecimal('center2_latitude',8,5)
996 if 'timetoexpire2' in fields: c.addInt ('timetoexpire2')
997 if 'radius2' in fields: c.addInt ('radius2')
998 if 'stationid3' in fields: c.addInt ('stationid3')
999 if 'time3_day' in fields: c.addInt ('time3_day')
1000 if 'time3_hour' in fields: c.addInt ('time3_hour')
1001 if 'time3_min' in fields: c.addInt ('time3_min')
1002 if dbType != 'postgres':
1003 if 'center3_longitude' in fields: c.addDecimal('center3_longitude',8,5)
1004 if dbType != 'postgres':
1005 if 'center3_latitude' in fields: c.addDecimal('center3_latitude',8,5)
1006 if 'timetoexpire3' in fields: c.addInt ('timetoexpire3')
1007 if 'radius3' in fields: c.addInt ('radius3')
1008 if 'Spare2' in fields: c.addInt ('Spare2')
1009
1010 if addCoastGuardFields:
1011
1012
1013
1014
1015
1016 c.addVarChar('cg_r',15)
1017 c.addInt('cg_sec')
1018
1019 c.addTimestamp('cg_timestamp')
1020
1021 if dbType == 'postgres':
1022
1023
1024 c.addPostGIS('center1','POINT',2,SRID=4326);
1025
1026
1027 c.addPostGIS('center2','POINT',2,SRID=4326);
1028
1029
1030 c.addPostGIS('center3','POINT',2,SRID=4326);
1031
1032 return c
1033
1034 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
1035 '''
1036 Return the SQL INSERT command for this message type
1037 @param params: dictionary of values keyed by field name
1038 @param outfile: file like object to print to.
1039 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
1040 @return: sql create string
1041 @rtype: str
1042
1043 @see: sqlCreate
1044 '''
1045 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
1046
1047
1048 -def sqlInsert(params,extraParams=None,dbType='postgres'):
1049 '''
1050 Give the SQL INSERT statement
1051 @param params: dict keyed by field name of values
1052 @param extraParams: any extra fields that you have created beyond the normal ais message fields
1053 @rtype: sqlhelp.insert
1054 @return: insert class instance
1055 @todo: allow optional type checking of params?
1056 @warning: this will take invalid keys happily and do what???
1057 '''
1058 import sqlhelp
1059 i = sqlhelp.insert('whalenotice',dbType=dbType)
1060
1061 if dbType=='postgres':
1062 finished = []
1063 for key in params:
1064 if key in finished:
1065 continue
1066
1067 if key not in toPgFields and key not in fromPgFields:
1068 if type(params[key])==Decimal: i.add(key,float(params[key]))
1069 else: i.add(key,params[key])
1070 else:
1071 if key in fromPgFields:
1072 val = params[key]
1073
1074 i.addPostGIS(key,val)
1075 finished.append(key)
1076 else:
1077
1078 pgName = toPgFields[key]
1079
1080 valStr=pgTypes[pgName]+'('
1081 vals = []
1082 for nonPgKey in fromPgFields[pgName]:
1083 vals.append(str(params[nonPgKey]))
1084 finished.append(nonPgKey)
1085 valStr+=' '.join(vals)+')'
1086 i.addPostGIS(pgName,valStr)
1087 else:
1088 for key in params:
1089 if type(params[key])==Decimal: i.add(key,float(params[key]))
1090 else: i.add(key,params[key])
1091
1092 if None != extraParams:
1093 for key in extraParams:
1094 i.add(key,extraParams[key])
1095
1096 return i
1097
1098
1099
1100
1101
1104 '''
1105 Return the LaTeX definition table for this message type
1106 @param outfile: file like object to print to.
1107 @type outfile: file obj
1108 @return: LaTeX table string via the outfile
1109 @rtype: str
1110
1111 '''
1112 o = outfile
1113
1114 o.write('''
1115 \\begin{table}%[htb]
1116 \\centering
1117 \\begin{tabular}{|l|c|l|}
1118 \\hline
1119 Parameter & Number of bits & Description
1120 \\\\ \\hline\\hline
1121 MessageID & 6 & AIS message number. Must be 8 \\\\ \hline
1122 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline
1123 UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline
1124 Spare & 2 & Reserved for definition by a regional authority. \\\\ \hline
1125 dac & 10 & Designated Area Code - 366 for the United States \\\\ \hline
1126 fid & 6 & Functional IDentifier - 63 for the Whale Notice \\\\ \hline
1127 efid & 12 & Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type) \\\\ \hline
1128 numreports & 2 & Number of detection reports filled out in this message \\\\ \hline
1129 stationid1 & 8 & Identifier of the station that recorded the whale. Usually a number. \\\\ \hline
1130 time1\_day & 5 & Time of most recent whale detection. UTC day of the month 1..31 \\\\ \hline
1131 time1\_hour & 5 & Time of most recent whale detection. UTC hours 0..23 \\\\ \hline
1132 time1\_min & 6 & Time of most recent whale detection. UTC minutes \\\\ \hline
1133 center1\_longitude & 28 & Center of the detection zone. East West location \\\\ \hline
1134 center1\_latitude & 27 & Center of the detection zone. North South location \\\\ \hline
1135 timetoexpire1 & 16 & Seconds from the detection time until the notice expires \\\\ \hline
1136 radius1 & 16 & Distance from center of detection zone (lat/lon above) \\\\ \hline
1137 stationid2 & 8 & Identifier of the station that recorded the whale. Usually a number. \\\\ \hline
1138 time2\_day & 5 & Time of most recent whale detection. UTC day of the month 1..31 \\\\ \hline
1139 time2\_hour & 5 & Time of most recent whale detection. UTC hours 0..23 \\\\ \hline
1140 time2\_min & 6 & Time of most recent whale detection. UTC minutes \\\\ \hline
1141 center2\_longitude & 28 & Center of the detection zone. East West location \\\\ \hline
1142 center2\_latitude & 27 & Center of the detection zone. North South location \\\\ \hline
1143 timetoexpire2 & 16 & Seconds from the detection time until the notice expires \\\\ \hline
1144 radius2 & 16 & Distance from center of detection zone (lat/lon above) \\\\ \hline
1145 stationid3 & 8 & Identifier of the station that recorded the whale. Usually a number. \\\\ \hline
1146 time3\_day & 5 & Time of most recent whale detection. UTC day of the month 1..31 \\\\ \hline
1147 time3\_hour & 5 & Time of most recent whale detection. UTC hours 0..23 \\\\ \hline
1148 time3\_min & 6 & Time of most recent whale detection. UTC minutes \\\\ \hline
1149 center3\_longitude & 28 & Center of the detection zone. East West location \\\\ \hline
1150 center3\_latitude & 27 & Center of the detection zone. North South location \\\\ \hline
1151 timetoexpire3 & 16 & Seconds from the detection time until the notice expires \\\\ \hline
1152 radius3 & 16 & Distance from center of detection zone (lat/lon above) \\\\ \hline
1153 Spare2 & 21 & Not used. Should be set to zero.\\\\ \\hline \\hline
1154 Total bits & 424 & Appears to take 2 slots \\\\ \\hline
1155 \\end{tabular}
1156 \\caption{AIS message number 8: Endangered whale notification binary message}
1157 \\label{tab:whalenotice}
1158 \\end{table}
1159 ''')
1160
1161
1162
1163
1164
1165 -def textDefinitionTable(outfile=sys.stdout
1166 ,delim='\t'
1167 ):
1168 '''
1169 Return the text definition table for this message type
1170 @param outfile: file like object to print to.
1171 @type outfile: file obj
1172 @return: text table string via the outfile
1173 @rtype: str
1174
1175 '''
1176 o = outfile
1177 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description
1178 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 8
1179 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated
1180 UserID'''+delim+'''30'''+delim+'''Unique ship identification number (MMSI)
1181 Spare'''+delim+'''2'''+delim+'''Reserved for definition by a regional authority.
1182 dac'''+delim+'''10'''+delim+'''Designated Area Code - 366 for the United States
1183 fid'''+delim+'''6'''+delim+'''Functional IDentifier - 63 for the Whale Notice
1184 efid'''+delim+'''12'''+delim+'''Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type)
1185 numreports'''+delim+'''2'''+delim+'''Number of detection reports filled out in this message
1186 stationid1'''+delim+'''8'''+delim+'''Identifier of the station that recorded the whale. Usually a number.
1187 time1_day'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC day of the month 1..31
1188 time1_hour'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC hours 0..23
1189 time1_min'''+delim+'''6'''+delim+'''Time of most recent whale detection. UTC minutes
1190 center1_longitude'''+delim+'''28'''+delim+'''Center of the detection zone. East West location
1191 center1_latitude'''+delim+'''27'''+delim+'''Center of the detection zone. North South location
1192 timetoexpire1'''+delim+'''16'''+delim+'''Seconds from the detection time until the notice expires
1193 radius1'''+delim+'''16'''+delim+'''Distance from center of detection zone (lat/lon above)
1194 stationid2'''+delim+'''8'''+delim+'''Identifier of the station that recorded the whale. Usually a number.
1195 time2_day'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC day of the month 1..31
1196 time2_hour'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC hours 0..23
1197 time2_min'''+delim+'''6'''+delim+'''Time of most recent whale detection. UTC minutes
1198 center2_longitude'''+delim+'''28'''+delim+'''Center of the detection zone. East West location
1199 center2_latitude'''+delim+'''27'''+delim+'''Center of the detection zone. North South location
1200 timetoexpire2'''+delim+'''16'''+delim+'''Seconds from the detection time until the notice expires
1201 radius2'''+delim+'''16'''+delim+'''Distance from center of detection zone (lat/lon above)
1202 stationid3'''+delim+'''8'''+delim+'''Identifier of the station that recorded the whale. Usually a number.
1203 time3_day'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC day of the month 1..31
1204 time3_hour'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC hours 0..23
1205 time3_min'''+delim+'''6'''+delim+'''Time of most recent whale detection. UTC minutes
1206 center3_longitude'''+delim+'''28'''+delim+'''Center of the detection zone. East West location
1207 center3_latitude'''+delim+'''27'''+delim+'''Center of the detection zone. North South location
1208 timetoexpire3'''+delim+'''16'''+delim+'''Seconds from the detection time until the notice expires
1209 radius3'''+delim+'''16'''+delim+'''Distance from center of detection zone (lat/lon above)
1210 Spare2'''+delim+'''21'''+delim+'''Not used. Should be set to zero.
1211 Total bits'''+delim+'''424'''+delim+'''Appears to take 2 slots''')
1212
1213
1214
1215
1216
1217 import unittest
1219 '''Return a params file base on the testvalue tags.
1220 @rtype: dict
1221 @return: params based on testvalue tags
1222 '''
1223 params = {}
1224 params['MessageID'] = 8
1225 params['RepeatIndicator'] = 1
1226 params['UserID'] = 1193046
1227 params['Spare'] = 0
1228 params['dac'] = 366
1229 params['fid'] = 63
1230 params['efid'] = 1
1231 params['numreports'] = 3
1232 params['stationid1'] = 76
1233 params['time1_day'] = 28
1234 params['time1_hour'] = 23
1235 params['time1_min'] = 45
1236 params['center1_longitude'] = Decimal('-122.16328055555556')
1237 params['center1_latitude'] = Decimal('37.424458333333334')
1238 params['timetoexpire1'] = 1
1239 params['radius1'] = 5000
1240 params['stationid2'] = 76
1241 params['time2_day'] = 28
1242 params['time2_hour'] = 23
1243 params['time2_min'] = 45
1244 params['center2_longitude'] = Decimal('-122.16328055555556')
1245 params['center2_latitude'] = Decimal('37.424458333333334')
1246 params['timetoexpire2'] = 1
1247 params['radius2'] = 5000
1248 params['stationid3'] = 76
1249 params['time3_day'] = 28
1250 params['time3_hour'] = 23
1251 params['time3_min'] = 45
1252 params['center3_longitude'] = Decimal('-122.16328055555556')
1253 params['center3_latitude'] = Decimal('37.424458333333334')
1254 params['timetoexpire3'] = 1
1255 params['radius3'] = 5000
1256 params['Spare2'] = 0
1257
1258 return params
1259
1261 '''Use testvalue tag text from each type to build test case the whalenotice message'''
1263
1264 params = testParams()
1265 bits = encode(params)
1266 r = decode(bits)
1267
1268
1269 self.failUnlessEqual(r['MessageID'],params['MessageID'])
1270 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
1271 self.failUnlessEqual(r['UserID'],params['UserID'])
1272 self.failUnlessEqual(r['Spare'],params['Spare'])
1273 self.failUnlessEqual(r['dac'],params['dac'])
1274 self.failUnlessEqual(r['fid'],params['fid'])
1275 self.failUnlessEqual(r['efid'],params['efid'])
1276 self.failUnlessEqual(r['numreports'],params['numreports'])
1277 self.failUnlessEqual(r['stationid1'],params['stationid1'])
1278 self.failUnlessEqual(r['time1_day'],params['time1_day'])
1279 self.failUnlessEqual(r['time1_hour'],params['time1_hour'])
1280 self.failUnlessEqual(r['time1_min'],params['time1_min'])
1281 self.failUnlessAlmostEqual(r['center1_longitude'],params['center1_longitude'],5)
1282 self.failUnlessAlmostEqual(r['center1_latitude'],params['center1_latitude'],5)
1283 self.failUnlessEqual(r['timetoexpire1'],params['timetoexpire1'])
1284 self.failUnlessEqual(r['radius1'],params['radius1'])
1285 self.failUnlessEqual(r['stationid2'],params['stationid2'])
1286 self.failUnlessEqual(r['time2_day'],params['time2_day'])
1287 self.failUnlessEqual(r['time2_hour'],params['time2_hour'])
1288 self.failUnlessEqual(r['time2_min'],params['time2_min'])
1289 self.failUnlessAlmostEqual(r['center2_longitude'],params['center2_longitude'],5)
1290 self.failUnlessAlmostEqual(r['center2_latitude'],params['center2_latitude'],5)
1291 self.failUnlessEqual(r['timetoexpire2'],params['timetoexpire2'])
1292 self.failUnlessEqual(r['radius2'],params['radius2'])
1293 self.failUnlessEqual(r['stationid3'],params['stationid3'])
1294 self.failUnlessEqual(r['time3_day'],params['time3_day'])
1295 self.failUnlessEqual(r['time3_hour'],params['time3_hour'])
1296 self.failUnlessEqual(r['time3_min'],params['time3_min'])
1297 self.failUnlessAlmostEqual(r['center3_longitude'],params['center3_longitude'],5)
1298 self.failUnlessAlmostEqual(r['center3_latitude'],params['center3_latitude'],5)
1299 self.failUnlessEqual(r['timetoexpire3'],params['timetoexpire3'])
1300 self.failUnlessEqual(r['radius3'],params['radius3'])
1301 self.failUnlessEqual(r['Spare2'],params['Spare2'])
1302
1304 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
1305 help='decode a "whalenotice" AIS message')
1306 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
1307 help='encode a "whalenotice" AIS message')
1308 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
1309 ,help='Field parameter value [default: %default]')
1310 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
1311 ,help='Field parameter value [default: %default]')
1312 parser.add_option('--numreports-field', dest='numreportsField',default=0,metavar='uint',type='int'
1313 ,help='Field parameter value [default: %default]')
1314 parser.add_option('--stationid1-field', dest='stationid1Field',default=0,metavar='uint',type='int'
1315 ,help='Field parameter value [default: %default]')
1316 parser.add_option('--time1_day-field', dest='time1_dayField',metavar='uint',type='int'
1317 ,help='Field parameter value [default: %default]')
1318 parser.add_option('--time1_hour-field', dest='time1_hourField',metavar='uint',type='int'
1319 ,help='Field parameter value [default: %default]')
1320 parser.add_option('--time1_min-field', dest='time1_minField',metavar='uint',type='int'
1321 ,help='Field parameter value [default: %default]')
1322 parser.add_option('--center1_longitude-field', dest='center1_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
1323 ,help='Field parameter value [default: %default]')
1324 parser.add_option('--center1_latitude-field', dest='center1_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
1325 ,help='Field parameter value [default: %default]')
1326 parser.add_option('--timetoexpire1-field', dest='timetoexpire1Field',default=65535,metavar='uint',type='int'
1327 ,help='Field parameter value [default: %default]')
1328 parser.add_option('--radius1-field', dest='radius1Field',default=65534,metavar='uint',type='int'
1329 ,help='Field parameter value [default: %default]')
1330 parser.add_option('--stationid2-field', dest='stationid2Field',default=0,metavar='uint',type='int'
1331 ,help='Field parameter value [default: %default]')
1332 parser.add_option('--time2_day-field', dest='time2_dayField',metavar='uint',type='int'
1333 ,help='Field parameter value [default: %default]')
1334 parser.add_option('--time2_hour-field', dest='time2_hourField',metavar='uint',type='int'
1335 ,help='Field parameter value [default: %default]')
1336 parser.add_option('--time2_min-field', dest='time2_minField',metavar='uint',type='int'
1337 ,help='Field parameter value [default: %default]')
1338 parser.add_option('--center2_longitude-field', dest='center2_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
1339 ,help='Field parameter value [default: %default]')
1340 parser.add_option('--center2_latitude-field', dest='center2_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
1341 ,help='Field parameter value [default: %default]')
1342 parser.add_option('--timetoexpire2-field', dest='timetoexpire2Field',default=65535,metavar='uint',type='int'
1343 ,help='Field parameter value [default: %default]')
1344 parser.add_option('--radius2-field', dest='radius2Field',default=65534,metavar='uint',type='int'
1345 ,help='Field parameter value [default: %default]')
1346 parser.add_option('--stationid3-field', dest='stationid3Field',default=0,metavar='uint',type='int'
1347 ,help='Field parameter value [default: %default]')
1348 parser.add_option('--time3_day-field', dest='time3_dayField',metavar='uint',type='int'
1349 ,help='Field parameter value [default: %default]')
1350 parser.add_option('--time3_hour-field', dest='time3_hourField',metavar='uint',type='int'
1351 ,help='Field parameter value [default: %default]')
1352 parser.add_option('--time3_min-field', dest='time3_minField',metavar='uint',type='int'
1353 ,help='Field parameter value [default: %default]')
1354 parser.add_option('--center3_longitude-field', dest='center3_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
1355 ,help='Field parameter value [default: %default]')
1356 parser.add_option('--center3_latitude-field', dest='center3_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
1357 ,help='Field parameter value [default: %default]')
1358 parser.add_option('--timetoexpire3-field', dest='timetoexpire3Field',default=65535,metavar='uint',type='int'
1359 ,help='Field parameter value [default: %default]')
1360 parser.add_option('--radius3-field', dest='radius3Field',default=65534,metavar='uint',type='int'
1361 ,help='Field parameter value [default: %default]')
1362
1363
1364 if __name__=='__main__':
1365
1366 from optparse import OptionParser
1367 parser = OptionParser(usage="%prog [options]",
1368 version="%prog "+__version__)
1369
1370 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
1371 help='run the documentation tests')
1372 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
1373 help='run the unit tests')
1374 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
1375 help='Make the test output verbose')
1376
1377
1378
1379 typeChoices = ('binary','nmeapayload','nmea')
1380 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
1381 ,default='nmeapayload'
1382 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]')
1383
1384
1385 outputChoices = ('std','html','csv','sql' , 'kml','kml-full')
1386 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
1387 ,default='std'
1388 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
1389
1390 parser.add_option('-o','--output',dest='outputFileName',default=None,
1391 help='Name of the python file to write [default: stdout]')
1392
1393 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
1394 choices=fieldList,
1395 help='Which fields to include in the output. Currently only for csv output [default: all]')
1396
1397 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
1398 help='Print the field name for csv')
1399
1400 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true',
1401 help='Print out an sql create command for the table.')
1402
1403 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true',
1404 help='Print a LaTeX table of the type')
1405
1406 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true',
1407 help='Print delimited table of the type (for Word table importing)')
1408 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t'
1409 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)')
1410
1411
1412 dbChoices = ('sqlite','postgres')
1413 parser.add_option('-D','--db-type',dest='dbType',default='postgres'
1414 ,choices=dbChoices,type='choice'
1415 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]')
1416
1417 addMsgOptions(parser)
1418
1419 (options,args) = parser.parse_args()
1420 success=True
1421
1422 if options.doctest:
1423 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
1424 sys.argv= [sys.argv[0]]
1425 if options.verbose: sys.argv.append('-v')
1426 import doctest
1427 numfail,numtests=doctest.testmod()
1428 if numfail==0: print 'ok'
1429 else:
1430 print 'FAILED'
1431 success=False
1432
1433 if not success: sys.exit('Something Failed')
1434 del success
1435
1436 if options.unittest:
1437 sys.argv = [sys.argv[0]]
1438 if options.verbose: sys.argv.append('-v')
1439 unittest.main()
1440
1441 outfile = sys.stdout
1442 if None!=options.outputFileName:
1443 outfile = file(options.outputFileName,'w')
1444
1445
1446 if options.doEncode:
1447
1448 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
1449 if None==options.UserIDField: parser.error("missing value for UserIDField")
1450 if None==options.numreportsField: parser.error("missing value for numreportsField")
1451 if None==options.stationid1Field: parser.error("missing value for stationid1Field")
1452 if None==options.time1_dayField: parser.error("missing value for time1_dayField")
1453 if None==options.time1_hourField: parser.error("missing value for time1_hourField")
1454 if None==options.time1_minField: parser.error("missing value for time1_minField")
1455 if None==options.center1_longitudeField: parser.error("missing value for center1_longitudeField")
1456 if None==options.center1_latitudeField: parser.error("missing value for center1_latitudeField")
1457 if None==options.timetoexpire1Field: parser.error("missing value for timetoexpire1Field")
1458 if None==options.radius1Field: parser.error("missing value for radius1Field")
1459 if None==options.stationid2Field: parser.error("missing value for stationid2Field")
1460 if None==options.time2_dayField: parser.error("missing value for time2_dayField")
1461 if None==options.time2_hourField: parser.error("missing value for time2_hourField")
1462 if None==options.time2_minField: parser.error("missing value for time2_minField")
1463 if None==options.center2_longitudeField: parser.error("missing value for center2_longitudeField")
1464 if None==options.center2_latitudeField: parser.error("missing value for center2_latitudeField")
1465 if None==options.timetoexpire2Field: parser.error("missing value for timetoexpire2Field")
1466 if None==options.radius2Field: parser.error("missing value for radius2Field")
1467 if None==options.stationid3Field: parser.error("missing value for stationid3Field")
1468 if None==options.time3_dayField: parser.error("missing value for time3_dayField")
1469 if None==options.time3_hourField: parser.error("missing value for time3_hourField")
1470 if None==options.time3_minField: parser.error("missing value for time3_minField")
1471 if None==options.center3_longitudeField: parser.error("missing value for center3_longitudeField")
1472 if None==options.center3_latitudeField: parser.error("missing value for center3_latitudeField")
1473 if None==options.timetoexpire3Field: parser.error("missing value for timetoexpire3Field")
1474 if None==options.radius3Field: parser.error("missing value for radius3Field")
1475 msgDict={
1476 'MessageID': '8',
1477 'RepeatIndicator': options.RepeatIndicatorField,
1478 'UserID': options.UserIDField,
1479 'Spare': '0',
1480 'dac': '366',
1481 'fid': '63',
1482 'efid': '1',
1483 'numreports': options.numreportsField,
1484 'stationid1': options.stationid1Field,
1485 'time1_day': options.time1_dayField,
1486 'time1_hour': options.time1_hourField,
1487 'time1_min': options.time1_minField,
1488 'center1_longitude': options.center1_longitudeField,
1489 'center1_latitude': options.center1_latitudeField,
1490 'timetoexpire1': options.timetoexpire1Field,
1491 'radius1': options.radius1Field,
1492 'stationid2': options.stationid2Field,
1493 'time2_day': options.time2_dayField,
1494 'time2_hour': options.time2_hourField,
1495 'time2_min': options.time2_minField,
1496 'center2_longitude': options.center2_longitudeField,
1497 'center2_latitude': options.center2_latitudeField,
1498 'timetoexpire2': options.timetoexpire2Field,
1499 'radius2': options.radius2Field,
1500 'stationid3': options.stationid3Field,
1501 'time3_day': options.time3_dayField,
1502 'time3_hour': options.time3_hourField,
1503 'time3_min': options.time3_minField,
1504 'center3_longitude': options.center3_longitudeField,
1505 'center3_latitude': options.center3_latitudeField,
1506 'timetoexpire3': options.timetoexpire3Field,
1507 'radius3': options.radius3Field,
1508 'Spare2': '0',
1509 }
1510
1511 bits = encode(msgDict)
1512 if 'binary'==options.ioType: print str(bits)
1513 elif 'nmeapayload'==options.ioType:
1514
1515 print "bitLen",len(bits)
1516 bitLen=len(bits)
1517 if bitLen%6!=0:
1518 bits = bits + BitVector(size=(6 - (bitLen%6)))
1519 print "result:",binary.bitvectoais6(bits)[0]
1520
1521
1522
1523 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
1524 else: sys.exit('ERROR: unknown ioType. Help!')
1525
1526
1527 if options.sqlCreate:
1528 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType)
1529
1530 if options.latexDefinitionTable:
1531 latexDefinitionTable(outfile)
1532
1533
1534 if options.textDefinitionTable:
1535 textDefinitionTable(outfile,options.delimTextDefinitionTable)
1536
1537 if options.printCsvfieldList:
1538
1539 if None == options.fieldList: options.fieldList = fieldList
1540 import StringIO
1541 buf = StringIO.StringIO()
1542 for field in options.fieldList:
1543 buf.write(field+',')
1544 result = buf.getvalue()
1545 if result[-1] == ',': print result[:-1]
1546 else: print result
1547
1548 if options.doDecode:
1549 if len(args)==0: args = sys.stdin
1550 for msg in args:
1551 bv = None
1552
1553 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'):
1554
1555
1556 bv = binary.ais6tobitvec(msg.split(',')[5])
1557 else:
1558
1559 binaryMsg=True
1560 for c in msg:
1561 if c not in ('0','1'):
1562 binaryMsg=False
1563 break
1564 if binaryMsg:
1565 bv = BitVector(bitstring=msg)
1566 else:
1567 bv = binary.ais6tobitvec(msg)
1568
1569 printFields(decode(bv)
1570 ,out=outfile
1571 ,format=options.outputType
1572 ,fieldList=options.fieldList
1573 ,dbType=options.dbType
1574 )
1575