def test_empty_value_for_cog(self): """ this sentence doesn't appear to have a value for course over ground the binary module should raise a NoBinaryData exception """ testsentence = '!AIVDM,1,1,,A,3O>soN5MUNBoMdUdlh,0*64' nmeatracker = nmea.NMEAtracker() testdata = nmeatracker.process_sentence(testsentence) testbinarystr = binary.ais_sentence_payload_binary(testdata) with self.assertRaises(binary.NoBinaryData): binary.decode_sixbit_integer(testbinarystr[116:128]) / 10
def __init__(self, msgbinary): self.msgbinary = msgbinary self.msgtype = binary.decode_sixbit_integer(msgbinary[0:6]) self.repeatcount = binary.decode_sixbit_integer(msgbinary[6:8]) self.mmsi = str( format(binary.decode_sixbit_integer(msgbinary[8:38]), '09d')) try: self.description = MSGDESCRIPTIONS[self.msgtype] except KeyError: self.description = 'Unknown' self.rxtime = 'N/A'
def process_message(self, data): """ determine what type of AIS message it is Args: data(str): full message payload from 1 or more NMEA sentences Raises: InvalidMMSI: if the mmsi = 000000000 Returns: msgobj(messages.aismessage.AISMessage): the ais message type object """ msgbinary = binary.ais_sentence_payload_binary(data) msgtype = binary.decode_sixbit_integer(msgbinary[0:6]) if msgtype in (4, 11): msgobj = allmessages.MSGTYPES[msgtype](msgbinary) if msgobj.mmsi == '000000000': raise InvalidMMSI('Invalid MMSI - 000000000') if msgobj.mmsi not in self.stations: self.stations[msgobj.mmsi] = AISStation(msgobj.mmsi) if self.stations[msgobj.mmsi].stnclass == 'Unknown': self.stations[msgobj.mmsi].determine_station_class(msgobj) msgobj.rxtime = msgobj.timestamp self.stations[msgobj.mmsi].find_position_information(msgobj) self.messagesprocessed += 1 self.messages[allmessages.MSGDESCRIPTIONS[msgtype]] += 1
def decode_turn_rate(rawvalue): """ decode the turn rate value to something meaningful Args: rawvalue(str): turn rate encoded as binary string Returns: turnvalue(str): actual turn rate of the vessel """ decodedturnrate = binary.decode_sixbit_integer(rawvalue) decodedvalues = { 0: 'not turning', 128: 'no turn rate available', 127: ('turning right at more than 10 degrees per minute' ' - NO TURN INDICATOR'), 129: ('turning left at more than -10 degrees per minute' ' - NO TURN INDICATOR')} if decodedturnrate in decodedvalues: turnvalue = decodedvalues[decodedturnrate] else: twos = binary.decode_twos_complement(rawvalue) rot = (twos / 4.733) ** 2 if rawvalue[0] == '1': rot = rot * -1 direction = 'left' else: direction = 'right' turnvalue = 'turning {} at {} degrees per minute'.format( direction, round(rot, 1)) return turnvalue
def process_message(self, data, timestamp=None): """ determine what type of AIS message it is Note: the timestamp can be given as an argument for each message to be processed or timings can be approximated from the last type 4/11 base station report timestamp received. for the latter option it is preferred that you have a nearby base station transmitting the correct time on a regular interval Args: data(str): full message payload from 1 or more NMEA sentences timestamp(str): time this message was recieved, if provided this will take precedence over timings received from AIS base stations Raises: UnknownMessageType: if the message type is not in the allmessages.MSGTYPES dict InvalidMMSI: if the mmsi = 000000000 Returns: msgobj(messages.aismessage.AISMessage): the ais message type object """ msgbinary = binary.ais_sentence_payload_binary(data) msgtype = binary.decode_sixbit_integer(msgbinary[0:6]) if msgtype in allmessages.MSGTYPES.keys(): msgobj = allmessages.MSGTYPES[msgtype](msgbinary) else: raise UnknownMessageType( 'Unknown message type {} - {}'.format(msgtype, data)) if msgobj.mmsi == '000000000': raise InvalidMMSI('Invalid MMSI - 000000000') if msgobj.mmsi not in self.stations: self.stations[msgobj.mmsi] = AISStation(msgobj.mmsi) if self.stations[msgobj.mmsi].stnclass == 'Unknown': self.stations[msgobj.mmsi].determine_station_class(msgobj) if (self.stations[msgobj.mmsi].stntype == 'Unknown' or self.stations[msgobj.mmsi].name == ''): self.stations[msgobj.mmsi].find_station_name_and_type(msgobj) if timestamp: if timestamp not in self.timings: self.timings.append(timestamp) else: if msgtype in (4, 11) and msgobj.mmsi in self.timingsource: if (msgobj.timestamp != TIMEUNAVAILABLE and msgobj.timestamp not in self.timings and kml.DATETIMEREGEX.match(msgobj.timestamp)): self.timings.append(msgobj.timestamp + ' (estimated)') try: timestamp = self.timings[len(self.timings) - 1] except IndexError: timestamp = 'N/A' msgobj.rxtime = timestamp self.stations[msgobj.mmsi].find_position_information(msgobj) self.messagesprocessed += 1 self.messages[allmessages.MSGDESCRIPTIONS[msgtype]] += 1 return msgobj
def test_sixbit_integer_decoding(self): """ tests converting from binary into integer """ binstr = '000001100' expected = 12 decoded = binary.decode_sixbit_integer(binstr[2:9]) self.assertEqual(expected, decoded)
def decode_sixbit_integer(binarystr): """ a wrapper for binary.decode_sixbit_intger adds exception handling Note: if we get a no binary data exception simply return a 0 """ try: returnval = binary.decode_sixbit_integer(binarystr) except binary.NoBinaryData: returnval = 0 return returnval