예제 #1
0
    def from_frames(self, frames, datatype_crc=None):
        # Ignore frame index for anonymous transfers since they can't be
        # multi-frame
        if frames[0].source_node_id:
            for i, f in enumerate(frames):
                if i != f.frame_index:
                    raise IndexError(("Frame index mismatch: expected {0}, " +
                                      "got {1}").format(i, f.frame_index))

        self.transfer_id = frames[0].transfer_id
        self.transfer_priority = frames[0].transfer_priority
        self.source_node_id = frames[0].source_node_id
        self.data_type_id = frames[0].data_type_id
        self.dest_node_id = frames[0].dest_node_id
        self.payload = sum((f.payload for f in frames), bytearray())
        self.request_not_response = frames[0].request_not_response
        self.broadcast_not_unicast = frames[0].broadcast_not_unicast

        # For a multi-frame transfer, validate the CRC and frame indexes
        if len(frames) > 1:
            transfer_crc = self.payload[0] + (self.payload[1] << 8)
            self.payload = self.payload[2:]
            crc = common.crc16_from_bytes(self.payload, initial=datatype_crc)
            if crc != transfer_crc:
                raise ValueError(("CRC mismatch: expected {0:x}, got {1:x} " +
                                  "for payload {2!r} (DTID {3:d})").format(
                                  crc, transfer_crc, self.payload,
                                  self.data_type_id))
예제 #2
0
    def to_frames(self):
        out_frames = []
        remaining_payload = self.payload

        # Prepend the transfer CRC to the payload if the transfer requires
        # multiple frames
        if len(remaining_payload) > 7:
            crc = common.crc16_from_bytes(self.payload,
                                          initial=self.data_type_crc)
            remaining_payload = bytearray([crc & 0xFF, crc >> 8
                                           ]) + remaining_payload

        # Generate the frame sequence
        tail = 0x20  # set toggle bit high so the first frame is emitted with it cleared
        while True:
            # Tail byte contains start-of-transfer, end-of-transfer, toggle, and Transfer ID
            tail = ((0x80 if len(out_frames) == 0 else 0) |
                    (0x40 if len(remaining_payload) <= 7 else 0) |
                    ((tail ^ 0x20) & 0x20) | (self.transfer_id & 0x1F))
            out_frames.append(
                Frame(message_id=self.message_id,
                      data=remaining_payload[0:7] + bchr(tail)))
            remaining_payload = remaining_payload[7:]
            if not remaining_payload:
                break

        return out_frames
예제 #3
0
    def to_frames(self):
        out_frames = []
        remaining_payload = self.payload

        # Prepend the transfer CRC to the payload if the transfer requires
        # multiple frames
        if len(remaining_payload) > 7:
            crc = common.crc16_from_bytes(self.payload,
                                          initial=self.data_type_crc)
            remaining_payload = bytearray([crc & 0xFF, crc >> 8]) + remaining_payload

        # Generate the frame sequence
        tail = 0x20  # set toggle bit high so the first frame is emitted with it cleared
        while True:
            # Tail byte contains start-of-transfer, end-of-transfer, toggle, and Transfer ID
            tail = ((0x80 if len(out_frames) == 0 else 0) |
                    (0x40 if len(remaining_payload) <= 7 else 0) |
                    ((tail ^ 0x20) & 0x20) |
                    (self.transfer_id & 0x1F))
            out_frames.append(Frame(message_id=self.message_id, data=remaining_payload[0:7] + bchr(tail)))
            remaining_payload = remaining_payload[7:]
            if not remaining_payload:
                break

        return out_frames
예제 #4
0
    def from_frames(self, frames):
        # Initialize transfer timestamps from the first frame
        self.ts_monotonic = frames[0].ts_monotonic
        self.ts_real = frames[0].ts_real

        # Validate the flags in the tail byte
        expected_toggle = 0
        expected_transfer_id = frames[0].bytes[-1] & 0x1F
        for idx, f in enumerate(frames):
            tail = f.bytes[-1]
            if (tail & 0x1F) != expected_transfer_id:
                raise TransferError("Transfer ID {0} incorrect, expected {1}".format(tail & 0x1F, expected_transfer_id))
            elif idx == 0 and not (tail & 0x80):
                raise TransferError("Start of transmission not set on frame 0")
            elif idx > 0 and tail & 0x80:
                raise TransferError("Start of transmission set unexpectedly on frame {0}".format(idx))
            elif idx == len(frames) - 1 and not (tail & 0x40):
                raise TransferError("End of transmission not set on last frame")
            elif idx < len(frames) - 1 and (tail & 0x40):
                raise TransferError("End of transmission set unexpectedly on frame {0}".format(idx))
            elif (tail & 0x20) != expected_toggle:
                raise TransferError("Toggle bit value {0} incorrect on frame {1}".format(tail & 0x20, idx))

            expected_toggle ^= 0x20

        self.transfer_id = expected_transfer_id
        self.message_id = frames[0].message_id
        payload_bytes = bytearray(b''.join(bytes(f.bytes[0:-1]) for f in frames))

        # Find the data type
        if self.service_not_message:
            kind = dsdl.CompoundType.KIND_SERVICE
        else:
            kind = dsdl.CompoundType.KIND_MESSAGE
        datatype = uavcan.DATATYPES.get((self.data_type_id, kind))
        if not datatype:
            raise TransferError("Unrecognised {0} type ID {1}"
                                .format("service" if self.service_not_message else "message", self.data_type_id))

        # For a multi-frame transfer, validate the CRC and frame indexes
        if len(frames) > 1:
            transfer_crc = payload_bytes[0] + (payload_bytes[1] << 8)
            payload_bytes = payload_bytes[2:]
            crc = common.crc16_from_bytes(payload_bytes, initial=datatype.base_crc)
            if crc != transfer_crc:
                raise TransferError("CRC mismatch: expected {0:x}, got {1:x} for payload {2!r} (DTID {3:d})"
                                    .format(crc, transfer_crc, payload_bytes, self.data_type_id))

        self.data_type_id = datatype.default_dtid
        self.data_type_signature = datatype.get_data_type_signature()
        self.data_type_crc = datatype.base_crc

        if self.service_not_message:
            self.payload = datatype(_mode="request" if self.request_not_response else "response")
        else:
            self.payload = datatype()

        # noinspection PyProtectedMember
        self.payload._unpack(bits_from_bytes(payload_bytes))
예제 #5
0
    def to_frames(self, datatype_crc=None):
        # Broadcast frames support up to 8 bytes, other frames have a
        # destination node ID which consumes the first byte of the message
        if self.dest_node_id is None:
            bytes_per_frame = 8
        else:
            bytes_per_frame = 7

        out_frames = []
        remaining_payload = self.payload

        # Prepend the transfer CRC to the payload if the transfer requires
        # multiple frames
        if len(remaining_payload) > bytes_per_frame:
            crc = common.crc16_from_bytes(self.payload, initial=datatype_crc)
            remaining_payload = bytearray([crc & 0xFF, crc >> 8]) + \
                                remaining_payload

        # Generate the frame sequence
        while True:
            frame = Frame(message_id=0)
            frame.transfer_priority = self.transfer_priority
            frame.transfer_id = self.transfer_id
            frame.frame_index = len(out_frames)
            frame.last_frame = len(remaining_payload) <= bytes_per_frame
            frame.source_node_id = self.source_node_id
            frame.data_type_id = self.data_type_id
            frame.dest_node_id = self.dest_node_id
            frame.payload = remaining_payload[0:bytes_per_frame]
            frame.request_not_response = self.request_not_response
            frame.broadcast_not_unicast = False if self.dest_node_id else True

            out_frames.append(frame)
            remaining_payload = remaining_payload[bytes_per_frame:]
            if not remaining_payload:
                break

        return out_frames
예제 #6
0
 def test_bytearray(self):
     self.assertEqual(
         common.crc16_from_bytes(bytearray('123456789', 'utf-8')),
         0x29B1)
예제 #7
0
 def test_bytes(self):
     self.assertEqual(common.crc16_from_bytes(b'123456789'), 0x29B1)
예제 #8
0
 def test_str(self):
     self.assertEqual(common.crc16_from_bytes("123456789"), 0x29B1)
예제 #9
0
 def test_bytearray(self):
     self.assertEqual(common.crc16_from_bytes(bytearray("123456789", "utf-8")), 0x29B1)