Exemplo n.º 1
0
    def test_calculation_crc_error2(self):
        # Frame with CRC error
        #                                                                **
        # B5 62 01 11 14 00 50 2b d7 11 01 00 00 00 00 00 00 00 01 00 00 4c 03 00 00 00 8e 2b
        # hdr  | <--                          checksum                             --> | chksum

        # Frame looks ok, except ecefVZ, guess 4c should be 00
        dut = Checksum()
        frame = [
            0x01, 0x11, 0x14, 0x00, 0x50, 0x2b, 0xd7, 0x11, 0x01, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4c, 0x03, 0x00,
            0x00, 0x00
        ]
        for byte in frame:
            dut.add(byte)

        assert dut.matches(0xda, 0xa7)  # Checksum for incorrect frame

        # Fix faulty byte at position 19: Wrong 0x4C, correct 0x00
        dut.reset()
        frame[19] = 0x00
        for byte in frame:
            dut.add(byte)

        print(f'{dut._cka:02x} {dut._ckb:02x}')
        assert dut.matches(0x8e, 0x2b)
Exemplo n.º 2
0
    def test_calculation_crc_error1(self):
        # Frame with CRC error
        #          **
        # B5 62 01 00 14 00 54 a0 06 0f 00 00 00 00 00 00 00 00 01 00 00 00 03 00 00 00 33 46
        # hdr  | <--                          checksum                             --> | chksum

        # No frame 0x01 0x00 found
        # 0x11 missing as ID could explain checksum difference 22bf vs 3346. Check with test
        dut = Checksum()
        frame = [
            0x01, 0x00, 0x14, 0x00, 0x54, 0xa0, 0x06, 0x0f, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00,
            0x00, 0x00
        ]
        for byte in frame:
            dut.add(byte)

        assert dut.matches(0x22, 0xBF)  # Checksum for incorrect frame

        # Fix faulty byte at position 1: Wrong 0x00, correct 0x11
        dut.reset()
        frame[1] = 0x11
        for byte in frame:
            dut.add(byte)

        # print(f'{dut._cka:02x} {dut._ckb:02x}')
        assert dut.matches(0x33, 0x46)
Exemplo n.º 3
0
    def test_calculation_crc_error3(self):
        # Frame with CRC error
        #
        # B5 62 01 01 14 00 54 a0 06 ff 02 4e 92 19 0f f6 94 03 a5 2c d0 1b 44 00 00 00 b6 b1
        # hdr  | <--                          checksum                             --> | chksum

        # iTOW of next messages is 54 a0 06 0f instead of .. .. .. ff
        dut = Checksum()
        frame = [
            0x01, 0x01, 0x14, 0x00, 0x54, 0xa0, 0x06, 0xff, 0x02, 0x4e, 0x92,
            0x19, 0x0f, 0xf6, 0x94, 0x03, 0xa5, 0x2c, 0xd0, 0x1b, 0x44, 0x00,
            0x00, 0x00
        ]
        for byte in frame:
            dut.add(byte)

        assert dut.matches(0xa6, 0xa1)  # Checksum for incorrect frame

        # Fix faulty byte at position 19: Wrong 0x4C, correct 0x00
        dut.reset()
        frame[7] = 0x0F
        for byte in frame:
            dut.add(byte)

        # print(f'{dut._cka:02x} {dut._ckb:02x}')
        assert dut.matches(0xb6, 0xb1)
Exemplo n.º 4
0
    def __init__(self, rx_queue):
        super().__init__()

        self.rx_queue = rx_queue
        self.checksum = Checksum()

        self._reset()
        self.state = __class__.State.INIT
Exemplo n.º 5
0
    def __init__(self, crc_error_cid):
        super().__init__()

        self.crc_error_cid = crc_error_cid
        self.rx_queue = list()
        self.wait_cids = None
        self.checksum = Checksum()
        self.frames_rx = 0
        self.state = __class__.State.INIT
        self._reset()
Exemplo n.º 6
0
    def test_reset(self):
        dut = Checksum()
        dut.add(0xF0)
        dut.add(0xE0)

        dut.reset()
        assert dut.matches(0x00, 0x00)
Exemplo n.º 7
0
    def test_calculation(self):
        # B5 62 13 40 18 00 10 00 00 12 E4 07 09 05 06 28 30 00 40 28 EF 0C 0A 00 00 00 00 00 00 00 51 AC
        # hdr  | <--                                 checksum                                  --> | chksum

        dut = Checksum()
        frame = [
            0x13,
            0x40,
            0x18,
            0x00,
            0x10,
            0x00,
            0x00,
            0x12,
            0xE4,
            0x07,
            0x09,
            0x05,
            0x06,
            0x28,
            0x30,
            0x00,
            0x40,
            0x28,
            0xEF,
            0x0C,
            0x0A,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
        ]
        for byte in frame:
            dut.add(byte)

        assert dut.matches(0x51, 0xAC)
Exemplo n.º 8
0
 def __init__(self):
     super().__init__()
     self.data = bytearray()
     # TODO: Do we need checksum as member?
     self.checksum = Checksum()
     self.f = Fields()
Exemplo n.º 9
0
class UbxFrame(object):
    CID = UbxCID(0, 0)
    NAME = 'UBX'

    SYNC_1 = 0xb5
    SYNC_2 = 0x62

    @classmethod
    def construct(cls, data):
        obj = cls()
        obj.data = data
        obj.unpack()
        return obj

    @classmethod
    def MATCHES(cls, cid):
        return cls.CID == cid

    def __init__(self):
        super().__init__()
        self.data = bytearray()
        # TODO: Do we need checksum as member?
        self.checksum = Checksum()
        self.f = Fields()

    def to_bytes(self):
        self._calc_checksum()

        msg = bytearray([UbxFrame.SYNC_1, UbxFrame.SYNC_2])
        msg.append(self.CID.cls)
        msg.append(self.CID.id)

        length = len(self.data)
        msg.append((length >> 0) % 0xFF)
        msg.append((length >> 8) % 0xFF)

        msg += self.data
        msg.append(self.cka)
        msg.append(self.ckb)

        return msg

    def get(self, name):
        return self.f.get(name)

    def pack(self):
        self.data = self.f.pack()

    def unpack(self):
        self.f.unpack(self.data)

    def _calc_checksum(self):
        self.checksum.reset()

        self.checksum.add(self.CID.cls)
        self.checksum.add(self.CID.id)

        length = len(self.data)
        self.checksum.add((length >> 0) & 0xFF)
        self.checksum.add((length >> 8) & 0xFF)

        for d in self.data:
            self.checksum.add(d)

        self.cka, self.ckb = self.checksum.value()

    def __str__(self):
        res = f'{self.NAME} {self.CID}'
        res += str(self.f)
        return res
Exemplo n.º 10
0
class UbxParser(object):
    """
    Parser that tries to extract UBX frames from arbitrary byte streams

    Byte streams can also be NMEA or other frames. Unfortunately,
    u-blox frame header also appears in NMEA frames (e.g. version
    information). Such data will be detected by a checksum error

    TODO: Do more elaborate parsing to filter out such data in advance
    """
    class State(Enum):
        """
        Parser states
        """
        INIT = 1
        SYNC = 2
        CLASS = 3
        ID = 4
        LEN1 = 5
        LEN2 = 6
        DATA = 7
        CRC1 = 8
        CRC2 = 9

    def __init__(self, rx_queue):
        super().__init__()

        self.rx_queue = rx_queue
        self.checksum = Checksum()

        self._reset()
        self.state = __class__.State.INIT

    def process(self, data):
        for d in data:
            if self.state == __class__.State.INIT:
                if d == UbxFrame.SYNC_1:
                    self.state = __class__.State.SYNC

            elif self.state == __class__.State.SYNC:
                if d == UbxFrame.SYNC_2:
                    self._reset()
                    self.state = __class__.State.CLASS
                else:
                    self.state = __class__.State.INIT

            elif self.state == __class__.State.CLASS:
                self.msg_class = d
                self.checksum.add(d)
                self.state = __class__.State.ID

            elif self.state == __class__.State.ID:
                self.msg_id = d
                self.checksum.add(d)
                self.state = __class__.State.LEN1

            elif self.state == __class__.State.LEN1:
                self.msg_len = d
                self.checksum.add(d)
                self.state = __class__.State.LEN2

            elif self.state == __class__.State.LEN2:
                self.msg_len = self.msg_len + (d * 256)
                self.checksum.add(d)
                # TODO: Handle case with len = 0 -> goto CRC directly
                # TODO: Handle case with unreasonable size
                self.ofs = 0
                self.state = __class__.State.DATA

            elif self.state == __class__.State.DATA:
                self.msg_data.append(d)
                self.checksum.add(d)
                self.ofs += 1
                if self.ofs == self.msg_len:
                    self.state = __class__.State.CRC1

            elif self.state == __class__.State.CRC1:
                self.cka = d
                self.state = __class__.State.CRC2

            elif self.state == __class__.State.CRC2:
                self.ckb = d

                # if checksum matches received checksum put frame in receive queue
                if self.checksum.matches(self.cka, self.ckb):
                    # Send CID and data as tuple to server
                    self.rx_queue.put((UbxCID(self.msg_class,
                                              self.msg_id), self.msg_data))
                else:
                    logger.warning(f'checksum error in frame, discarding')

                self._reset()
                self.state = __class__.State.INIT

    def _reset(self):
        self.msg_class = 0
        self.msg_id = 0
        self.msg_len = 0
        self.msg_data = bytearray()
        self.cka = 0
        self.ckb = 0
        self.ofs = 0

        self.checksum.reset()
Exemplo n.º 11
0
class UbxParser(object):
    """
    Parser that tries to extract UBX frames from arbitrary byte streams

    Byte streams can also be NMEA or other frames. Unfortunately,
    u-blox frame header also appears in NMEA frames (e.g. version
    information). Such data will be detected by a checksum error

    TODO: Do more elaborate parsing to filter out such data in advance
    """
    """ Maximum message length supported """
    MAX_MESSAGE_LENGTH = 1000

    class State(Enum):
        """ Parser states """
        INIT = 1
        SYNC = 2
        CLASS = 3
        ID = 4
        LEN1 = 5
        LEN2 = 6
        DATA = 7
        CRC1 = 8
        CRC2 = 9

    def __init__(self, crc_error_cid):
        super().__init__()

        self.crc_error_cid = crc_error_cid
        self.rx_queue = list()
        self.wait_cids = None
        self.checksum = Checksum()
        self.frames_rx = 0
        self.state = __class__.State.INIT
        self._reset()

    def restart(self):
        self.state = __class__.State.INIT

    def set_filter(self, cid):
        assert isinstance(cid, UbxCID)
        self.wait_cids = [cid]  # Put single filter in list

    def set_filters(self, cids):
        assert isinstance(cids, list)
        self.wait_cids = cids

    def empty_queue(self):
        self.rx_queue.clear()

    def packet(self):
        # Returns (cid, data) or (None, None)
        try:
            return self.rx_queue.pop(0)
        except IndexError:
            # No more frames to de-queue
            return (None, None)

    def process(self, data):
        for d in data:
            self._process_byte(d)

    def _process_byte(self, data):
        if self.state == __class__.State.INIT:
            self._state_init(data)
        elif self.state == __class__.State.SYNC:
            self._state_sync(data)
        elif self.state == __class__.State.CLASS:
            self._state_class(data)
        elif self.state == __class__.State.ID:
            self._state_id(data)
        elif self.state == __class__.State.LEN1:
            self._state_len1(data)
        elif self.state == __class__.State.LEN2:
            self._state_len2(data)
        elif self.state == __class__.State.DATA:
            self._state_data(data)
        elif self.state == __class__.State.CRC1:
            self._state_crc1(data)
        elif self.state == __class__.State.CRC2:
            self._state_crc2(data)

    def _state_init(self, d):
        if d == UbxFrame.SYNC_1:
            self.state = __class__.State.SYNC

    def _state_sync(self, d):
        if d == UbxFrame.SYNC_2:
            self._reset()
            self.state = __class__.State.CLASS
        else:
            self.state = __class__.State.INIT

    def _state_class(self, d):
        # TODO: Could add check for SYNC_1, SYNC_2 here, as both are not valid classes or IDs
        self.msg_class = d
        self.checksum.add(d)
        self.state = __class__.State.ID

    def _state_id(self, d):
        self.msg_id = d
        self.checksum.add(d)
        self.state = __class__.State.LEN1

    def _state_len1(self, d):
        self.msg_len = d
        self.checksum.add(d)
        self.state = __class__.State.LEN2

    def _state_len2(self, d):
        self.msg_len = self.msg_len + (d * 256)
        self.checksum.add(d)

        if self.msg_len == 0:
            self.state = __class__.State.CRC1
        elif self.msg_len > __class__.MAX_MESSAGE_LENGTH:
            logger.warning(f'invalid msg len {self.msg_len}')
            self.state = __class__.State.INIT
        else:
            self.ofs = 0
            self.state = __class__.State.DATA

    def _state_data(self, d):
        self.msg_data.append(d)
        self.checksum.add(d)
        self.ofs += 1

        if self.ofs == self.msg_len:
            self.state = __class__.State.CRC1

    def _state_crc1(self, d):
        self.cka = d
        self.state = __class__.State.CRC2

    def _state_crc2(self, d):
        self.ckb = d

        # if checksum matches received checksum ..
        if self.checksum.matches(self.cka, self.ckb):
            self.frames_rx += 1

            # .. and frame passes filter ..
            cid = UbxCID(self.msg_class, self.msg_id)

            if self.wait_cids and cid in self.wait_cids:
                # .. queue packet (CID and data)
                packet = (cid, self.msg_data)
                self.rx_queue.append(packet)
            else:
                if logger.isEnabledFor(logging.DEBUG):
                    logger.debug(
                        f'no match - dropping {cid}, {self.msg_len} bytes')
        else:
            logger.warning('checksum error in frame, discarding')
            logger.warning(
                f'{self.msg_class:02x} {self.msg_id:02x} {binascii.hexlify(self.msg_data)}'
            )

            crc_error_message = (self.crc_error_cid, None)
            self.rx_queue.append(crc_error_message)

        self.state = __class__.State.INIT

    def _reset(self):
        self.msg_class = 0
        self.msg_id = 0
        self.msg_len = 0
        self.msg_data = bytearray()
        self.cka = 0
        self.ckb = 0
        self.ofs = 0
        self.checksum.reset()
Exemplo n.º 12
0
 def test_creation(self):
     dut = Checksum()
     assert dut.matches(0x00, 0x00)