openrvdas.logger.transforms.nmea_checksum_transform

No module-level documentation available.
  1import logging
  2# For efficient checksum code
  3from functools import reduce
  4from operator import xor
  5
  6from logger.transforms.transform import Transform  # noqa: E402
  7
  8
  9############################
 10def get_message_str(source):
 11    """ Returns message_str, which is everything between the '$' and '*' in the source string """
 12
 13    if ((source.find('$') == -1) or (source.find('*') == -1)):
 14        return None
 15
 16    start = source.index('$')+1
 17    end = source.index('*')
 18    message_str = source[start:end]
 19    return message_str
 20
 21
 22def get_checksum_value(source):
 23    """ Returns checksum_value, which is the parsed checksum value (after '*')
 24    from the source string.
 25    """
 26
 27    if (source.find('*') == -1):
 28        return None
 29
 30    start = source.index('*')+1
 31    checksum_value = source[start:]
 32    return checksum_value
 33
 34
 35def compute_checksum(source):
 36    """Return hex checksum for source string."""
 37
 38    return '%02X' % reduce(xor, (ord(c) for c in source))
 39
 40
 41################################################################################
 42class NMEAChecksumTransform(Transform):
 43    """
 44    NMEAChecksumTransform checks the integrity/completeness of a record by confirming
 45    whether or not the checksum matches. If the checksum matches, it returns the record,
 46    and otherwise it sends an error message.
 47    """
 48
 49    DEFAULT_ERROR_MESSAGE = 'Bad checksum for record: '
 50
 51    def __init__(self, checksum_optional=False, error_message=DEFAULT_ERROR_MESSAGE,
 52                 writer=None, **kwargs):
 53        """
 54        checksum_optional — If True, then pass record along even if checksum is missing
 55        error_message     — Optional custom error message; if None then use DEFAULT_ERROR_MESSAGE
 56        writer            — Optional error writer; if None, log to stderr
 57        """
 58        super().__init__(**kwargs)  # processes 'quiet' and type hints
 59
 60        self.checksum_optional = checksum_optional
 61        self.error_message = error_message
 62        self.writer = writer
 63
 64        # Tries to utilize the write() method of writer, which it
 65        # would only have if the object is a Writer. Send it a 'None'
 66        # record, which all writers should ignore. If this fails,
 67        # writer is set to None.
 68        if writer:
 69            try:
 70                writer.write(None)
 71            except AttributeError:
 72                logging.error('Writer passed to NMEAChecksumTransform has no '
 73                              'write() method!')
 74                self.writer = None
 75
 76    def transform(self, record: str):
 77        """
 78        Checks if computed checksum matches parsed checksum. If True, it returns the record,
 79        otherwise it calls send_error_message().
 80
 81        record - the record in question
 82        """
 83        # See if it's something we can process, and if not, try digesting
 84        if not self.can_process_record(record):  # inherited from BaseModule()
 85            return self.digest_record(record)  # inherited from BaseModule()
 86
 87        if not type(record) is str:
 88            logging.warning('NMEAChecksumTransform passed non-string record '
 89                            '(type %s): %s', type(record), record)
 90            return None
 91
 92        checksum_value = get_checksum_value(record)
 93
 94        if checksum_value is None:
 95            if self.checksum_optional:
 96                return record
 97
 98            # If here, checksum is not optional and does not exist
 99            self.send_error_message(record, 'No checksum found in record ')
100            return None
101
102        message_str = get_message_str(record)
103        computed_checksum = compute_checksum(message_str)
104
105        # If here, and we are about to see if it matches
106        if computed_checksum == checksum_value:
107            return record
108
109        # If here, then checksum exists but didn't match
110        self.send_error_message(record)
111        return None
112
113    def send_error_message(self, record, message=None):
114        """
115            Send error to writer if one exists, otherwise send it to stderr
116
117            record - the record with the error
118            message - optional custom message. If None, then use self.error_message
119        """
120
121        error_message = message or self.error_message
122        error_message += record
123
124        if self.writer:
125            self.writer.write(error_message)
126        else:
127            logging.warning(error_message)
def get_message_str(source):
11def get_message_str(source):
12    """ Returns message_str, which is everything between the '$' and '*' in the source string """
13
14    if ((source.find('$') == -1) or (source.find('*') == -1)):
15        return None
16
17    start = source.index('$')+1
18    end = source.index('*')
19    message_str = source[start:end]
20    return message_str

Returns message_str, which is everything between the '$' and '*' in the source string

def get_checksum_value(source):
23def get_checksum_value(source):
24    """ Returns checksum_value, which is the parsed checksum value (after '*')
25    from the source string.
26    """
27
28    if (source.find('*') == -1):
29        return None
30
31    start = source.index('*')+1
32    checksum_value = source[start:]
33    return checksum_value

Returns checksum_value, which is the parsed checksum value (after '*') from the source string.

def compute_checksum(source):
36def compute_checksum(source):
37    """Return hex checksum for source string."""
38
39    return '%02X' % reduce(xor, (ord(c) for c in source))

Return hex checksum for source string.

class NMEAChecksumTransform(logger.transforms.transform.Transform):
 43class NMEAChecksumTransform(Transform):
 44    """
 45    NMEAChecksumTransform checks the integrity/completeness of a record by confirming
 46    whether or not the checksum matches. If the checksum matches, it returns the record,
 47    and otherwise it sends an error message.
 48    """
 49
 50    DEFAULT_ERROR_MESSAGE = 'Bad checksum for record: '
 51
 52    def __init__(self, checksum_optional=False, error_message=DEFAULT_ERROR_MESSAGE,
 53                 writer=None, **kwargs):
 54        """
 55        checksum_optional — If True, then pass record along even if checksum is missing
 56        error_message     — Optional custom error message; if None then use DEFAULT_ERROR_MESSAGE
 57        writer            — Optional error writer; if None, log to stderr
 58        """
 59        super().__init__(**kwargs)  # processes 'quiet' and type hints
 60
 61        self.checksum_optional = checksum_optional
 62        self.error_message = error_message
 63        self.writer = writer
 64
 65        # Tries to utilize the write() method of writer, which it
 66        # would only have if the object is a Writer. Send it a 'None'
 67        # record, which all writers should ignore. If this fails,
 68        # writer is set to None.
 69        if writer:
 70            try:
 71                writer.write(None)
 72            except AttributeError:
 73                logging.error('Writer passed to NMEAChecksumTransform has no '
 74                              'write() method!')
 75                self.writer = None
 76
 77    def transform(self, record: str):
 78        """
 79        Checks if computed checksum matches parsed checksum. If True, it returns the record,
 80        otherwise it calls send_error_message().
 81
 82        record - the record in question
 83        """
 84        # See if it's something we can process, and if not, try digesting
 85        if not self.can_process_record(record):  # inherited from BaseModule()
 86            return self.digest_record(record)  # inherited from BaseModule()
 87
 88        if not type(record) is str:
 89            logging.warning('NMEAChecksumTransform passed non-string record '
 90                            '(type %s): %s', type(record), record)
 91            return None
 92
 93        checksum_value = get_checksum_value(record)
 94
 95        if checksum_value is None:
 96            if self.checksum_optional:
 97                return record
 98
 99            # If here, checksum is not optional and does not exist
100            self.send_error_message(record, 'No checksum found in record ')
101            return None
102
103        message_str = get_message_str(record)
104        computed_checksum = compute_checksum(message_str)
105
106        # If here, and we are about to see if it matches
107        if computed_checksum == checksum_value:
108            return record
109
110        # If here, then checksum exists but didn't match
111        self.send_error_message(record)
112        return None
113
114    def send_error_message(self, record, message=None):
115        """
116            Send error to writer if one exists, otherwise send it to stderr
117
118            record - the record with the error
119            message - optional custom message. If None, then use self.error_message
120        """
121
122        error_message = message or self.error_message
123        error_message += record
124
125        if self.writer:
126            self.writer.write(error_message)
127        else:
128            logging.warning(error_message)

NMEAChecksumTransform checks the integrity/completeness of a record by confirming whether or not the checksum matches. If the checksum matches, it returns the record, and otherwise it sends an error message.

NMEAChecksumTransform( checksum_optional=False, error_message='Bad checksum for record: ', writer=None, **kwargs)
52    def __init__(self, checksum_optional=False, error_message=DEFAULT_ERROR_MESSAGE,
53                 writer=None, **kwargs):
54        """
55        checksum_optional — If True, then pass record along even if checksum is missing
56        error_message     — Optional custom error message; if None then use DEFAULT_ERROR_MESSAGE
57        writer            — Optional error writer; if None, log to stderr
58        """
59        super().__init__(**kwargs)  # processes 'quiet' and type hints
60
61        self.checksum_optional = checksum_optional
62        self.error_message = error_message
63        self.writer = writer
64
65        # Tries to utilize the write() method of writer, which it
66        # would only have if the object is a Writer. Send it a 'None'
67        # record, which all writers should ignore. If this fails,
68        # writer is set to None.
69        if writer:
70            try:
71                writer.write(None)
72            except AttributeError:
73                logging.error('Writer passed to NMEAChecksumTransform has no '
74                              'write() method!')
75                self.writer = None

checksum_optional — If True, then pass record along even if checksum is missing error_message — Optional custom error message; if None then use DEFAULT_ERROR_MESSAGE writer — Optional error writer; if None, log to stderr

DEFAULT_ERROR_MESSAGE = 'Bad checksum for record: '
checksum_optional
error_message
writer
def transform(self, record: str):
 77    def transform(self, record: str):
 78        """
 79        Checks if computed checksum matches parsed checksum. If True, it returns the record,
 80        otherwise it calls send_error_message().
 81
 82        record - the record in question
 83        """
 84        # See if it's something we can process, and if not, try digesting
 85        if not self.can_process_record(record):  # inherited from BaseModule()
 86            return self.digest_record(record)  # inherited from BaseModule()
 87
 88        if not type(record) is str:
 89            logging.warning('NMEAChecksumTransform passed non-string record '
 90                            '(type %s): %s', type(record), record)
 91            return None
 92
 93        checksum_value = get_checksum_value(record)
 94
 95        if checksum_value is None:
 96            if self.checksum_optional:
 97                return record
 98
 99            # If here, checksum is not optional and does not exist
100            self.send_error_message(record, 'No checksum found in record ')
101            return None
102
103        message_str = get_message_str(record)
104        computed_checksum = compute_checksum(message_str)
105
106        # If here, and we are about to see if it matches
107        if computed_checksum == checksum_value:
108            return record
109
110        # If here, then checksum exists but didn't match
111        self.send_error_message(record)
112        return None

Checks if computed checksum matches parsed checksum. If True, it returns the record, otherwise it calls send_error_message().

record - the record in question

def send_error_message(self, record, message=None):
114    def send_error_message(self, record, message=None):
115        """
116            Send error to writer if one exists, otherwise send it to stderr
117
118            record - the record with the error
119            message - optional custom message. If None, then use self.error_message
120        """
121
122        error_message = message or self.error_message
123        error_message += record
124
125        if self.writer:
126            self.writer.write(error_message)
127        else:
128            logging.warning(error_message)

Send error to writer if one exists, otherwise send it to stderr

record - the record with the error message - optional custom message. If None, then use self.error_message