Ejemplo n.º 1
0
 def decode(self, byte_str):
     """ Checks if byte_str is the literal """
     if byte_str != self.literal:
         raise ValueError('Byte array does not match literal: expected %s, got %s' %
                              (printable(self.literal), printable(byte_str)))
     else:
         return ""
Ejemplo n.º 2
0
    def consume_response_payload(
            self, payload):  # type: (bytearray) -> Dict[str, Any]
        """
        Consumes the payload bytes

        :param payload Payload from the Core response
        :returns: Dictionary containing the parsed response
        """
        payload_length = len(payload)
        result = {}
        for field in self.response_fields:
            if field.length is None:
                continue
            field_length = field.length  # type: Union[int, Callable[[int], int]]
            if callable(field_length):
                field_length = field_length(payload_length)
            if len(payload) < field_length:
                logger.warning(
                    'Payload for instruction {0} did not contain all the expected data: {1}'
                    .format(self.instruction, printable(payload)))
                break
            data = payload[:field_length]
            if not isinstance(field, PaddingField):
                result[field.name] = field.decode(data)
            payload = payload[field_length:]
        if payload != bytearray():
            logger.warning(
                'Payload for instruction {0} could not be consumed completely: {1}'
                .format(self.instruction, printable(payload)))
        return result
Ejemplo n.º 3
0
    def consume_response_payload(self, payload):
        """
        Consumes the payload bytes

        :param payload Payload from the uCAN responses
        :type payload: list of int
        :returns: Dictionary containing the parsed response
        :rtype: dict
        """
        payload_data = []
        for response_hash in self.headers:
            # Headers are ordered
            if response_hash not in payload:
                logger.warning(
                    'Payload did not contain all the expected data: {0}'.
                    format(printable(payload)))
                return None
            response_instruction = self._response_instruction_by_hash[
                response_hash]
            payload_entry = payload[response_hash]
            crc = payload_entry[response_instruction.checksum_byte]
            expected_crc = UCANCommandSpec.calculate_crc(
                payload_entry[:response_instruction.checksum_byte])
            if crc != expected_crc:
                logger.info('Unexpected CRC ({0} vs expected {1}): {2}'.format(
                    crc, expected_crc, printable(payload_entry)))
                return None
            usefull_payload = payload_entry[
                self.header_length:response_instruction.checksum_byte]
            payload_data += usefull_payload
        return self._parse_payload(payload_data)
Ejemplo n.º 4
0
    def consume_response_payload(self, payload):
        """
        Consumes the payload bytes

        :param payload Payload from the Core response
        :type payload: str
        :returns: Dictionary containing the parsed response
        :rtype: dict
        """
        payload_length = len(payload)
        result = {}
        for field in self.response_fields:
            field_length = field.length
            if callable(field_length):
                field_length = field_length(payload_length)
            if len(payload) < field_length:
                logger.warning(
                    'Payload for instruction {0} did not contain all the expected data: {1}'
                    .format(self.instruction, printable(payload)))
                break
            data = payload[:field_length]
            if not isinstance(field, PaddingField):
                result[field.name] = field.decode(data)
            payload = payload[field_length:]
        if payload != '':
            logger.warning(
                'Payload for instruction {0} could not be consumed completely: {1}'
                .format(self.instruction, printable(payload)))
        return result
Ejemplo n.º 5
0
 def write(self, data):
     # type: (bytes) -> int
     if data != self._sequence[0]:
         assert printable(self._sequence[0]) == printable(data)
     self._sequence.pop(0)
     if self._replies:
         self.fd.write(self._replies[0])
         self._replies.pop(0)
     return len(data)
Ejemplo n.º 6
0
    def write(self, data):
        """ Write data to serial port """
        while self.__sequence[0][0] == 'o':
            time.sleep(0.01)

        if data != self.__sequence[0][1]:
            raise Exception("Got wrong data in SerialMock: expected %s, got %s",
                            (printable(self.__sequence[0][1]), printable(data)))
        self.__sequence.pop(0)
        self.bytes_written += len(data)
Ejemplo n.º 7
0
    def write(self, data):
        """ Write data to serial port """
        while self.__sequence[0][0] == 'o':
            time.sleep(0.01)

        if data != self.__sequence[0][1]:
            raise Exception(
                "Got wrong data in SerialMock: expected %s, got %s",
                (printable(self.__sequence[0][1]), printable(data)))
        self.__sequence.pop(0)
        self.bytes_written += len(data)
Ejemplo n.º 8
0
    def write(self, data):
        # type: (bytes) -> None
        """ Write data to serial port """
        while self.__sequence[0][0] == 'o':
            time.sleep(0.01)

        if bytearray(data) != self.__sequence[0][1]:
            raise Exception(
                "Got wrong data in SerialMock:\n  expected %s,\n       got %s"
                % (printable(self.__sequence[0][1]), printable(data)))
        self.__sequence.pop(0)
        self.bytes_written += len(data)
Ejemplo n.º 9
0
    def _write_to_serial(self, data):
        """
        Write data to the serial port.

        :param data: the data to write
        :type data: string
        """
        with self._serial_write_lock:
            if self._verbose:
                logger.info('Writing to Core serial:   {0}'.format(
                    printable(data)))

            threshold = time.time() - self._debug_buffer_duration
            self._debug_buffer['write'][time.time()] = printable(data)
            for t in self._debug_buffer['write'].keys():
                if t < threshold:
                    del self._debug_buffer['write'][t]

            self._serial.write(data)
            self._serial_bytes_written += len(data)
            self._communication_stats['bytes_written'] += len(data)
Ejemplo n.º 10
0
    def __write_to_serial(self, data):
        # type: (bytearray) -> None
        """ Write data to the serial port.

        :param data: the data to write
        """
        self.__debug('writing to', data)
        self.__serial.write(data)
        self.__communication_stats_bytes['bytes_written'] += len(data)
        threshold = time.time() - self.__debug_buffer_duration
        self.__debug_buffer['write'][time.time()] = printable(data)
        for t in self.__debug_buffer['write'].keys():
            if t < threshold:
                del self.__debug_buffer['write'][t]
Ejemplo n.º 11
0
    def consume_response_payload(self, payload):
        """
        Consumes the payload bytes

        :param payload Payload from the uCAN responses
        :type payload: list of int
        :returns: Dictionary containing the parsed response
        :rtype: dict
        """
        crc = UCANPalletCommandSpec.calculate_crc(payload)
        if crc != 0:
            logger.info('Unexpected pallet CRC ({0} != 0): {1}'.format(crc, printable(payload)))
            return None
        return self._parse_payload(payload[7:-4])
Ejemplo n.º 12
0
    def __write_to_serial(self, data):
        """ Write data to the serial port.

        :param data: the data to write
        :type data: string
        """
        if self.__verbose:
            PowerCommunicator.__log('writing to', data)
        self.__serial.write(data)
        self.__communication_stats['bytes_written'] += len(data)
        threshold = time.time() - self.__debug_buffer_duration
        self.__debug_buffer['write'][time.time()] = printable(data)
        for t in self.__debug_buffer['write'].keys():
            if t < threshold:
                del self.__debug_buffer['write'][t]
Ejemplo n.º 13
0
    def consume_response_payload(
        self, payload
    ):  # type: (Union[bytearray, Dict[int, bytearray]]) -> Optional[Dict[str, Any]]
        """
        Consumes the payload bytes

        :param payload Payload from the uCAN responses
        :returns: Dictionary containing the parsed response
        """
        if isinstance(payload, bytearray):
            raise RuntimeError(
                'An UCANCommandSpec cannot consume bytearray payloads')
        payload_data = bytearray()
        for response_hash in self.headers:
            # Headers are ordered
            if response_hash not in payload:
                logger.warning(
                    'Payload did not contain all the expected data: {0}'.
                    format(printable(payload)))
                return None
            response_instruction = self._response_instruction_by_hash[
                response_hash]
            payload_entry = payload[response_hash]
            if response_instruction.checksum_byte is None:
                raise RuntimeError('Unknown checksum byte')
            crc = payload_entry[response_instruction.checksum_byte]
            expected_crc = UCANCommandSpec.calculate_crc(
                payload_entry[:response_instruction.checksum_byte])
            if crc != expected_crc:
                logger.info('Unexpected CRC ({0} vs expected {1}): {2}'.format(
                    crc, expected_crc, printable(payload_entry)))
                return None
            usefull_payload = payload_entry[
                self.header_length:response_instruction.checksum_byte]
            payload_data += usefull_payload
        return self._parse_payload(payload_data)
Ejemplo n.º 14
0
 def consume_response_payload(
         self, payload):  # type: (bytearray) -> Optional[Dict[str, Any]]
     """ Consumes the payload bytes """
     crc = SlaveCommandSpec.decode_crc(
         payload[-(self._response_footer_length -
                   1):-len(SlaveCommandSpec.RESPONSE_SUFFIX)])
     expected_crc = SlaveCommandSpec.decode_crc(
         SlaveCommandSpec.calculate_crc(
             payload[self._response_prefix_length:-self.
                     _response_footer_length]))
     if crc != expected_crc:
         logger.info('Unexpected CRC ({0} vs expected {1}): {2}'.format(
             crc, expected_crc, printable(payload)))
         return None
     payload_data = payload[self.header_length +
                            self._instruction_length:-self.
                            _response_footer_length]
     return self._parse_payload(payload_data)
Ejemplo n.º 15
0
    def consume_response_payload(
        self, payload
    ):  # type: (Union[bytearray, Dict[int, bytearray]]) -> Optional[Dict[str, Any]]
        """
        Consumes the payload bytes

        :param payload Payload from the uCAN responses
        :returns: Dictionary containing the parsed response
        """
        if not isinstance(payload, bytearray):
            raise RuntimeError(
                'UCANPalletCommandSpec can only consume bytearray payloads')
        crc = UCANPalletCommandSpec.calculate_crc(payload)
        if crc != 0:
            logger.info('Unexpected pallet CRC ({0} != 0): {1}'.format(
                crc, printable(payload)))
            return None
        return self._parse_payload(payload[7:-4])
Ejemplo n.º 16
0
 def _parse_payload(self, payload_data):
     result = {}
     payload_length = len(payload_data)
     for field in self._response_fields:
         if isinstance(field, StringField):
             field_length = payload_data.index(0) + 1
         else:
             field_length = field.length
         if callable(field_length):
             field_length = field_length(payload_length)
         if len(payload_data) < field_length:
             logger.warning(
                 'Payload did not contain all the expected data: {0}'.
                 format(printable(payload_data)))
             break
         data = payload_data[:field_length]
         if not isinstance(field, PaddingField):
             result[field.name] = field.decode_bytes(data)
         payload_data = payload_data[field_length:]
     return result
Ejemplo n.º 17
0
 def _parse_payload(self,
                    payload_data):  # type: (bytearray) -> Dict[str, Any]
     result = {}
     payload_length = len(payload_data)
     for field in self.response_fields:
         if field.length is None:
             continue
         field_length = field.length  # type: Union[int, Callable[[int], int]]
         if callable(field_length):
             field_length = field_length(payload_length)
         if len(payload_data) < field_length:
             logger.warning(
                 'Payload did not contain all the expected data: {0}'.
                 format(printable(payload_data)))
             break
         data = payload_data[:field_length]  # type: bytearray
         if not isinstance(field, PaddingField):
             result[field.name] = field.decode(data)
         payload_data = payload_data[field_length:]
     return result
Ejemplo n.º 18
0
    def do_command(self, address, command, fields, timeout=2):
        # type: (str, SlaveCommandSpec, Dict[str, Any], Optional[int]) -> Optional[Dict[str, Any]]
        """
        Send an slave command over the Communicator and block until an answer is received.
        If the Core does not respond within the timeout period, a CommunicationTimedOutException is raised
        """
        if not self._transparent_mode:
            raise RuntimeError('Transparent mode not active.')

        command.set_address(address)

        consumer = Consumer(command)
        self.register_consumer(consumer)

        master_timeout = False
        payload = command.create_request_payload(fields)
        if self._verbose:
            logger.info(
                'Writing to slave transport:   Address: {0} - Data: {1}'.
                format(address, printable(payload)))
        try:
            self._communicator.do_command(
                command=CoreAPI.slave_tx_transport_message(len(payload)),
                fields={'payload': payload},
                timeout=timeout)
        except CommunicationTimedOutException as ex:
            logger.error(
                'Internal timeout during slave transport: {0}'.format(ex))
            master_timeout = True

        try:
            if master_timeout:
                # When there's a communication timeout with the master, catch this exception and timeout the consumer
                # so it uses a flow expected by the caller
                return consumer.get(0)
            if timeout is not None and not consumer.send_only():
                return consumer.get(timeout)
        except CommunicationTimedOutException:
            self.unregister_consumer(consumer)
            raise
        return None
Ejemplo n.º 19
0
    def _process_transport_message(self, package):
        payload = package['payload']
        if self._verbose:
            logger.info('Reading from slave transport: Data: {0}'.format(
                printable(payload)))

        self._read_buffer += payload
        if SlaveCommandSpec.RESPONSE_PREFIX not in self._read_buffer:
            return

        index = self._read_buffer.index(SlaveCommandSpec.RESPONSE_PREFIX)
        if index > 0:
            self._read_buffer = self._read_buffer[index:]

        consumed_bytes = 0
        for consumer in self._consumers[:]:
            consumed_bytes = consumer.suggest_payload(self._read_buffer)
            if consumed_bytes > 0:
                self.unregister_consumer(consumer)
                break
        self._read_buffer = self._read_buffer[
            max(len(SlaveCommandSpec.RESPONSE_PREFIX), consumed_bytes):]
Ejemplo n.º 20
0
 def __debug(self, action, data):
     # type: (str, Optional[bytearray]) -> None
     if self.__verbose and data is not None:
         logger.debug("%.3f %s power: %s" %
                      (time.time(), action, printable(data)))
Ejemplo n.º 21
0
    def __read_from_serial(self):
        """ Read a PowerCommand from the serial port. """
        phase = 0
        index = 0

        header = ""
        length = 0
        data = ""
        crc = 0

        command = ""

        try:
            while phase < 8:
                byte = self.__serial.read_queue.get(True, 0.25)
                command += byte
                self.__communication_stats['bytes_read'] += 1

                if phase == 0:  # Skip non 'R' bytes
                    if byte == 'R':
                        phase = 1
                    else:
                        phase = 0
                elif phase == 1:  # Expect 'T'
                    if byte == 'T':
                        phase = 2
                    else:
                        raise Exception("Unexpected character")
                elif phase == 2:  # Expect 'R'
                    if byte == 'R':
                        phase = 3
                        index = 0
                    else:
                        raise Exception("Unexpected character")
                elif phase == 3:  # Read the header fields
                    header += byte
                    index += 1
                    if index == 8:
                        length = ord(byte)
                        if length > 0:
                            phase = 4
                            index = 0
                        else:
                            phase = 5
                elif phase == 4:  # Read the data
                    data += byte
                    index += 1
                    if index == length:
                        phase = 5
                elif phase == 5:  # Read the CRC code
                    crc = ord(byte)
                    phase = 6
                elif phase == 6:  # Expect '\r'
                    if byte == '\r':
                        phase = 7
                    else:
                        raise Exception("Unexpected character")
                elif phase == 7:  # Expect '\n'
                    if byte == '\n':
                        phase = 8
                    else:
                        raise Exception("Unexpected character")
            crc_match = (crc7(header + data)
                         == crc) if header[0] == 'E' else (crc8(data) == crc)
            if not crc_match:
                raise Exception('CRC{0} doesn\'t match'.format(
                    '7' if header[0] == 'E' else '8'))
        except Empty:
            raise CommunicationTimedOutException('Communication timed out')
        finally:
            if self.__verbose:
                PowerCommunicator.__log('reading from', command)

        threshold = time.time() - self.__debug_buffer_duration
        self.__debug_buffer['read'][time.time()] = printable(command)
        for t in self.__debug_buffer['read'].keys():
            if t < threshold:
                del self.__debug_buffer['read'][t]

        return header, data
Ejemplo n.º 22
0
    def _read(self):
        """
        Code for the background read thread: reads from the serial port and forward certain messages to waiting
        consumers

        Request format: 'STR' + {CID, 1 byte} + {command, 2 bytes} + {length, 2 bytes} + {payload, `length` bytes} + 'C' + {checksum, 1 byte} + '\r\n\r\n'
        Response format: 'RTR' + {CID, 1 byte} + {command, 2 bytes} + {length, 2 bytes} + {payload, `length` bytes} + 'C' + {checksum, 1 byte} + '\r\n'

        """
        data = bytearray()
        message_length = None
        header_fields = None
        header_length = len(
            CoreCommunicator.START_OF_REPLY
        ) + 1 + 2 + 2  # RTR + CID (1 byte) + command (2 bytes) + length (2 bytes)
        footer_length = 1 + 1 + len(
            CoreCommunicator.END_OF_REPLY)  # 'C' + checksum (1 byte) + \r\n
        need_more_data = False

        while not self._stop:
            try:
                # Wait for data if more data is expected
                if need_more_data:
                    readers, _, _ = select.select([self._serial], [], [], 1)
                    if not readers:
                        continue
                    need_more_data = False

                # Read what's now on the serial port
                num_bytes = self._serial.inWaiting()
                if num_bytes > 0:
                    data += self._serial.read(num_bytes)
                    # Update counters
                    self._serial_bytes_read += num_bytes
                    self._communication_stats['bytes_read'] += num_bytes

                # Wait for the full message, or the header length
                min_length = message_length or header_length
                if len(data) < min_length:
                    need_more_data = True
                    continue

                if message_length is None:
                    # Check if the data contains the START_OF_REPLY
                    if CoreCommunicator.START_OF_REPLY not in data:
                        need_more_data = True
                        continue

                    # Align with START_OF_REPLY
                    if not data.startswith(CoreCommunicator.START_OF_REPLY):
                        data = CoreCommunicator.START_OF_REPLY + data.split(
                            CoreCommunicator.START_OF_REPLY, 1)[-1]
                        if len(data) < header_length:
                            continue

                    header_fields = CoreCommunicator._parse_header(data)
                    message_length = header_fields[
                        'length'] + header_length + footer_length

                    # If not all data is present, wait for more data
                    if len(data) < message_length:
                        continue

                message = data[:message_length]  # type: bytearray
                data = data[message_length:]

                # A possible message is received, log where appropriate
                if self._verbose:
                    logger.debug('Reading from Core serial: {0}'.format(
                        printable(message)))
                threshold = time.time() - self._debug_buffer_duration
                self._debug_buffer['read'][time.time()] = message
                for t in self._debug_buffer['read'].keys():
                    if t < threshold:
                        del self._debug_buffer['read'][t]

                # Validate message boundaries
                correct_boundaries = message.startswith(
                    CoreCommunicator.START_OF_REPLY) and message.endswith(
                        CoreCommunicator.END_OF_REPLY)
                if not correct_boundaries:
                    logger.info('Unexpected boundaries: {0}'.format(
                        printable(message)))
                    # Reset, so we'll wait for the next RTR
                    message_length = None
                    data = message[
                        3:] + data  # Strip the START_OF_REPLY, and restore full data
                    continue

                # Validate message CRC
                crc = bytearray([message[-3]])
                payload = message[8:-4]  # type: bytearray
                checked_payload = message[3:-4]  # type: bytearray
                expected_crc = CoreCommunicator._calculate_crc(checked_payload)
                if crc != expected_crc:
                    logger.info(
                        'Unexpected CRC ({0} vs expected {1}): {2}'.format(
                            crc, expected_crc, printable(checked_payload)))
                    # Reset, so we'll wait for the next RTR
                    message_length = None
                    data = message[
                        3:] + data  # Strip the START_OF_REPLY, and restore full data
                    continue

                # A valid message is received, reliver it to the correct consumer
                consumers = self._consumers.get(header_fields['hash'], [])
                for consumer in consumers[:]:
                    if self._verbose:
                        logger.debug(
                            'Delivering payload to consumer {0}.{1}: {2}'.
                            format(header_fields['command'],
                                   header_fields['cid'], printable(payload)))
                    consumer.consume(payload)
                    if isinstance(consumer, Consumer):
                        self.unregister_consumer(consumer)

                self.discard_cid(header_fields['cid'])

                # Message processed, cleaning up
                message_length = None
            except Exception:
                logger.exception('Unexpected exception at Core read thread')
                data = bytearray()
                message_length = None
Ejemplo n.º 23
0
 def process(buffer):
     return {k: printable(v) for k, v in six.iteritems(buffer)}
Ejemplo n.º 24
0
 def __log(action, data):
     if data is not None:
         LOGGER.info("%.3f %s power: %s" % (time.time(), action, printable(data)))
Ejemplo n.º 25
0
    def _read(self):
        """
        Code for the background read thread: reads from the serial port and forward certain messages to waiting
        consumers

        Request format: 'STR' + {CID, 1 byte} + {command, 2 bytes} + {length, 2 bytes} + {payload, `length` bytes} + 'C' + {checksum, 1 byte} + '\r\n\r\n'
        Response format: 'RTR' + {CID, 1 byte} + {command, 2 bytes} + {length, 2 bytes} + {payload, `length` bytes} + 'C' + {checksum, 1 byte} + '\r\n'

        """
        data = ''
        wait_for_length = None
        header_length = len(
            CoreCommunicator.START_OF_REPLY
        ) + 1 + 2 + 2  # RTR + CID (1 byte) + command (2 bytes) + length (2 bytes)
        footer_length = 1 + 1 + len(
            CoreCommunicator.END_OF_REPLY)  # 'C' + checksum (1 byte) + \r\n

        while not self._stop:

            # Read what's now on the buffer
            num_bytes = self._serial.inWaiting()
            if num_bytes > 0:
                data += self._serial.read(num_bytes)

            # Update counters
            self._serial_bytes_read += num_bytes
            self._communication_stats['bytes_read'] += num_bytes

            # Wait for a speicific number of bytes, or the header length
            if (wait_for_length is None and
                    len(data) < header_length) or len(data) < wait_for_length:
                continue

            # Check if the data contains the START_OF_REPLY
            if CoreCommunicator.START_OF_REPLY not in data:
                continue

            if wait_for_length is None:
                # Flush everything before the START_OF_REPLY
                data = CoreCommunicator.START_OF_REPLY + data.split(
                    CoreCommunicator.START_OF_REPLY, 1)[-1]
                if len(data) < header_length:
                    continue  # Not enough data

            header_fields = CoreCommunicator._parse_header(data)
            message_length = header_fields[
                'length'] + header_length + footer_length

            # If not all data is present, wait for more data
            if len(data) < message_length:
                wait_for_length = message_length
                continue

            message = data[:message_length]
            data = data[message_length:]

            # A possible message is received, log where appropriate
            if self._verbose:
                logger.info('Reading from Core serial: {0}'.format(
                    printable(message)))
            threshold = time.time() - self._debug_buffer_duration
            self._debug_buffer['read'][time.time()] = printable(message)
            for t in self._debug_buffer['read'].keys():
                if t < threshold:
                    del self._debug_buffer['read'][t]

            # Validate message boundaries
            correct_boundaries = message.startswith(
                CoreCommunicator.START_OF_REPLY) and message.endswith(
                    CoreCommunicator.END_OF_REPLY)
            if not correct_boundaries:
                logger.info('Unexpected boundaries: {0}'.format(
                    printable(message)))
                # Reset, so we'll wait for the next RTR
                wait_for_length = None
                data = message[
                    3:] + data  # Strip the START_OF_REPLY, and restore full data
                continue

            # Validate message CRC
            crc = ord(message[-3])
            payload = message[8:-4]
            checked_payload = message[3:-4]
            expected_crc = CoreCommunicator._calculate_crc(checked_payload)
            if crc != expected_crc:
                logger.info('Unexpected CRC ({0} vs expected {1}): {2}'.format(
                    crc, expected_crc, printable(checked_payload)))
                # Reset, so we'll wait for the next RTR
                wait_for_length = None
                data = message[
                    3:] + data  # Strip the START_OF_REPLY, and restore full data
                continue

            # A valid message is received, reliver it to the correct consumer
            consumers = self._consumers.get(header_fields['header'], [])
            for consumer in consumers[:]:
                if self._verbose:
                    logger.info(
                        'Delivering payload to consumer {0}.{1}: {2}'.format(
                            header_fields['command'], header_fields['cid'],
                            printable(payload)))
                consumer.consume(payload)
                if isinstance(consumer, Consumer):
                    self.unregister_consumer(consumer)

            # Message processed, cleaning up
            wait_for_length = None
Ejemplo n.º 26
0
 def decode(self, byte_str):
     """ Checks if byte_str is the literal """
     if byte_str != self.literal:
         raise ValueError('Byte array does not match literal: expected %s, got %s' % (printable(self.literal), printable(byte_str)))
     else:
         return ""
Ejemplo n.º 27
0
 def __log(self, action, data):
     if data is not None:
         LOGGER.info("%.3f %s power: %s" %
                     (time.time(), action, printable(data)))
Ejemplo n.º 28
0
    def do_command(self, cc_address, command, identity, fields, timeout=2):
        """
        Send a uCAN command over the Communicator and block until an answer is received.
        If the Core does not respond within the timeout period, a CommunicationTimedOutException is raised

        :param cc_address: An address of the CC connected to the uCAN
        :type cc_address: str
        :param command: specification of the command to execute
        :type command: master_core.ucan_command.UCANCommandSpec
        :param identity: The identity
        :type identity: str
        :param fields: A dictionary with the command input field values
        :type fields dict
        :param timeout: maximum allowed time before a CommunicationTimedOutException is raised
        :type timeout: int or None
        :raises: serial_utils.CommunicationTimedOutException
        :returns: dict containing the output fields of the command
        """
        if self._cc_pallet_mode.get(cc_address, False) is True:
            raise BootloadingException('CC {0} is currently bootloading'.format(cc_address))

        command.set_identity(identity)

        if command.sid == SID.BOOTLOADER_PALLET:
            consumer = PalletConsumer(cc_address, command, self._release_pallet_mode)
            self._cc_pallet_mode[cc_address] = True
        else:
            consumer = Consumer(cc_address, command)
        self.register_consumer(consumer)

        master_timeout = False
        for payload in command.create_request_payloads(identity, fields):
            if self._verbose:
                logger.info('Writing to uCAN transport:   CC {0} - SID {1} - Data: {2}'.format(cc_address, command.sid, printable(payload)))
            try:
                self._communicator.do_command(command=CoreAPI.ucan_tx_transport_message(),
                                              fields={'cc_address': cc_address,
                                                      'nr_can_bytes': len(payload),
                                                      'sid': command.sid,
                                                      'payload': payload + [0] * (8 - len(payload))},
                                              timeout=timeout)
            except CommunicationTimedOutException as ex:
                logger.error('Internal timeout during uCAN transport to CC {0}: {1}'.format(cc_address, ex))
                master_timeout = True
                break

        consumer.check_send_only()
        if master_timeout:
            # When there's a communication timeout with the master, catch this exception and timeout the consumer
            # so it uses a flow expected by the caller
            return consumer.get(0)
        if timeout is not None:
            return consumer.get(timeout)
Ejemplo n.º 29
0
    def _process_transport_message(self, package):
        payload_length = package['nr_can_bytes']
        payload = package['payload'][:payload_length]
        sid = package['sid']
        cc_address = package['cc_address']
        if self._verbose:
            logger.info('Reading from uCAN transport: CC {0} - SID {1} - Data: {2}'.format(cc_address, sid, printable(payload)))

        consumers = self._consumers.get(cc_address, [])
        for consumer in consumers[:]:
            if consumer.suggest_payload(payload):
                self.unregister_consumer(consumer)
Ejemplo n.º 30
0
    def __read_from_serial(self):
        # type: () -> Tuple[bytearray, bytearray]
        """ Read a PowerCommand from the serial port. """
        phase = 0
        index = 0

        header = bytearray()
        length = 0
        data = bytearray()
        crc = 0

        command = bytearray()

        try:
            while phase < 8:
                byte = self.__serial.read_queue.get(True, 0.25)
                command += byte
                self.__communication_stats_bytes['bytes_read'] += 1

                if phase == 0:  # Skip non 'R' bytes
                    if byte == bytearray(b'R'):
                        phase = 1
                    else:
                        phase = 0
                elif phase == 1:  # Expect 'T'
                    if byte == bytearray(b'T'):
                        phase = 2
                    else:
                        raise Exception("Unexpected character")
                elif phase == 2:  # Expect 'R'
                    if byte == bytearray(b'R'):
                        phase = 3
                        index = 0
                    else:
                        raise Exception("Unexpected character")
                elif phase == 3:  # Read the header fields
                    header += byte
                    index += 1
                    if index == 8:
                        length = ord(byte)
                        if length > 0:
                            phase = 4
                            index = 0
                        else:
                            phase = 5
                elif phase == 4:  # Read the data
                    data += byte
                    index += 1
                    if index == length:
                        phase = 5
                elif phase == 5:  # Read the CRC code
                    crc = ord(byte)
                    phase = 6
                elif phase == 6:  # Expect '\r'
                    if byte == bytearray(b'\r'):
                        phase = 7
                    else:
                        raise Exception("Unexpected character")
                elif phase == 7:  # Expect '\n'
                    if byte == bytearray(b'\n'):
                        phase = 8
                    else:
                        raise Exception("Unexpected character")
            if PowerCommand.get_crc(header, data) != crc:
                raise Exception('CRC doesn\'t match')
        except Empty:
            raise CommunicationTimedOutException('Communication timed out')
        except Exception:
            self.__debug('reading from', command)
            raise
        finally:
            self.__debug('reading from', command)

        threshold = time.time() - self.__debug_buffer_duration
        self.__debug_buffer['read'][time.time()] = printable(command)
        for t in self.__debug_buffer['read'].keys():
            if t < threshold:
                del self.__debug_buffer['read'][t]

        return header, data
Ejemplo n.º 31
0
 def __log(action, data):
     if data is not None:
         logger.info("%.3f %s power: %s" %
                     (time.time(), action, printable(data)))