Exemplo n.º 1
0
    def __init__(self, raw: bytes):
        # Set all values to None initially
        [setattr(self, name, None) for name in self.__slots__]

        # Store raw data
        self.raw = raw

        # An AIS NMEA message consists of seven, comma separated parts
        values = raw.split(b",")

        # Only encapsulated messages are currently supported
        if values[0][0] != 0x21:
            return

        if len(values) != 7:
            raise InvalidNMEAMessageException("A NMEA message needs to have exactly 7 comma separated entries.")

        # Unpack NMEA message parts
        (
            head,
            count,
            index,
            seq_id,
            channel,
            data,
            checksum
        ) = values

        # The talker is identified by the next 2 characters
        self.talker = head[1:3].decode('ascii')

        # The type of message is then identified by the next 3 characters
        self.msg_type = head[3:].decode('ascii')

        # Store other important parts
        self.count = int(count)
        self.index = int(index)
        self.seq_id = seq_id
        self.channel = channel
        self.data = data
        self.checksum = int(checksum[2:], 16)

        # Verify if the checksum is correct
        if not self.is_valid:
            raise InvalidChecksumException(
                f"Invalid Checksum. Expected {self.checksum}, got {compute_checksum(self.data)}.")

        # Finally decode bytes into bits
        self.bit_array = decode_into_bit_array(self.data)
        self.ais_id = get_int(self.bit_array, 0, 6)
Exemplo n.º 2
0
def validate_message(msg: bytes) -> None:
    """
    Validates a given message.
    It checks if the messages complies with the AIS standard.
    It is based on:
        1. https://en.wikipedia.org/wiki/Automatic_identification_system
        2. https://en.wikipedia.org/wiki/NMEA_0183

    If not errors are found, nothing is returned.
    Otherwise an InvalidNMEAMessageException is raised.
    """
    values = msg.split(b",")

    # A message has exactly 7 comma separated values
    if len(values) != 7:
        raise InvalidNMEAMessageException(
            "A NMEA message needs to have exactly 7 comma separated entries.")

    # The only allowed blank value may be the message ID
    if not values[0]:
        raise InvalidNMEAMessageException("The NMEA message type is empty!")

    if not values[1]:
        raise InvalidNMEAMessageException("Number of sentences is empty!")

    if not values[2]:
        raise InvalidNMEAMessageException("Sentence number is empty!")

    if not values[4]:
        raise InvalidNMEAMessageException("The AIS channel (A or B) is empty.")

    if not values[5]:
        raise InvalidNMEAMessageException(
            "The NMEA message body (payload) is empty.")

    if not values[6]:
        raise InvalidNMEAMessageException(
            "NMEA checksum (NMEA 0183 Standard CRC16) is empty.")

    try:
        sentence_num = int(values[1])
        if sentence_num > 9:
            raise InvalidNMEAMessageException(
                "Number of sentences exceeds limit of 9 total sentences.")
    except ValueError:
        raise InvalidNMEAMessageException(
            "Invalid sentence number. No Number.")

    if values[2]:
        try:
            sentence_num = int(values[2])
            if sentence_num > 9:
                raise InvalidNMEAMessageException(
                    " Sentence number exceeds limit of 9 total sentences.")
        except ValueError:
            raise InvalidNMEAMessageException(
                "Invalid Sentence number. No Number.")

    if values[3]:
        try:
            sentence_num = int(values[3])
            if sentence_num > 9:
                raise InvalidNMEAMessageException(
                    "Number of sequential message ID exceeds limit of 9 total sentences."
                )
        except ValueError:
            raise InvalidNMEAMessageException(
                "Invalid  sequential message ID. No Number.")

    # It should not have more than 82 chars (including starting $ or ! and <LF>)
    if len(msg) > 82:
        raise InvalidNMEAMessageException(
            f"{msg.decode('utf-8')} has more than 82 characters.")

    # Only encapsulated messages are currently supported
    if values[0][0] != 0x21:
        # https://en.wikipedia.org/wiki/Automatic_identification_system
        raise InvalidNMEAMessageException(
            "'NMEAMessage' only supports !AIVDM/!AIVDO encapsulated messages. "
            f"These start with an '!', but got '{chr(values[0][0])}'")