From 6a9eb435eef5f2ddf29db2ba8539ef4bbefc64dc Mon Sep 17 00:00:00 2001 From: pwoods25443 Date: Wed, 9 Sep 2020 20:07:52 -0400 Subject: [PATCH] tidy up --- ais_tools/ais.py | 25 ++++------ ais_tools/ais18.py | 6 +-- ais_tools/ais24.py | 104 +++++++++++++++++++++-------------------- ais_tools/ais25.py | 21 +++------ ais_tools/transcode.py | 10 +++- 5 files changed, 79 insertions(+), 87 deletions(-) diff --git a/ais_tools/ais.py b/ais_tools/ais.py index b1ceb40..b9f18e7 100644 --- a/ais_tools/ais.py +++ b/ais_tools/ais.py @@ -10,31 +10,24 @@ message_types = { - 18: [ais18.AIS18Transcoder()], + 18: ais18.ais18_fields, 24: [ais24.AIS24Transcoder()], - 25: [ais25.AIS25Transcoder()], + 25: ais25.ais25_fields, } -class AISMessageTypeTranscoder(MessageTranscoder): +class AISMessageTranscoder(MessageTranscoder): - def get_fields(self, message=None): - msg_type = message.get('id') + def message_type_fields(self, msg_type): if msg_type not in message_types: raise DecodeError('AIS: Unknown message type {}'.format(msg_type)) - fields = message_types.get(msg_type, []) - return fields - + return message_types.get(msg_type, []) -ais_fields = [ - Uint(name='id', nbits=6, default=0), - AISMessageTypeTranscoder(), -] + def encode_fields(self, message): + return self.message_type_fields(message.get('id')) - -class AISMessageTranscoder(MessageTranscoder): - def __init__(self): - super().__init__(ais_fields) + def decode_fields(self, bits, message): + return self.message_type_fields(message.get('id', bits[0:6].uint)) def encode_nmea(self, message): return bits_to_nmea(byte_align(self.encode(message))) diff --git a/ais_tools/ais18.py b/ais_tools/ais18.py index c2849c4..4889131 100644 --- a/ais_tools/ais18.py +++ b/ais_tools/ais18.py @@ -6,11 +6,6 @@ from ais_tools.transcode import LatLonTranscoder as LatLon -class AIS18Transcoder(transcode.MessageTranscoder): - def __init__(self): - super().__init__(ais18_fields) - - class AIS18CommState(transcode.MessageTranscoder): def get_fields(self, message=None): unit_flag = message.get('unit_flag', 0) @@ -41,6 +36,7 @@ def get_fields(self, message=None): ais18_fields = [ + Uint(name='id', nbits=6, default=0), Uint(name='repeat_indicator', nbits=2), Uint(name='mmsi', nbits=30), Uint(name='spare', nbits=8), diff --git a/ais_tools/ais24.py b/ais_tools/ais24.py index 76b229e..d6bbffa 100644 --- a/ais_tools/ais24.py +++ b/ais_tools/ais24.py @@ -1,19 +1,12 @@ -from ais_tools import transcode from ais_tools.transcode import MessageTranscoder as Message -from ais_tools.transcode import DynamicTranscoder from ais_tools.transcode import DecodeError from ais_tools.transcode import UintTranscoder as Uint from ais_tools.transcode import ASCII6Transcoder as ASCII6 class AIS24Transcoder(Message): - def __init__(self): - super().__init__(ais24_fields) - -class AIS24PartAB(Message): - def get_fields(self, message=None): - part_num = message.get('part_num', 0) + def part_AB_fields(self, part_num): if part_num == 0: return ais24_part_A_fields elif part_num == 1: @@ -21,76 +14,87 @@ def get_fields(self, message=None): else: raise DecodeError('AIS24: unknown part number {}'.format(part_num)) + def encode_fields(self, message): + return self.part_AB_fields(message.get('part_num')) + + def decode_fields(self, bits, message): + return self.part_AB_fields(message.get('id', bits[38:40].uint)) -class VendorID(DynamicTranscoder): - def __init__(self): - self.vendorid_1371_2 = Message(ais24_vendorid_ITU_R_1371_2) - self.vendorid_1371_4 = Message(ais24_vendorid_ITU_R_1371_4) - def encoder(self, message): +class VendorID(Message): + def __init__(self, vendorid_1371_2, vendorid_1371_4): + self.vendorid_1371_2 = vendorid_1371_2 + self.vendorid_1371_4 = vendorid_1371_4 + + def encode_fields(self, message): if 'vendor_id' in message: return self.vendorid_1371_2 else: return self.vendorid_1371_4 - def decoders(self, message): - return [self.vendorid_1371_2, self.vendorid_1371_4] + def decode(self, bits, message=None): + message = message or {} + pos = bits.pos + for d in self.vendorid_1371_2: + message.update(d.decode(bits, message)) + bits.pos = pos # reset read position to read the same bits again for multiple decoders + for d in self.vendorid_1371_4: + message.update(d.decode(bits, message)) + return message class DimensionOrMothership(Message): - def __init__(self): + def __init__(self, dim_fields, mothership_fields): super().__init__() - self.shipDimension = Message(ais24_part_B_dimension_fields) - self.mothershipMMSI = Message(ais24_part_B_mothership_fields) + self.dim_fields = dim_fields + self.mothership_fields = mothership_fields def get_fields(self, message=None): mmsi = message.get('id') if mmsi // 10000000 == 98: - return [self.mothershipMMSI] + return self.mothership_fields else: - return [self.shipDimension] + return self.dim_fields -# COMMON FIELDS -ais24_fields = [ +# PART A +ais24_part_A_fields = [ + Uint(name='id', nbits=6, default=0), Uint(name='repeat_indicator', nbits=2), Uint(name='mmsi', nbits=30), Uint(name='part_num', nbits=2), - AIS24PartAB() -] - -# PART A -ais24_part_A_fields = [ ASCII6(name='name', nbits=120), ] -# PART B -ais24_vendorid_ITU_R_1371_2 =[ - ASCII6(name='vendor_id', nbits=42, default='@@@@@@@'), -] - -ais24_vendorid_ITU_R_1371_4 =[ - ASCII6(name='vendor_id_1371_4', nbits=18, default='@@@'), - Uint(name='vendor_model', nbits=4), - Uint(name='vendor_serial', nbits=20), -] - -ais24_part_B_dimension_fields = [ - Uint(name='dim_a', nbits=9), - Uint(name='dim_b', nbits=9), - Uint(name='dim_c', nbits=6), - Uint(name='dim_d', nbits=6), -] - -ais24_part_B_mothership_fields = [ - Uint(name='mothership_mmsi', nbits=30), -] ais24_part_B_fields = [ + Uint(name='id', nbits=6, default=0), + Uint(name='repeat_indicator', nbits=2), + Uint(name='mmsi', nbits=30), + Uint(name='part_num', nbits=2), Uint(name='type_and_cargo', nbits=8), - VendorID(), + VendorID( + [ + ASCII6(name='vendor_id', nbits=42, default='@@@@@@@'), + ], + [ + ASCII6(name='vendor_id_1371_4', nbits=18, default='@@@'), + Uint(name='vendor_model', nbits=4), + Uint(name='vendor_serial', nbits=20), + ], + ), ASCII6(name='callsign', nbits=42, default='@@@@@@@'), - DimensionOrMothership(), + DimensionOrMothership( + [ + Uint(name='dim_a', nbits=9), + Uint(name='dim_b', nbits=9), + Uint(name='dim_c', nbits=6), + Uint(name='dim_d', nbits=6), + ], + [ + Uint(name='mothership_mmsi', nbits=30), + ] + ), Uint(name='gps_type', nbits=4), Uint(name='spare', nbits=2), ] diff --git a/ais_tools/ais25.py b/ais_tools/ais25.py index e7c847b..fc93b99 100644 --- a/ais_tools/ais25.py +++ b/ais_tools/ais25.py @@ -1,43 +1,36 @@ from ais_tools import transcode -from ais_tools.transcode import DecodeError from ais_tools.transcode import UintTranscoder as Uint -from ais_tools.transcode import ASCII6Transcoder as ASCII6 from ais_tools.transcode import VariableLengthASCII6Transcoder as VarASCII6 -# Using this coding http://www.e-navigation.nl/content/text-using-6-bit-ascii-1 - - -class AIS25Transcoder(transcode.MessageTranscoder): - def __init__(self): - super().__init__(ais25_fields) +# Using this coding http://www.e-navigation.nl/content/text-using-6-bit-ascii-1 class AIS25Destination(transcode.MessageTranscoder): def get_fields(self, message=None): addressed = message.get('addressed', 0) if addressed: - return ais25_destination_fields + return self._fields else: return [] ais25_fields = [ + Uint(name='id', nbits=6, default=0), Uint(name='repeat_indicator', nbits=2), Uint(name='mmsi', nbits=30), Uint(name='part_num', nbits=2), Uint(name='addressed', nbits=1), Uint(name='use_app_id', nbits=1), - AIS25Destination(), + AIS25Destination([ + Uint(name='dest_mmsi', nbits=30), + Uint(name='spare', nbits=2), + ]), Uint(name='dac', nbits=10, default=1), Uint(name='fi', nbits=6), Uint(name='text_seq', nbits=11), VarASCII6(name='text', default='') ] -ais25_destination_fields = [ - Uint(name='dest_mmsi', nbits=30), - Uint(name='spare', nbits=2), -] diff --git a/ais_tools/transcode.py b/ais_tools/transcode.py index f2e9be5..be47601 100644 --- a/ais_tools/transcode.py +++ b/ais_tools/transcode.py @@ -62,15 +62,21 @@ def __init__(self, fields=None): def get_fields(self, message=None): return self._fields + def encode_fields(self, message): + return self.get_fields(message) + + def decode_fields(self, bits, message): + return self.get_fields(message) + def encode(self, message): bits = Bits() - for f in self.get_fields(message): + for f in self.encode_fields(message): bits += f.encode(message) return bits def decode(self, bits, message=None): message = message or {} - for f in self.get_fields(message): + for f in self.decode_fields(bits, message): message.update(f.decode(bits, message)) return message