1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2007-11-07 $'.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 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None
932 ,addCoastGuardFields=True
933 ,dbType='postgres'
934 ):
935 '''
936 Return the SQL CREATE command for this message type
937 @param outfile: file like object to print to.
938 @param fields: which fields to put in the create. Defaults to all.
939 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
940 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
941 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
942 @type addCoastGuardFields: bool
943 @return: sql create string
944 @rtype: str
945
946 @see: sqlCreate
947 '''
948
949 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
950
951 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
952 '''
953 Return the sqlhelp object to create the table.
954
955 @param fields: which fields to put in the create. Defaults to all.
956 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
957 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
958 @type addCoastGuardFields: bool
959 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
960 @return: An object that can be used to generate a return
961 @rtype: sqlhelp.create
962 '''
963 if None == fields: fields = fieldList
964 import sqlhelp
965 c = sqlhelp.create('whalenotice',dbType=dbType)
966 c.addPrimaryKey()
967 if 'MessageID' in fields: c.addInt ('MessageID')
968 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator')
969 if 'UserID' in fields: c.addInt ('UserID')
970 if 'Spare' in fields: c.addInt ('Spare')
971 if 'dac' in fields: c.addInt ('dac')
972 if 'fid' in fields: c.addInt ('fid')
973 if 'efid' in fields: c.addInt ('efid')
974 if 'numreports' in fields: c.addInt ('numreports')
975 if 'stationid1' in fields: c.addInt ('stationid1')
976 if 'time1_day' in fields: c.addInt ('time1_day')
977 if 'time1_hour' in fields: c.addInt ('time1_hour')
978 if 'time1_min' in fields: c.addInt ('time1_min')
979 if dbType != 'postgres':
980 if 'center1_longitude' in fields: c.addDecimal('center1_longitude',8,5)
981 if dbType != 'postgres':
982 if 'center1_latitude' in fields: c.addDecimal('center1_latitude',8,5)
983 if 'timetoexpire1' in fields: c.addInt ('timetoexpire1')
984 if 'radius1' in fields: c.addInt ('radius1')
985 if 'stationid2' in fields: c.addInt ('stationid2')
986 if 'time2_day' in fields: c.addInt ('time2_day')
987 if 'time2_hour' in fields: c.addInt ('time2_hour')
988 if 'time2_min' in fields: c.addInt ('time2_min')
989 if dbType != 'postgres':
990 if 'center2_longitude' in fields: c.addDecimal('center2_longitude',8,5)
991 if dbType != 'postgres':
992 if 'center2_latitude' in fields: c.addDecimal('center2_latitude',8,5)
993 if 'timetoexpire2' in fields: c.addInt ('timetoexpire2')
994 if 'radius2' in fields: c.addInt ('radius2')
995 if 'stationid3' in fields: c.addInt ('stationid3')
996 if 'time3_day' in fields: c.addInt ('time3_day')
997 if 'time3_hour' in fields: c.addInt ('time3_hour')
998 if 'time3_min' in fields: c.addInt ('time3_min')
999 if dbType != 'postgres':
1000 if 'center3_longitude' in fields: c.addDecimal('center3_longitude',8,5)
1001 if dbType != 'postgres':
1002 if 'center3_latitude' in fields: c.addDecimal('center3_latitude',8,5)
1003 if 'timetoexpire3' in fields: c.addInt ('timetoexpire3')
1004 if 'radius3' in fields: c.addInt ('radius3')
1005 if 'Spare2' in fields: c.addInt ('Spare2')
1006
1007 if addCoastGuardFields:
1008
1009
1010
1011
1012
1013 c.addVarChar('cg_r',15)
1014 c.addInt('cg_sec')
1015
1016 c.addTimestamp('cg_timestamp')
1017
1018 if dbType == 'postgres':
1019
1020
1021 c.addPostGIS('center1','POINT',2,SRID=4326);
1022
1023
1024 c.addPostGIS('center2','POINT',2,SRID=4326);
1025
1026
1027 c.addPostGIS('center3','POINT',2,SRID=4326);
1028
1029 return c
1030
1031 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
1032 '''
1033 Return the SQL INSERT command for this message type
1034 @param params: dictionary of values keyed by field name
1035 @param outfile: file like object to print to.
1036 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
1037 @return: sql create string
1038 @rtype: str
1039
1040 @see: sqlCreate
1041 '''
1042 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
1043
1044
1045 -def sqlInsert(params,extraParams=None,dbType='postgres'):
1046 '''
1047 Give the SQL INSERT statement
1048 @param params: dict keyed by field name of values
1049 @param extraParams: any extra fields that you have created beyond the normal ais message fields
1050 @rtype: sqlhelp.insert
1051 @return: insert class instance
1052 @todo: allow optional type checking of params?
1053 @warning: this will take invalid keys happily and do what???
1054 '''
1055 import sqlhelp
1056 i = sqlhelp.insert('whalenotice',dbType=dbType)
1057
1058 if dbType=='postgres':
1059 finished = []
1060 for key in params:
1061 if key in finished:
1062 continue
1063
1064 if key not in toPgFields and key not in fromPgFields:
1065 if type(params[key])==Decimal: i.add(key,float(params[key]))
1066 else: i.add(key,params[key])
1067 else:
1068 if key in fromPgFields:
1069 val = params[key]
1070
1071 i.addPostGIS(key,val)
1072 finished.append(key)
1073 else:
1074
1075 pgName = toPgFields[key]
1076
1077 valStr=pgTypes[pgName]+'('
1078 vals = []
1079 for nonPgKey in fromPgFields[pgName]:
1080 vals.append(str(params[nonPgKey]))
1081 finished.append(nonPgKey)
1082 valStr+=' '.join(vals)+')'
1083 i.addPostGIS(pgName,valStr)
1084 else:
1085 for key in params:
1086 if type(params[key])==Decimal: i.add(key,float(params[key]))
1087 else: i.add(key,params[key])
1088
1089 if None != extraParams:
1090 for key in extraParams:
1091 i.add(key,extraParams[key])
1092
1093 return i
1094
1095
1096
1097
1098
1101 '''
1102 Return the LaTeX definition table for this message type
1103 @param outfile: file like object to print to.
1104 @type outfile: file obj
1105 @return: LaTeX table string via the outfile
1106 @rtype: str
1107
1108 '''
1109 o = outfile
1110
1111 o.write('''
1112 \\begin{table}%[htb]
1113 \\centering
1114 \\begin{tabular}{|l|c|l|}
1115 \\hline
1116 Parameter & Number of bits & Description
1117 \\\\ \\hline\\hline
1118 MessageID & 6 & AIS message number. Must be 8 \\\\ \hline
1119 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline
1120 UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline
1121 Spare & 2 & Reserved for definition by a regional authority. \\\\ \hline
1122 dac & 10 & Designated Area Code - 366 for the United States \\\\ \hline
1123 fid & 6 & Functional IDentifier - 63 for the Whale Notice \\\\ \hline
1124 efid & 12 & Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type) \\\\ \hline
1125 numreports & 2 & Number of detection reports filled out in this message \\\\ \hline
1126 stationid1 & 8 & Identifier of the station that recorded the whale. Usually a number. \\\\ \hline
1127 time1\_day & 5 & Time of most recent whale detection. UTC day of the month 1..31 \\\\ \hline
1128 time1\_hour & 5 & Time of most recent whale detection. UTC hours 0..23 \\\\ \hline
1129 time1\_min & 6 & Time of most recent whale detection. UTC minutes \\\\ \hline
1130 center1\_longitude & 28 & Center of the detection zone. East West location \\\\ \hline
1131 center1\_latitude & 27 & Center of the detection zone. North South location \\\\ \hline
1132 timetoexpire1 & 16 & Seconds from the detection time until the notice expires \\\\ \hline
1133 radius1 & 16 & Distance from center of detection zone (lat/lon above) \\\\ \hline
1134 stationid2 & 8 & Identifier of the station that recorded the whale. Usually a number. \\\\ \hline
1135 time2\_day & 5 & Time of most recent whale detection. UTC day of the month 1..31 \\\\ \hline
1136 time2\_hour & 5 & Time of most recent whale detection. UTC hours 0..23 \\\\ \hline
1137 time2\_min & 6 & Time of most recent whale detection. UTC minutes \\\\ \hline
1138 center2\_longitude & 28 & Center of the detection zone. East West location \\\\ \hline
1139 center2\_latitude & 27 & Center of the detection zone. North South location \\\\ \hline
1140 timetoexpire2 & 16 & Seconds from the detection time until the notice expires \\\\ \hline
1141 radius2 & 16 & Distance from center of detection zone (lat/lon above) \\\\ \hline
1142 stationid3 & 8 & Identifier of the station that recorded the whale. Usually a number. \\\\ \hline
1143 time3\_day & 5 & Time of most recent whale detection. UTC day of the month 1..31 \\\\ \hline
1144 time3\_hour & 5 & Time of most recent whale detection. UTC hours 0..23 \\\\ \hline
1145 time3\_min & 6 & Time of most recent whale detection. UTC minutes \\\\ \hline
1146 center3\_longitude & 28 & Center of the detection zone. East West location \\\\ \hline
1147 center3\_latitude & 27 & Center of the detection zone. North South location \\\\ \hline
1148 timetoexpire3 & 16 & Seconds from the detection time until the notice expires \\\\ \hline
1149 radius3 & 16 & Distance from center of detection zone (lat/lon above) \\\\ \hline
1150 Spare2 & 21 & Not used. Should be set to zero.\\\\ \\hline \\hline
1151 Total bits & 424 & Appears to take 2 slots \\\\ \\hline
1152 \\end{tabular}
1153 \\caption{AIS message number 8: Endangered whale notification binary message}
1154 \\label{tab:whalenotice}
1155 \\end{table}
1156 ''')
1157
1158
1159
1160
1161
1162 -def textDefinitionTable(outfile=sys.stdout
1163 ,delim='\t'
1164 ):
1165 '''
1166 Return the text definition table for this message type
1167 @param outfile: file like object to print to.
1168 @type outfile: file obj
1169 @return: text table string via the outfile
1170 @rtype: str
1171
1172 '''
1173 o = outfile
1174 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description
1175 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 8
1176 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated
1177 UserID'''+delim+'''30'''+delim+'''Unique ship identification number (MMSI)
1178 Spare'''+delim+'''2'''+delim+'''Reserved for definition by a regional authority.
1179 dac'''+delim+'''10'''+delim+'''Designated Area Code - 366 for the United States
1180 fid'''+delim+'''6'''+delim+'''Functional IDentifier - 63 for the Whale Notice
1181 efid'''+delim+'''12'''+delim+'''Extended Functional IDentifier. 1 for the Whale Notice (dac+fid+efid defines the exact message type)
1182 numreports'''+delim+'''2'''+delim+'''Number of detection reports filled out in this message
1183 stationid1'''+delim+'''8'''+delim+'''Identifier of the station that recorded the whale. Usually a number.
1184 time1_day'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC day of the month 1..31
1185 time1_hour'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC hours 0..23
1186 time1_min'''+delim+'''6'''+delim+'''Time of most recent whale detection. UTC minutes
1187 center1_longitude'''+delim+'''28'''+delim+'''Center of the detection zone. East West location
1188 center1_latitude'''+delim+'''27'''+delim+'''Center of the detection zone. North South location
1189 timetoexpire1'''+delim+'''16'''+delim+'''Seconds from the detection time until the notice expires
1190 radius1'''+delim+'''16'''+delim+'''Distance from center of detection zone (lat/lon above)
1191 stationid2'''+delim+'''8'''+delim+'''Identifier of the station that recorded the whale. Usually a number.
1192 time2_day'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC day of the month 1..31
1193 time2_hour'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC hours 0..23
1194 time2_min'''+delim+'''6'''+delim+'''Time of most recent whale detection. UTC minutes
1195 center2_longitude'''+delim+'''28'''+delim+'''Center of the detection zone. East West location
1196 center2_latitude'''+delim+'''27'''+delim+'''Center of the detection zone. North South location
1197 timetoexpire2'''+delim+'''16'''+delim+'''Seconds from the detection time until the notice expires
1198 radius2'''+delim+'''16'''+delim+'''Distance from center of detection zone (lat/lon above)
1199 stationid3'''+delim+'''8'''+delim+'''Identifier of the station that recorded the whale. Usually a number.
1200 time3_day'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC day of the month 1..31
1201 time3_hour'''+delim+'''5'''+delim+'''Time of most recent whale detection. UTC hours 0..23
1202 time3_min'''+delim+'''6'''+delim+'''Time of most recent whale detection. UTC minutes
1203 center3_longitude'''+delim+'''28'''+delim+'''Center of the detection zone. East West location
1204 center3_latitude'''+delim+'''27'''+delim+'''Center of the detection zone. North South location
1205 timetoexpire3'''+delim+'''16'''+delim+'''Seconds from the detection time until the notice expires
1206 radius3'''+delim+'''16'''+delim+'''Distance from center of detection zone (lat/lon above)
1207 Spare2'''+delim+'''21'''+delim+'''Not used. Should be set to zero.
1208 Total bits'''+delim+'''424'''+delim+'''Appears to take 2 slots''')
1209
1210
1211
1212
1213
1214 import unittest
1216 '''Return a params file base on the testvalue tags.
1217 @rtype: dict
1218 @return: params based on testvalue tags
1219 '''
1220 params = {}
1221 params['MessageID'] = 8
1222 params['RepeatIndicator'] = 1
1223 params['UserID'] = 1193046
1224 params['Spare'] = 0
1225 params['dac'] = 366
1226 params['fid'] = 63
1227 params['efid'] = 1
1228 params['numreports'] = 3
1229 params['stationid1'] = 76
1230 params['time1_day'] = 28
1231 params['time1_hour'] = 23
1232 params['time1_min'] = 45
1233 params['center1_longitude'] = Decimal('-122.16328055555556')
1234 params['center1_latitude'] = Decimal('37.424458333333334')
1235 params['timetoexpire1'] = 1
1236 params['radius1'] = 5000
1237 params['stationid2'] = 76
1238 params['time2_day'] = 28
1239 params['time2_hour'] = 23
1240 params['time2_min'] = 45
1241 params['center2_longitude'] = Decimal('-122.16328055555556')
1242 params['center2_latitude'] = Decimal('37.424458333333334')
1243 params['timetoexpire2'] = 1
1244 params['radius2'] = 5000
1245 params['stationid3'] = 76
1246 params['time3_day'] = 28
1247 params['time3_hour'] = 23
1248 params['time3_min'] = 45
1249 params['center3_longitude'] = Decimal('-122.16328055555556')
1250 params['center3_latitude'] = Decimal('37.424458333333334')
1251 params['timetoexpire3'] = 1
1252 params['radius3'] = 5000
1253 params['Spare2'] = 0
1254
1255 return params
1256
1258 '''Use testvalue tag text from each type to build test case the whalenotice message'''
1260
1261 params = testParams()
1262 bits = encode(params)
1263 r = decode(bits)
1264
1265
1266 self.failUnlessEqual(r['MessageID'],params['MessageID'])
1267 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
1268 self.failUnlessEqual(r['UserID'],params['UserID'])
1269 self.failUnlessEqual(r['Spare'],params['Spare'])
1270 self.failUnlessEqual(r['dac'],params['dac'])
1271 self.failUnlessEqual(r['fid'],params['fid'])
1272 self.failUnlessEqual(r['efid'],params['efid'])
1273 self.failUnlessEqual(r['numreports'],params['numreports'])
1274 self.failUnlessEqual(r['stationid1'],params['stationid1'])
1275 self.failUnlessEqual(r['time1_day'],params['time1_day'])
1276 self.failUnlessEqual(r['time1_hour'],params['time1_hour'])
1277 self.failUnlessEqual(r['time1_min'],params['time1_min'])
1278 self.failUnlessAlmostEqual(r['center1_longitude'],params['center1_longitude'],5)
1279 self.failUnlessAlmostEqual(r['center1_latitude'],params['center1_latitude'],5)
1280 self.failUnlessEqual(r['timetoexpire1'],params['timetoexpire1'])
1281 self.failUnlessEqual(r['radius1'],params['radius1'])
1282 self.failUnlessEqual(r['stationid2'],params['stationid2'])
1283 self.failUnlessEqual(r['time2_day'],params['time2_day'])
1284 self.failUnlessEqual(r['time2_hour'],params['time2_hour'])
1285 self.failUnlessEqual(r['time2_min'],params['time2_min'])
1286 self.failUnlessAlmostEqual(r['center2_longitude'],params['center2_longitude'],5)
1287 self.failUnlessAlmostEqual(r['center2_latitude'],params['center2_latitude'],5)
1288 self.failUnlessEqual(r['timetoexpire2'],params['timetoexpire2'])
1289 self.failUnlessEqual(r['radius2'],params['radius2'])
1290 self.failUnlessEqual(r['stationid3'],params['stationid3'])
1291 self.failUnlessEqual(r['time3_day'],params['time3_day'])
1292 self.failUnlessEqual(r['time3_hour'],params['time3_hour'])
1293 self.failUnlessEqual(r['time3_min'],params['time3_min'])
1294 self.failUnlessAlmostEqual(r['center3_longitude'],params['center3_longitude'],5)
1295 self.failUnlessAlmostEqual(r['center3_latitude'],params['center3_latitude'],5)
1296 self.failUnlessEqual(r['timetoexpire3'],params['timetoexpire3'])
1297 self.failUnlessEqual(r['radius3'],params['radius3'])
1298 self.failUnlessEqual(r['Spare2'],params['Spare2'])
1299
1301 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
1302 help='decode a "whalenotice" AIS message')
1303 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
1304 help='encode a "whalenotice" AIS message')
1305 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
1306 ,help='Field parameter value [default: %default]')
1307 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
1308 ,help='Field parameter value [default: %default]')
1309 parser.add_option('--numreports-field', dest='numreportsField',default=0,metavar='uint',type='int'
1310 ,help='Field parameter value [default: %default]')
1311 parser.add_option('--stationid1-field', dest='stationid1Field',default=0,metavar='uint',type='int'
1312 ,help='Field parameter value [default: %default]')
1313 parser.add_option('--time1_day-field', dest='time1_dayField',metavar='uint',type='int'
1314 ,help='Field parameter value [default: %default]')
1315 parser.add_option('--time1_hour-field', dest='time1_hourField',metavar='uint',type='int'
1316 ,help='Field parameter value [default: %default]')
1317 parser.add_option('--time1_min-field', dest='time1_minField',metavar='uint',type='int'
1318 ,help='Field parameter value [default: %default]')
1319 parser.add_option('--center1_longitude-field', dest='center1_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
1320 ,help='Field parameter value [default: %default]')
1321 parser.add_option('--center1_latitude-field', dest='center1_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
1322 ,help='Field parameter value [default: %default]')
1323 parser.add_option('--timetoexpire1-field', dest='timetoexpire1Field',default=65535,metavar='uint',type='int'
1324 ,help='Field parameter value [default: %default]')
1325 parser.add_option('--radius1-field', dest='radius1Field',default=65534,metavar='uint',type='int'
1326 ,help='Field parameter value [default: %default]')
1327 parser.add_option('--stationid2-field', dest='stationid2Field',default=0,metavar='uint',type='int'
1328 ,help='Field parameter value [default: %default]')
1329 parser.add_option('--time2_day-field', dest='time2_dayField',metavar='uint',type='int'
1330 ,help='Field parameter value [default: %default]')
1331 parser.add_option('--time2_hour-field', dest='time2_hourField',metavar='uint',type='int'
1332 ,help='Field parameter value [default: %default]')
1333 parser.add_option('--time2_min-field', dest='time2_minField',metavar='uint',type='int'
1334 ,help='Field parameter value [default: %default]')
1335 parser.add_option('--center2_longitude-field', dest='center2_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
1336 ,help='Field parameter value [default: %default]')
1337 parser.add_option('--center2_latitude-field', dest='center2_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
1338 ,help='Field parameter value [default: %default]')
1339 parser.add_option('--timetoexpire2-field', dest='timetoexpire2Field',default=65535,metavar='uint',type='int'
1340 ,help='Field parameter value [default: %default]')
1341 parser.add_option('--radius2-field', dest='radius2Field',default=65534,metavar='uint',type='int'
1342 ,help='Field parameter value [default: %default]')
1343 parser.add_option('--stationid3-field', dest='stationid3Field',default=0,metavar='uint',type='int'
1344 ,help='Field parameter value [default: %default]')
1345 parser.add_option('--time3_day-field', dest='time3_dayField',metavar='uint',type='int'
1346 ,help='Field parameter value [default: %default]')
1347 parser.add_option('--time3_hour-field', dest='time3_hourField',metavar='uint',type='int'
1348 ,help='Field parameter value [default: %default]')
1349 parser.add_option('--time3_min-field', dest='time3_minField',metavar='uint',type='int'
1350 ,help='Field parameter value [default: %default]')
1351 parser.add_option('--center3_longitude-field', dest='center3_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
1352 ,help='Field parameter value [default: %default]')
1353 parser.add_option('--center3_latitude-field', dest='center3_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
1354 ,help='Field parameter value [default: %default]')
1355 parser.add_option('--timetoexpire3-field', dest='timetoexpire3Field',default=65535,metavar='uint',type='int'
1356 ,help='Field parameter value [default: %default]')
1357 parser.add_option('--radius3-field', dest='radius3Field',default=65534,metavar='uint',type='int'
1358 ,help='Field parameter value [default: %default]')
1359
1360
1361 if __name__=='__main__':
1362
1363 from optparse import OptionParser
1364 parser = OptionParser(usage="%prog [options]",
1365 version="%prog "+__version__)
1366
1367 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
1368 help='run the documentation tests')
1369 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
1370 help='run the unit tests')
1371 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
1372 help='Make the test output verbose')
1373
1374
1375
1376 typeChoices = ('binary','nmeapayload','nmea')
1377 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
1378 ,default='nmeapayload'
1379 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]')
1380
1381
1382 outputChoices = ('std','html','csv','sql' , 'kml','kml-full')
1383 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
1384 ,default='std'
1385 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
1386
1387 parser.add_option('-o','--output',dest='outputFileName',default=None,
1388 help='Name of the python file to write [default: stdout]')
1389
1390 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
1391 choices=fieldList,
1392 help='Which fields to include in the output. Currently only for csv output [default: all]')
1393
1394 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
1395 help='Print the field name for csv')
1396
1397 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true',
1398 help='Print out an sql create command for the table.')
1399
1400 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true',
1401 help='Print a LaTeX table of the type')
1402
1403 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true',
1404 help='Print delimited table of the type (for Word table importing)')
1405 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t'
1406 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)')
1407
1408
1409 dbChoices = ('sqlite','postgres')
1410 parser.add_option('-D','--db-type',dest='dbType',default='postgres'
1411 ,choices=dbChoices,type='choice'
1412 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]')
1413
1414 addMsgOptions(parser)
1415
1416 (options,args) = parser.parse_args()
1417 success=True
1418
1419 if options.doctest:
1420 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
1421 sys.argv= [sys.argv[0]]
1422 if options.verbose: sys.argv.append('-v')
1423 import doctest
1424 numfail,numtests=doctest.testmod()
1425 if numfail==0: print 'ok'
1426 else:
1427 print 'FAILED'
1428 success=False
1429
1430 if not success: sys.exit('Something Failed')
1431 del success
1432
1433 if options.unittest:
1434 sys.argv = [sys.argv[0]]
1435 if options.verbose: sys.argv.append('-v')
1436 unittest.main()
1437
1438 outfile = sys.stdout
1439 if None!=options.outputFileName:
1440 outfile = file(options.outputFileName,'w')
1441
1442
1443 if options.doEncode:
1444
1445 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
1446 if None==options.UserIDField: parser.error("missing value for UserIDField")
1447 if None==options.numreportsField: parser.error("missing value for numreportsField")
1448 if None==options.stationid1Field: parser.error("missing value for stationid1Field")
1449 if None==options.time1_dayField: parser.error("missing value for time1_dayField")
1450 if None==options.time1_hourField: parser.error("missing value for time1_hourField")
1451 if None==options.time1_minField: parser.error("missing value for time1_minField")
1452 if None==options.center1_longitudeField: parser.error("missing value for center1_longitudeField")
1453 if None==options.center1_latitudeField: parser.error("missing value for center1_latitudeField")
1454 if None==options.timetoexpire1Field: parser.error("missing value for timetoexpire1Field")
1455 if None==options.radius1Field: parser.error("missing value for radius1Field")
1456 if None==options.stationid2Field: parser.error("missing value for stationid2Field")
1457 if None==options.time2_dayField: parser.error("missing value for time2_dayField")
1458 if None==options.time2_hourField: parser.error("missing value for time2_hourField")
1459 if None==options.time2_minField: parser.error("missing value for time2_minField")
1460 if None==options.center2_longitudeField: parser.error("missing value for center2_longitudeField")
1461 if None==options.center2_latitudeField: parser.error("missing value for center2_latitudeField")
1462 if None==options.timetoexpire2Field: parser.error("missing value for timetoexpire2Field")
1463 if None==options.radius2Field: parser.error("missing value for radius2Field")
1464 if None==options.stationid3Field: parser.error("missing value for stationid3Field")
1465 if None==options.time3_dayField: parser.error("missing value for time3_dayField")
1466 if None==options.time3_hourField: parser.error("missing value for time3_hourField")
1467 if None==options.time3_minField: parser.error("missing value for time3_minField")
1468 if None==options.center3_longitudeField: parser.error("missing value for center3_longitudeField")
1469 if None==options.center3_latitudeField: parser.error("missing value for center3_latitudeField")
1470 if None==options.timetoexpire3Field: parser.error("missing value for timetoexpire3Field")
1471 if None==options.radius3Field: parser.error("missing value for radius3Field")
1472 msgDict={
1473 'MessageID': '8',
1474 'RepeatIndicator': options.RepeatIndicatorField,
1475 'UserID': options.UserIDField,
1476 'Spare': '0',
1477 'dac': '366',
1478 'fid': '63',
1479 'efid': '1',
1480 'numreports': options.numreportsField,
1481 'stationid1': options.stationid1Field,
1482 'time1_day': options.time1_dayField,
1483 'time1_hour': options.time1_hourField,
1484 'time1_min': options.time1_minField,
1485 'center1_longitude': options.center1_longitudeField,
1486 'center1_latitude': options.center1_latitudeField,
1487 'timetoexpire1': options.timetoexpire1Field,
1488 'radius1': options.radius1Field,
1489 'stationid2': options.stationid2Field,
1490 'time2_day': options.time2_dayField,
1491 'time2_hour': options.time2_hourField,
1492 'time2_min': options.time2_minField,
1493 'center2_longitude': options.center2_longitudeField,
1494 'center2_latitude': options.center2_latitudeField,
1495 'timetoexpire2': options.timetoexpire2Field,
1496 'radius2': options.radius2Field,
1497 'stationid3': options.stationid3Field,
1498 'time3_day': options.time3_dayField,
1499 'time3_hour': options.time3_hourField,
1500 'time3_min': options.time3_minField,
1501 'center3_longitude': options.center3_longitudeField,
1502 'center3_latitude': options.center3_latitudeField,
1503 'timetoexpire3': options.timetoexpire3Field,
1504 'radius3': options.radius3Field,
1505 'Spare2': '0',
1506 }
1507
1508 bits = encode(msgDict)
1509 if 'binary'==options.ioType: print str(bits)
1510 elif 'nmeapayload'==options.ioType:
1511
1512 print "bitLen",len(bits)
1513 bitLen=len(bits)
1514 if bitLen%6!=0:
1515 bits = bits + BitVector(size=(6 - (bitLen%6)))
1516 print "result:",binary.bitvectoais6(bits)[0]
1517
1518
1519
1520 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
1521 else: sys.exit('ERROR: unknown ioType. Help!')
1522
1523
1524 if options.sqlCreate:
1525 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType)
1526
1527 if options.latexDefinitionTable:
1528 latexDefinitionTable(outfile)
1529
1530
1531 if options.textDefinitionTable:
1532 textDefinitionTable(outfile,options.delimTextDefinitionTable)
1533
1534 if options.printCsvfieldList:
1535
1536 if None == options.fieldList: options.fieldList = fieldList
1537 import StringIO
1538 buf = StringIO.StringIO()
1539 for field in options.fieldList:
1540 buf.write(field+',')
1541 result = buf.getvalue()
1542 if result[-1] == ',': print result[:-1]
1543 else: print result
1544
1545 if options.doDecode:
1546 if len(args)==0: args = sys.stdin
1547 for msg in args:
1548 bv = None
1549
1550 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'):
1551
1552
1553 bv = binary.ais6tobitvec(msg.split(',')[5])
1554 else:
1555
1556 binaryMsg=True
1557 for c in msg:
1558 if c not in ('0','1'):
1559 binaryMsg=False
1560 break
1561 if binaryMsg:
1562 bv = BitVector(bitstring=msg)
1563 else:
1564 bv = binary.ais6tobitvec(msg)
1565
1566 printFields(decode(bv)
1567 ,out=outfile
1568 ,format=options.outputType
1569 ,fieldList=options.fieldList
1570 ,dbType=options.dbType
1571 )
1572