def parse(message: bytes, validate: bool = False, mode: int = 0) -> object: """ Parse UBX byte stream to UBXMessage object. Includes option to validate incoming payload length and checksum (the UBXMessage constructor can calculate and assign its own values anyway). :param bytes message: binary message to parse :param bool validate: validate message length and checksum (False (default), True) :param int mode: message mode (0=GET (default), 1=SET, 2=POLL) :return: UBXMessage object :rtype: UBXMessage :raises: UBXParseError (if data stream contains invalid data or unknown message type) """ if mode not in (0, 1, 2): raise ube.UBXParseError( f"Invalid message mode {mode} - must be 0, 1 or 2") lenm = len(message) hdr = message[0:2] clsid = message[2:3] msgid = message[3:4] lenb = message[4:6] if lenb == b"\x00\x00": payload = None leni = 0 else: payload = message[6:lenm - 2] leni = len(payload) ckm = message[lenm - 2:lenm] if payload is not None: ckv = calc_checksum(clsid + msgid + lenb + payload) else: ckv = calc_checksum(clsid + msgid + lenb) if validate: if hdr != ubt.UBX_HDR: raise ube.UBXParseError((f"Invalid message header {hdr}" f" - should be {ubt.UBX_HDR}")) if leni != UBXMessage.bytes2val(lenb, ubt.U2): raise ube.UBXParseError( (f"Invalid payload length {lenb}" f" - should be {UBXMessage.val2bytes(leni, ubt.U2)}")) if ckm != ckv: raise ube.UBXParseError((f"Message checksum {ckm}" f" invalid - should be {ckv}")) try: if payload is None: return UBXMessage(clsid, msgid, mode) return UBXMessage(clsid, msgid, mode, payload=payload) except KeyError as err: modestr = ["GET", "SET", "POLL"][mode] raise ube.UBXParseError(( f"Unknown message type clsid {clsid}, msgid {msgid}, mode {modestr}" )) from err
def _do_len_checksum(self): """ Calculate and format payload length and checksum as bytes.""" if self._payload is None: self._length = self.val2bytes(0, ubt.U2) self._checksum = calc_checksum(self._ubxClass + self._ubxID + self._length) else: self._length = self.val2bytes(len(self._payload), ubt.U2) self._checksum = calc_checksum( self._ubxClass + self._ubxID + self._length + self._payload )
def parse(message: bytes, *args, **kwargs) -> object: """ Parse UBX byte stream to UBXMessage object. Includes option to validate incoming payload length and checksum (the UBXMessage constructor can calculate and assign its own values anyway). :param bytes message: binary message to parse :param int validate: (kwarg) validate cksum (VALCKSUM (1)=True (default), VALNONE (0)=False) :param int msgmode: (kwarg) message mode (0=GET (default), 1=SET, 2=POLL) :return: UBXMessage object :rtype: UBXMessage :raises: UBXParseError (if data stream contains invalid data or unknown message type) """ msgmode = kwargs.get("msgmode", ubt.GET) validate = kwargs.get("validate", VALCKSUM) parsebf = kwargs.get("parsebitfield", True) decnavdat = kwargs.get("deocdenavdata", False) # accept args for backwards compatibility if no kwargs if len(kwargs) == 0: if len(args) > 0: validate = args[0] if len(args) > 1: msgmode = args[1] if msgmode not in (0, 1, 2): raise ube.UBXParseError( f"Invalid message mode {msgmode} - must be 0, 1 or 2") lenm = len(message) hdr = message[0:2] clsid = message[2:3] msgid = message[3:4] lenb = message[4:6] if lenb == b"\x00\x00": payload = None leni = 0 else: payload = message[6:lenm - 2] leni = len(payload) ckm = message[lenm - 2:lenm] if payload is not None: ckv = calc_checksum(clsid + msgid + lenb + payload) else: ckv = calc_checksum(clsid + msgid + lenb) if validate & VALCKSUM: if hdr != ubt.UBX_HDR: raise ube.UBXParseError((f"Invalid message header {hdr}" f" - should be {ubt.UBX_HDR}")) if leni != UBXMessage.bytes2val(lenb, ubt.U2): raise ube.UBXParseError( (f"Invalid payload length {lenb}" f" - should be {UBXMessage.val2bytes(leni, ubt.U2)}")) if ckm != ckv: raise ube.UBXParseError((f"Message checksum {ckm}" f" invalid - should be {ckv}")) try: if payload is None: return UBXMessage(clsid, msgid, msgmode) return UBXMessage(clsid, msgid, msgmode, payload=payload, parsebitfield=parsebf, decodenavdata=decnavdat) except KeyError as err: modestr = ["GET", "SET", "POLL"][msgmode] raise ube.UBXParseError(( f"Unknown message type clsid {clsid}, msgid {msgid}, mode {modestr}" )) from err
def testCalcChecksum(self): res = calc_checksum(b'\x06\x01\x02\x00\xf0\x05') self.assertEqual(res, b'\xfe\x16')