Page MenuHomec4science

aisMsg.py
No OneTemporary

File Metadata

Created
Sun, Oct 6, 18:46

aisMsg.py

#!/usr/bin/python
import math
from bitBuf import bitBuf
from nmea import NMEAaddChecksum
#----------------------------------
# AIS message
# ITU-R M.1371-4 Annex 8
#----------------------------------
encodingTable = "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVW`abcdefghijklmnopqrstuvw"
class AISmsg :
def __init__(self) :
self.type = 0
self.repeat = 0
self.mmsi = 0
self.bb = bitBuf()
self.aisframe = ''
self.padding = 0
self.sentence = ''
def _bin2asc(self) :
out = ''
if self.bb.bit == 0 :
self.bb.buff.pop() # delete last element
for c in self.bb.buff :
if c < 64 :
out += encodingTable[c]
return out
# Encapsulate AIS frame in multiple NMEA frames
def EncapInAIVDM(self) :
multi = []
count = (len(self.aisframe)-1) / 60 # MAX_AIS=60
count += 1
segment = 0
for i in range(0, count) :
subframe = self.aisframe[segment:segment+60]
aivdm = "!AIVDM,"+str(count)+","+str(i+1)+",,A,"+subframe
segment += 60
if i != count-1 :
aivdm += ",0"
else :
aivdm += ","+str(self.padding)
aivdm = NMEAaddChecksum(aivdm)
multi.append(aivdm)
return multi
def Encode(self) :
self._encode()
return self.EncapInAIVDM()
def _asc2bin(self, c) :
byte = ord(c) - 48
if byte > 40 :
byte -= 8
return byte
def getBits(self, aChar, first, nb) :
return (aChar >> (6-(first+nb))) & ~(~0 << nb)
def read_uint(self, buf, firstBit, nbBits) :
idx = firstBit/6
byte = self._asc2bin(buf[idx])
bit = firstBit % 6
count = min(nbBits, 6-bit)
val = self.getBits(byte, bit, count)
nbBits -= (6-bit)
while nbBits > 0 :
idx += 1
byte = self._asc2bin(buf[idx])
count = min(nbBits, 6)
val = val << count
val |= self.getBits(byte, 0, count)
nbBits -= count
return val
def read_int(self, buf, firstBit, nbBits) :
val = self.read_uint(buf, firstBit, nbBits)
if ((val >> (nbBits-1) & 1) == 1) :
val |= (~0 << nbBits)
return val
def read_string(self, buf, firstBit, nbBits) :
str = ''
for i in range(0, nbBits/6) :
idx = self.read_uint(buf, firstBit, 6)
if idx <= 31 :
c = chr(idx + ord('@'))
elif idx <= 63 :
c = chr(idx)
else :
c = '@'
str = str + c
if c == '@' :
break
firstBit += 6
while str[-1] == '@' :
str = str[:-1]
return str
def Reset(self) :
self.sentence = ''
def Fragment(self, fragment) :
args = fragment.split(',')
if args[0].find('!AIVDM') >= 0 :
self.sentence += args[5]
if args[1] == args[2] :
return self._decode()
return None
def _decode(self) :
print 'Decode '+self.sentence
type = self.read_uint (self.sentence, 0, 6)
print 'Type '+str(type)
repeat = self.read_uint (self.sentence, 6, 2)
mmsi = self.read_uint (self.sentence, 8, 30)
if type == 1 :
obj = AISmsg1()
obj.repeat = repeat
obj.mmsi = mmsi
obj._decode(self.sentence)
elif type == 5 :
obj = AISmsg5()
obj.repeat = repeat
obj.mmsi = mmsi
obj._decode(self.sentence)
elif type == 21 :
obj = AISmsg21()
obj.repeat = repeat
obj.mmsi = mmsi
obj._decode(self.sentence)
else :
obj = None
return obj
class AISmsg1(AISmsg) :
UNDERWAY_ENGINE = 0
ANCHOR = 1
NOT_UNDER_COMMAND = 2
RESTRICTED_MANOEUVRABILITY = 3
CONSTRAINED_DRAUGHT = 4
MOORED = 5
AGROUND = 6
FISHING = 7
SAILING = 8
SART_ACTIVE = 14
SART_TEST = 15
NO_TURN_INFO_AVAILABLE = 128
HDG_NOT_AVAILABLE = 511
SPECIAL_MANOEUVRE_NOT_AVAIL = 0
SPECIAL_MANOEUVRE_NOT_ENGAGED = 1
SPECIAL_MANOEUVRE_ENGAGED = 2
def __init__(self) :
AISmsg.__init__(self)
self.type = 1
self.repeat = 0
# SART MMSI : 970xxxxxx
# MOB MMSI : 972xxxxxx
# EPIRB MMSI : 974xxxxxx
self.mmsi = 0
self.navStatus = AISmsg1.UNDERWAY_ENGINE
self.rot = AISmsg1.NO_TURN_INFO_AVAILABLE
self.sog = 0.0
self.accuracy = 0
self.lon = 0.0
self.lat = 0.0
self.cog = 0.0
self.hdg = AISmsg1.HDG_NOT_AVAILABLE
self.timeStamp = 0
self.specialManoeuvre = AISmsg1.SPECIAL_MANOEUVRE_NOT_AVAIL
self.RAIM = 0
self.radioStatus = 0
def _encode(self) :
self.bb = bitBuf()
self.aisframe = ''
self.padding = 0
self.bb.WriteByte (self.type, 6)
self.bb.WriteByte (self.repeat, 2)
self.bb.WriteInteger (self.mmsi, 30)
self.bb.WriteByte (self.navStatus, 4)
self.bb.WriteInteger (self.rot, 8)
self.bb.WriteInteger (int(self.sog * 10), 10)
self.bb.WriteBit (self.accuracy)
lon = int((self.lon * 600000) + 0.5)
if self.lon < 0 :
lon = (lon ^ 0x0fffffff) + 1 # 2-complement
self.bb.WriteInteger (lon, 28)
lat = int((self.lat * 600000) + 0.5)
if self.lat < 0 :
lat = (lat ^ 0x0fffffff) + 1 # 2-complement
self.bb.WriteInteger (lat, 27)
self.bb.WriteInteger (int(self.cog * 10), 12)
self.bb.WriteInteger (int(self.hdg), 9)
self.bb.WriteByte (self.timeStamp, 6)
self.bb.WriteByte (self.specialManoeuvre, 2)
self.bb.WriteByte (0, 3) # spare
self.bb.WriteBit (self.RAIM)
self.bb.WriteInteger (self.radioStatus, 19)
self.aisframe = self._bin2asc()
self.padding = self.bb.Padding()
def _decode(self, sentence) :
self.sentence = sentence
self.navStatus = self.read_uint (self.sentence, 38, 4)
self.rot = math.pow(self.read_uint (self.sentence, 42, 8) / 4.733, 2.0)
self.sog = self.read_uint (self.sentence, 50, 10) / 10.0
self.accuracy = self.read_uint (self.sentence, 60, 1)
self.lon = self.read_int(self.sentence, 61, 28) / 600000.0
self.lat = self.read_int(self.sentence, 89, 27) / 600000.0
self.cog = self.read_uint (self.sentence, 116, 12) / 10.0
self.hdg = self.read_uint (self.sentence, 128, 9) / 10.0
self.timeStamp = self.read_uint (self.sentence, 137, 6)
self.specialManoeuvre = self.read_uint (self.sentence, 143, 2)
self.RAIM = self.read_uint (self.sentence, 148, 1)
self.radioStatus = self.read_uint (self.sentence, 149, 19)
class AISmsg5(AISmsg) :
VERSION_M1371_1 = 0
VERSION_M1371_3 = 1
FISHING = 30
TOWING = 31
TOWING_200m = 32
DREDGING = 33
DIVING = 34
MILITARY = 35
SAILING = 36
PLEASURE = 37
HIGH_SPEED = 40
PILOT_VESSEL = 50
SAR_VESSEL = 51
TUG = 52
PORT_TENDER = 53
PASSENGER = 60
CARGO = 70
TANKER = 80
OTHER = 90
DEVICE_UNDEFINED = 0
DEVICE_GPS = 1
DEVICE_GLONASS = 2
DEVICE_LORANC = 4
DEVICE_GALILEO = 8
def __init__(self) :
AISmsg.__init__(self)
self.type = 5
self.version = self.VERSION_M1371_1
self.imo = 0
self.callSign = ''
self.name = ''
self.shipType = 0
self.to_bow = 0
self.to_stern = 0
self.to_port = 0
self.to_starboard = 0
self.deviceType = self.DEVICE_UNDEFINED
self.ETAmonth = 0
self.ETAday = 0
self.ETAhour = 0
self.ETAminute = 0
self.draught = 0
self.destination = ''
self.dte = 0
def _encode(self) :
self.bb = bitBuf()
self.aisframe = ''
self.padding = 0
self.bb.WriteByte (self.type, 6)
self.bb.WriteByte (self.repeat, 2)
self.bb.WriteInteger (self.mmsi, 30)
self.bb.WriteByte (self.version, 2)
self.bb.WriteInteger (self.imo, 30)
self.bb.WriteString (self.callSign, 7)
self.bb.WriteString (self.name, 20)
self.bb.WriteByte (self.shipType, 8)
self.bb.WriteInteger (self.to_bow, 9)
self.bb.WriteInteger (self.to_stern, 9)
self.bb.WriteByte (self.to_port, 6)
self.bb.WriteByte (self.to_starboard, 6)
self.bb.WriteByte (self.deviceType, 4)
self.bb.WriteInteger (self.ETAmonth, 4)
self.bb.WriteInteger (self.ETAday, 5)
self.bb.WriteInteger (self.ETAhour, 5)
self.bb.WriteInteger (self.ETAminute, 6)
self.bb.WriteByte (self.draught * 10, 8)
self.bb.WriteString (self.destination, 20)
self.bb.WriteBit (self.dte)
self.bb.WriteBit (0) # spare
self.aisframe = self._bin2asc()
self.padding = self.bb.Padding()
def _decode(self, sentence) :
self.sentence = sentence
self.version = self.read_uint (self.sentence, 38, 2)
self.imo = self.read_uint (self.sentence, 40, 30)
self.callSign = self.read_string (self.sentence, 70, 42)
self.name = self.read_string (self.sentence, 112, 120)
self.shipType = self.read_uint (self.sentence, 232, 8)
self.to_bow = self.read_uint (self.sentence, 240, 9)
self.to_stern = self.read_uint (self.sentence, 249, 9)
self.to_port = self.read_uint (self.sentence, 258, 6)
self.to_starboard = self.read_uint (self.sentence, 264, 6)
self.ETAmonth = self.read_uint (self.sentence, 274, 4)
self.ETAday = self.read_uint (self.sentence, 278, 5)
self.ETAhour = self.read_uint (self.sentence, 283, 5)
self.ETAminute = self.read_uint (self.sentence, 288, 6)
self.draught = self.read_uint (self.sentence, 294, 8) / 10.0
self.destination = self.read_string (self.sentence, 302, 120)
class AISmsg21(AISmsg) :
NOT_SPECIFIED = 0
REFERENCE_POINT = 1
RACON = 2
FIXED_STRUCTURE_OFFSHORE = 3
LIGHT_WITHOUT_SECTORS = 5
LIGHT_WITH_SECTORS = 6
LEADING_LIGHT_FRONT = 7
LEADING_LIGHT_REAR = 8
BEACON_CARDINAL_N = 9
BEACON_CARDINAL_E = 10
BEACON_CARDINAL_S = 11
BEACON_CARDINAL_W = 12
BEACON_PORT = 13
BEACON_STARBOARD = 14
BEACON_PREF_PORT = 15
BEACON_PREF_STARBOARD = 16
BEACON_ISOLATED = 17
BEACON_SAFE_WATER = 18
BEACON_SPECIAL_MARK = 19
CARDINAL_N = 20
CARDINAL_E = 21
CARDINAL_S = 22
CARDINAL_W = 23
PORT_HAND_MARK = 24
STARBOARD_HAND_MARK = 25
PREF_CHANNEL_PORT = 26
PREF_CHANNEL_STARBOARD = 27
ISOLATED_DANGER = 28
SAFE_WATER = 29
SPECIAL_MARK = 30
LIGHT_VESSEL = 31
def __init__(self) :
AISmsg.__init__(self)
self.type = 21
self.AtoN_type = self.NOT_SPECIFIED
self.name = ''
self.accuracy = 1
self.lon = 0.0
self.lat = 0.0
self.to_bow = 0
self.to_stern = 0
self.to_port = 0
self.to_starboard = 0
self.deviceType = 0
self.timeStamp = 0
self.offPosition = 0
self.AtoN_status = 0
self.RAIM = 0
self.virtual_AtoN = 0
self.assigned = 0
self.spare = 0
self.extension = ''
def _encode(self) :
self.bb = bitBuf()
self.aisframe = ''
self.padding = 0
self.bb.WriteByte (self.type, 6)
self.bb.WriteByte (self.repeat, 2)
self.bb.WriteInteger (self.mmsi, 30)
self.bb.WriteByte (self.AtoN_type, 5)
self.bb.WriteString (self.name, 20)
self.bb.WriteBit (self.accuracy)
lon = int((self.lon * 600000) + 0.5)
if self.lon < 0 :
lon = (lon ^ 0x0fffffff) + 1 # 2-complement
self.bb.WriteInteger (lon, 28)
lat = int((self.lat * 600000) + 0.5)
if self.lat < 0 :
lat = (lat ^ 0x0fffffff) + 1 # 2-complement
self.bb.WriteInteger (lat, 27)
self.bb.WriteInteger (self.to_bow, 9)
self.bb.WriteInteger (self.to_stern, 9)
self.bb.WriteByte (self.to_port, 6)
self.bb.WriteByte (self.to_starboard, 6)
self.bb.WriteByte (self.deviceType, 4)
self.bb.WriteByte (self.timeStamp, 6)
self.bb.WriteBit (self.offPosition)
self.bb.WriteByte (self.AtoN_status, 8)
self.bb.WriteBit (self.RAIM)
self.bb.WriteBit (self.virtual_AtoN)
self.bb.WriteBit (self.assigned)
self.bb.WriteBit (self.spare)
if len(self.extension) > 0 :
self.bb.WriteString (self.extension, len(self.extension))
self.bb.WriteInteger (self.spare2, 6)
self.aisframe = self._bin2asc()
self.padding = self.bb.Padding()
def _decode(self, sentence) :
self.sentence = sentence
self.AtoN_type = self.read_uint(self.sentence, 38, 5)
self.name = self.read_string(self.sentence, 43, 120)
self.accuracy = self.read_uint(self.sentence, 163, 1)
self.lon = self.read_int (self.sentence, 164, 28) / 600000.0
self.lat = self.read_int (self.sentence, 192, 27) / 600000.0
self.to_bow = self.read_uint(self.sentence, 219, 9)
self.to_stern = self.read_uint(self.sentence, 228, 9)
self.to_port = self.read_uint(self.sentence, 237, 6)
self.to_starboard = self.read_uint(self.sentence, 243, 6)
self.deviceType = self.read_uint(self.sentence, 249, 4)
self.timeStamp = self.read_uint(self.sentence, 253, 6)
self.offPosition = self.read_uint(self.sentence, 259, 1)
self.AtoN_status = self.read_uint(self.sentence, 260, 8)
self.RAIM = self.read_uint(self.sentence, 268, 1)
self.virtual_AtoN = self.read_uint(self.sentence, 269, 1)
self.assigned = self.read_uint(self.sentence, 270, 1)
self.spare = self.read_uint(self.sentence, 271, 1)
#
# Code for testing classes
#
if __name__ == '__main__':
obj = AISmsg5()
obj.mmsi = 205344990
obj.callSign = 'ATC'
obj.name = 'PETIT BAIGNEUR'
obj.destination = 'MARSEILLE'
obj.to_bow = 50
obj.to_stern = 20
obj.to_port = 10
obj.to_starboard = 10
obj.ETAmonth = 12
obj.ETAday = 12
obj.ETAhour = 1
obj.ETAminute = 30
obj.draught = 10
multi = obj.Encode()
for aivdm in multi :
print aivdm
obj = AISmsg1()
obj.mmsi = 205344990
obj.navStatus = AISmsg1.UNDERWAY_ENGINE
obj.sog = 20
obj.accuracy = 1
obj.lat = 43.01666
obj.lon = 6.0
obj.cog = 110.7
obj.hdg = AISmsg1.HDG_NOT_AVAILABLE
obj.timeStamp = 40
obj.specialManoeuvre = AISmsg1.SPECIAL_MANOEUVRE_NOT_AVAIL
obj.RAIM = 1
obj.state = 0
multi = obj.Encode()
for aivdm in multi :
print aivdm
obj = AISmsg21()
obj.mmsi = 101010100
obj.AtoN_type = AISmsg21.BEACON_CARDINAL_N
obj.name = 'Nord'
obj.accuracy = 1
obj.lat = 42.0 + 0.05
obj.lon = 6.0
obj.virtual_AtoN = 1
multi = obj.Encode()
for aivdm in multi :
print aivdm
# !AIVDM,1,1,,A,E1PE:e4W7a20000000000000000@=fr0<1uF0000000010,4*7D
decoder = AISmsg()
decoder.Fragment('!AIVDM,2,1,,A,533m@oP000005@<00010E@UB084TLpEE800000006@D::361NI3@DTiBC31@,0*4C')
ais = decoder.Fragment('!AIVDM,2,2,,A,00000000000,2*14')
if ais != None :
print 'Type : ' + str(ais.type)
print 'mmsi : ' + str(ais.mmsi)
print ais.name
print ais.destination
print ais.__dict__

Event Timeline