Exemplo n.º 1
0
    def __init__(self, master_communicator=INJECTED, pubsub=INJECTED):
        # type: (CoreCommunicator, PubSub) -> None
        """
        Initializes the MemoryFile instance, reprensenting read/write to EEPROM and FRAM
        """
        if not master_communicator:
            raise RuntimeError('Could not inject argument: core_communicator')

        self._core_communicator = master_communicator
        self._pubsub = pubsub

        self._eeprom_cache = {}  # type: Dict[int, bytearray]
        self._fram_cache = {}  # type: Dict[int, Tuple[float, bytearray]]

        # The write cache is a per-thread/per-type cache of all changes that need to be written that has the page
        # as key, and a list of tuples as value, where the tuples holds the start byte and contents
        self._write_cache = {
        }  # type: Dict[int, Dict[str, Dict[int, Dict[int, int]]]]
        self._write_cache_lock = {}  # type: Dict[int, Lock]
        self._select_write_cache_lock = Lock()
        self._activate_lock = Lock()

        self._eeprom_change_callback = None  # type: Optional[Callable[[], None]]
        self._self_activated = False
        self._activation_event = ThreadingEvent()

        self._core_communicator.register_consumer(
            BackgroundConsumer(CoreAPI.event_information(), 0,
                               self._handle_event))
Exemplo n.º 2
0
 def _read_page():
     page_data = bytearray()
     for i in range(self._page_length // 32):
         page_data += self._core_communicator.do_command(
             command=CoreAPI.memory_read(),
             fields={'type': self.type, 'page': page, 'start': i * 32, 'length': 32},
             timeout=MemoryFile.READ_TIMEOUT
         )['data']
     return page_data
Exemplo n.º 3
0
    def __init__(self, master_communicator=INJECTED, verbose=False):  # type: (CoreCommunicator, bool) -> None
        """
        :param master_communicator: CoreCommunicator
        :param verbose: Log all communication
        """
        self._verbose = verbose
        self._communicator = master_communicator
        self._consumers = {}  # type: Dict[str, List[Union[Consumer, PalletConsumer]]]
        self._cc_pallet_mode = {}  # type: Dict[str, bool]

        self._background_consumer = BackgroundConsumer(CoreAPI.ucan_rx_transport_message(), 1, self._process_transport_message)
        self._communicator.register_consumer(self._background_consumer)
Exemplo n.º 4
0
 def do_basic_action(self, basic_action, timeout=2):
     # type: (BasicAction, Optional[int]) -> Optional[Dict[str, Any]]
     """ Sends a basic action to the Core with the given action type and action number """
     logger.info('BA: Executed {0}'.format(basic_action))
     return self.do_command(
         CoreAPI.basic_action(),
         {'type': basic_action.action_type,
          'action': basic_action.action,
          'device_nr': basic_action.device_nr,
          'extra_parameter': basic_action.extra_parameter},
         timeout=timeout
     )
Exemplo n.º 5
0
    def do_command(self, cc_address, command, identity, fields, timeout=2, tx_timeout=2):
        # type: (str, UCANCommandSpec, str, Dict[str, Any], Optional[int], Optional[int]) -> Optional[Dict[str, Any]]
        """
        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
        :param command: specification of the command to execute
        :param identity: The identity
        :param fields: A dictionary with the command input field values
        :param timeout: maximum allowed time before a CommunicationTimedOutException is raised
        :param tx_timeout: timeout for the TX message(s) before a CommunicationTimedOutException is raised
        :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)  # type: Union[PalletConsumer, Consumer]
            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 + bytearray([0] * (8 - len(payload)))},
                                              timeout=tx_timeout if tx_timeout is not None else timeout)
            except CommunicationTimedOutException as ex:
                logger.error('Internal timeout during uCAN transport to CC {0}: {1}'.format(cc_address, ex))
                master_timeout = True
                break

        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
Exemplo n.º 6
0
 def _store_data(self, write_cache
                 ):  # type: (Dict[str, Dict[int, Dict[int, int]]]) -> bool
     data_written = False
     for memory_type, type_data in write_cache.items():
         for page, page_data in type_data.items():
             byte_numbers = list(page_data.keys())
             while len(byte_numbers) > 0:
                 # Get contiguous series of bytes
                 start = min(byte_numbers)
                 end = max(byte_numbers)
                 if start <= 127:
                     # Prevent writing over the 127/128 byte boundary
                     end = min(127, end)
                 data = bytearray()
                 for byte_number in range(start, end + 1):
                     if byte_number in page_data:
                         data.append(page_data[byte_number])
                         byte_numbers.remove(byte_number)
                     else:
                         break
                 # Compare with cache (is anything changed)
                 if memory_type == MemoryTypes.EEPROM:
                     cached_data = None
                     if page in self._eeprom_cache:
                         cached_data = self._eeprom_cache[page][
                             start:start + len(data)]
                     if data == cached_data:
                         continue
                 # Write in chuncks
                 for i in range(0, len(data), MemoryFile.WRITE_CHUNK_SIZE):
                     chunck = data[i:i + MemoryFile.WRITE_CHUNK_SIZE]
                     logger.info(
                         'MEMORY.{0}: Write P{1} S{2} D[{3}]'.format(
                             memory_type, page, start,
                             ' '.join(str(b) for b in chunck)))
                     self._core_communicator.do_command(
                         command=CoreAPI.memory_write(len(chunck)),
                         fields={
                             'type': memory_type,
                             'page': page,
                             'start': start,
                             'data': chunck
                         },
                         timeout=MemoryFile.WRITE_TIMEOUT)
                     data_written = True
                 # Cache updated values
                 if memory_type == MemoryTypes.EEPROM:
                     if page in self._eeprom_cache:
                         for index, data_byte in enumerate(data):
                             self._eeprom_cache[page][start +
                                                      index] = data_byte
     return data_written
Exemplo n.º 7
0
    def __init__(self, master_communicator=INJECTED, verbose=False):
        """
        :param master_communicator: CoreCommunicator
        :param verbose: Log all communication
        """
        self._verbose = verbose  # type: bool
        self._communicator = master_communicator  # type: CoreCommunicator
        self._consumers = []
        self._transparent_mode = False
        self._read_buffer = bytearray()

        self._background_consumer = BackgroundConsumer(
            CoreAPI.slave_rx_transport_message(), 2,
            self._process_transport_message)
        self._communicator.register_consumer(self._background_consumer)
Exemplo n.º 8
0
 def do_basic_action(self,
                     action_type,
                     action,
                     device_nr=0,
                     extra_parameter=0,
                     timeout=2,
                     log=True):
     # type: (int, int, int, int, Optional[int], bool) -> Optional[Dict[str, Any]]
     """ Sends a basic action to the Core with the given action type and action number """
     if log:
         logger.info('BA: Execute {0} {1} {2} {3}'.format(
             action_type, action, device_nr, extra_parameter))
     return self.do_command(CoreAPI.basic_action(), {
         'type': action_type,
         'action': action,
         'device_nr': device_nr,
         'extra_parameter': extra_parameter
     },
                            timeout=timeout)
Exemplo n.º 9
0
 def __init__(
         self,
         master_communicator=INJECTED):  # type: (CoreCommunicator) -> None
     super(FrontpanelCoreController, self).__init__()
     self._master_communicator = master_communicator
     self._master_communicator.register_consumer(
         BackgroundConsumer(CoreAPI.event_information(), 0,
                            self._handle_event))
     self._led_states = {}  # type: Dict[str, LedStateTracker]
     self._led_event_lock = Lock()
     self._carrier = True
     self._connectivity = True
     self._activity = False
     self._cloud = False
     self._vpn = False
     self._led_drive_states = {}  # type: Dict[str, Tuple[bool, str]]
     self._check_buttons_thread = None
     self._authorized_mode_buttons = [False, False]
     self._authorized_mode_buttons_pressed_since = None  # type: Optional[float]
     self._authorized_mode_buttons_released = False
Exemplo n.º 10
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
Exemplo n.º 11
0
    def write_page(self, page, data):  # type: (int, bytearray) -> None
        cached_data = None
        if self.type == MemoryTypes.EEPROM:
            cached_data = self._cache.get(page)

        for i in range(self._page_length // MemoryFile.WRITE_CHUNK_SIZE):
            start = i * MemoryFile.WRITE_CHUNK_SIZE
            cache_chunk = None
            if cached_data is not None:
                cache_chunk = cached_data[start:start + MemoryFile.WRITE_CHUNK_SIZE]
            data_chunk = data[start:start + MemoryFile.WRITE_CHUNK_SIZE]
            if data_chunk != cache_chunk:
                logger.info('MEMORY.{0}: Write P{1} S{2} D[{3}]'.format(self.type, page, start, ' '.join(str(b) for b in data_chunk)))
                self._core_communicator.do_command(
                    command=CoreAPI.memory_write(MemoryFile.WRITE_CHUNK_SIZE),
                    fields={'type': self.type, 'page': page, 'start': start, 'data': data_chunk},
                    timeout=MemoryFile.WRITE_TIMEOUT
                )
                self._dirty = True

        if self.type == MemoryTypes.EEPROM:
            self._cache[page] = data
Exemplo n.º 12
0
    def __init__(self, memory_type, master_communicator=INJECTED, pubsub=INJECTED):
        # type: (str, CoreCommunicator, PubSub) -> None
        """
        Initializes the MemoryFile instance, reprensenting one of the supported memory types.
        It provides caching for EEPROM, and direct write/read through for FRAM
        """
        if not master_communicator:
            raise RuntimeError('Could not inject argument: core_communicator')

        self._core_communicator = master_communicator
        self._pubsub = pubsub
        self.type = memory_type
        self._cache = {}  # type: Dict[int, bytearray]
        self._eeprom_change_callback = None  # type: Optional[Callable[[], None]]
        self._pages, self._page_length = MemoryFile.SIZES[memory_type]  # type: int, int
        self._self_activated = False
        self._dirty = False
        self._activation_event = ThreadingEvent()

        if memory_type == MemoryTypes.EEPROM:
            self._core_communicator.register_consumer(
                BackgroundConsumer(CoreAPI.event_information(), 0, self._handle_event)
            )
Exemplo n.º 13
0
 def exit_transparent_mode(self):
     response = self._communicator.do_command(
         command=CoreAPI.set_slave_bus_mode(),
         fields={'mode': CoreAPI.SlaveBusMode.LIVE})
     self._transparent_mode = response[
         'mode'] == CoreAPI.SlaveBusMode.TRANSPARENT
Exemplo n.º 14
0
 def test_event_consumer(self):
     with mock.patch.object(gateway.hal.master_controller_core, 'BackgroundConsumer',
                            return_value=None) as new_consumer:
         controller = MasterCoreController()
         expected_call = mock.call(CoreAPI.event_information(), 0, mock.ANY)
         self.assertIn(expected_call, new_consumer.call_args_list)