Package aisutils :: Module uscg
[hide private]
[frames] | no frames]

Source Code for Module aisutils.uscg

  1  #!/usr/bin/env python 
  2  __version__ = '$Revision: 2275 $'.split()[1] 
  3  __date__ = '$Date: 2006-07-10 16:22:35 -0400 (Mon, 10 Jul 2006) $'.split()[1] 
  4  __author__ = 'Kurt Schwehr' 
  5   
  6  __doc__ = ''' 
  7  Connect to a socket and forward what is received to another port. 
  8  Filter to a list of AIS receivers/basestations. 
  9   
 10  @author: '''+__author__+''' 
 11  @version: ''' + __version__ +''' 
 12  @copyright: 2006 
 13  @var __date__: Date of last svn commit 
 14  @undocumented: __version__ __author__ __doc__ myparser 
 15  @status: under development 
 16  @license: GPL v2 
 17  @since: Jan 2008 
 18  ''' 
 19   
 20  import datetime 
 21  import unittest 
 22  import sys 
 23  import ais.sqlhelp # for sec2timestamp 
 24   
25 -class UscgNmea:
26 - def __init__(self,nmeaStr=None):
27 ''' 28 Fields: 29 - rssi ('s'): relative signal strength indicator 30 - signalStrength ('d') - signal strendth in dBm 31 - timeOfArrival ('T') - time of arrive from receiver - seconds within the minute 32 - slotNumber ('S') - Receive slot number 33 - station ('r' or 'b') - station name or id that received the message 34 - stationTypeCode - first letter of the station name indicating 'b'asestation or 'r'eceive only (I think) 35 - cg_sec - receive time of the message from the logging software. Unix UTC second timestamp 36 - timestamp - python datetime object in UTC derived from the cg_sec 37 38 @todo: parse the other fields? 39 40 @see: Maritime navigation and radiocommunication equipment and 41 systems - Digital interfaces - Part 100: Single talker 42 and multiple listeners - Extra requirements to IEC 43 61162-1 for the UAIS. (80_330e_PAS) Draft... 44 45 ''' 46 if None!=nmeaStr: 47 #if len(nmeaStr)<6: 48 # # FIX: throw exception 49 # sys.stderr.write('Not a AIVDM... too short\n') 50 51 fields = nmeaStr.split(',') 52 self.cg_sec=float(fields[-1]) 53 self.timestamp = datetime.datetime.utcfromtimestamp(self.cg_sec) 54 self.sqlTimestampStr = ais.sqlhelp.sec2timestamp(self.cg_sec) 55 # See 80_330e_PAS 56 # 57 self.nmeaType=fields[0][1:] 58 self.totalSentences = int(fields[1]) 59 self.sentenceNum = int(fields[2]) 60 tmp = fields[3] 61 if len(tmp)>0: 62 self.sequentialMsgId = int(tmp) 63 else: 64 self.sequentialMsgId = None 65 # FIX: make an int if the above is set 66 self.aisChannel = fields[4] # 'A' or 'B' 67 self.contents = fields[5] 68 self.fillbits = int(fields[6].split('*')[0]) 69 self.checksumStr = fields[6].split('*')[1] # FIX: this is a hex string. Convert? 70 71 if self.sentenceNum==1: 72 self.msgTypeChar=fields[5][0] 73 else: 74 self.msgTypeChar=None 75 76 for i in range(len(fields)-1,5,-1): 77 if len(fields[i])==0: 78 continue # maybe it should throw a parse exception instead? 79 f = fields[i] 80 c = f[0] # first charater determines what the field is 81 if c in ('b','r'): 82 self.station = f # FIX: think we want to keep the code in the first char 83 self.stationTypeCode = self.station[0] 84 continue 85 #break # Found it so ditch the for loop 86 if c == 's': 87 self.rssi=int(f[1:]) 88 continue 89 if c == 'd': 90 self.signalStrength = int(f[1:]) 91 continue 92 if c == 'T': 93 self.timeOfArrival = float(f[1:]) 94 continue 95 if c == 'S': 96 self.slotNumber = int(f[1:]) 97 continue
98
99 -class TestUscgNmea(unittest.TestCase):
100 - def testUscgNmea(self):
101 un = UscgNmea('!AIVDM,1,1,,B,15Cjtd0Oj;Jp7ilG7=UkKBoB0<06,0*63,s1234,d-119,T12.34567123,r003669958,S4321,1085889680') 102 103 self.failUnlessEqual(un.nmeaType,'AIVDM') 104 self.failUnlessEqual(un.totalSentences,1) 105 self.failUnlessEqual(un.sentenceNum,1) 106 self.failUnlessEqual(un.sequentialMsgId,None) 107 self.failUnlessEqual(un.aisChannel,'B') 108 self.failUnlessEqual(un.fillbits,0) 109 self.failUnlessEqual(un.checksumStr,'63') 110 111 self.failUnlessEqual(un.rssi,1234) 112 self.failUnlessEqual(un.signalStrength,-119) 113 self.failUnlessEqual(un.timeOfArrival,12.34567123) 114 self.failUnlessEqual(un.slotNumber,4321) 115 self.failUnlessEqual(un.station,'r003669958') 116 self.failUnlessEqual(un.stationTypeCode,'r') 117 self.failUnlessEqual(un.cg_sec,float(1085889680)) 118 print un.timestamp 119 print un.sqlTimestampStr # Hmmm... they look the same
120 121 122 ############################################################ 123 if __name__=='__main__': 124 125 from optparse import OptionParser 126 parser = OptionParser(usage="%prog [options]", 127 version="%prog "+__version__) 128 129 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true' 130 ,help='run the documentation tests') 131 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true' 132 ,help='run the unit tests') 133 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true' 134 ,help='Make the test output verbose') 135 136 (options,args) = parser.parse_args() 137 138 if options.doctest: 139 success=True 140 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 141 sys.argv= [sys.argv[0]] 142 if options.verbose: sys.argv.append('-v') 143 import doctest 144 numfail,numtests=doctest.testmod() 145 if numfail==0: print 'ok' 146 else: 147 print 'FAILED' 148 success=False 149 150 if not success: sys.exit('Something Failed') 151 #del success # Hide success from epydoc 152 153 if options.unittest: 154 sys.argv = [sys.argv[0]] 155 if options.verbose: sys.argv.append('-v') 156 unittest.main() 157