示例#1
0
 def read_memory(self, address: int, n_bytes: int):
     logger(__name__).info(f'STM32: Read {n_bytes} fromo 0x{address:x}')
     assert 255 >= n_bytes > 0
     self._txrx_command(0x11)
     self._txrx_command(struct.pack('>I', address))
     self._txrx_command(n_bytes)
     return self.port.read(n_bytes)
示例#2
0
 def extended_erase_special(self, command: int):
     logger(__name__).info(f'STM32: Extended special erase: {command:x}')
     if not self.commands[6] == 0x44:
         raise IOError('Extended erase not supported on this device (only standard erase)')
     assert 0xfffd <= command <= 0xffff
     self._txrx_command(0x44)
     self._txrx_command(struct.pack('>H', command))
示例#3
0
 def write_memory(self, start_address: int, data: bytes):
     logger(__name__).info(f'STM32: Write {len(data)} to 0x{start_address:x}')
     assert 0 < len(data) <= 256
     if len(data) % 4 != 0:
         data = data + (b'\0' * (4 - (len(data) % 4)))
     self._txrx_command(0x31)
     self._txrx_command(struct.pack('>I', start_address))
     self._txrx_command(bytes([len(data) - 1, *data]))
示例#4
0
 def erase_memory(self, page_numbers: List[int]):
     logger(__name__).info(f'STM32: Erase pages: {page_numbers}')
     if not self.commands[6] == 0x43:
         raise VEXCommError('Standard erase not supported on this device (only extended erase)')
     assert 0 < len(page_numbers) <= 255
     assert all([0 <= p <= 255 for p in page_numbers])
     self._txrx_command(0x43)
     self._txrx_command(bytes([len(page_numbers) - 1, *page_numbers]))
示例#5
0
 def extended_erase(self, page_numbers: List[int]):
     logger(__name__).info(f'STM32: Extended Erase pages: {page_numbers}')
     if not self.commands[6] == 0x44:
         raise IOError('Extended erase not supported on this device (only standard erase)')
     assert 0 < len(page_numbers) < 0xfff0
     assert all([0 <= p <= 0xffff for p in page_numbers])
     self._txrx_command(0x44)
     self._txrx_command(bytes([len(page_numbers) - 1, *struct.pack(f'>{len(page_numbers)}H', *page_numbers)]))
示例#6
0
 def go(self, start_address: int):
     logger(__name__).info(f'STM32: Go 0x{start_address:x}')
     self._txrx_command(0x21)
     try:
         self._txrx_command(struct.pack('>I', start_address), timeout=5.)
     except VEXCommError:
         logger(__name__).warning('STM32 Bootloader did not acknowledge GO command. '
                                  'The program may take a moment to begin running '
                                  'or the device should be rebooted.')
示例#7
0
 def update_remote_templates(self, **_):
     import requests
     response = requests.get(self.location)
     if response.status_code == 200:
         self.remote_templates = jsonpickle.decode(response.text)
     else:
         logger(__name__).warning(
             f'Unable to access {self.name} ({self.location}): {response.status_code}'
         )
     self.last_remote_update = datetime.now()
示例#8
0
 def notify(cls, uuid, event, *args, **kwargs):
     """
     Triggers an Observable given its UUID. See arguments for Observable.trigger
     """
     if isinstance(uuid, Observable):
         uuid = uuid.uuid
     if uuid in _uuid_table:
         _uuid_table[uuid].trigger(event, *args, **kwargs)
     else:
         logger(__name__).warning(
             f'Could not find an Observable to notify with UUID: {uuid}',
             sentry=True)
示例#9
0
def create_serial_port(port_name: str, timeout: Optional[float] = 1.0) -> serial.Serial:
    try:
        logger(__name__).debug(f'Opening serial port {port_name}')
        port = serial.Serial(port_name, baudrate=115200, bytesize=serial.EIGHTBITS,
                             parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE)
        port.timeout = timeout
        port.inter_byte_timeout = 0.2
        return port
    except serial.SerialException as e:
        if any(msg in str(e) for msg in [
            'Access is denied', 'Errno 16', 'Errno 13'
        ]):
            tb = sys.exc_info()[2]
            raise dont_send(ConnectionRefusedException(port_name, e).with_traceback(tb))
        else:
            raise e
示例#10
0
    def __init__(self, port: BasePort, must_initialize: bool = False, do_negoitate: bool = True):
        super().__init__(port)
        self.commands = bytes([0x00, 0x01, 0x02, 0x11, 0x21, 0x31, 0x43, 0x63, 0x73, 0x82, 0x92])

        if do_negoitate:
            # self.port.write(b'\0' * 255)
            if must_initialize:
                self._txrx_command(0x7f, checksum=False)
            try:
                self.get(n_retries=0)
            except:
                logger(__name__).info('Sending bootloader initialization')
                time.sleep(0.01)
                self.port.rts = 0
                for _ in itertools.repeat(None, times=3):
                    time.sleep(0.01)
                    self._txrx_command(0x7f, checksum=False)
                    time.sleep(0.01)
                    self.get()
示例#11
0
 def _txrx_command(self, command: Union[int, bytes], timeout: float = 0.01, checksum: bool = True):
     self.port.read_all()
     if isinstance(command, bytes):
         message = command + (bytes([reduce(operator.xor, command, 0x00)]) if checksum else bytes([]))
     elif isinstance(command, int):
         message = bytearray([command, ~command & 0xff] if checksum else [command])
     else:
         raise ValueError(f'Expected command to be bytes or int but got {type(command)}')
     logger(__name__).debug(f'STM32 TX: {bytes_to_str(message)}')
     self.port.write(message)
     self.port.flush()
     start_time = time.time()
     while time.time() - start_time < timeout:
         data = self.port.read(1)
         if data and len(data) == 1:
             logger(__name__).debug(f'STM32 RX: {data[0]} =?= {self.ACK_BYTE}')
             if data[0] == self.ACK_BYTE:
                 return
     raise VEXCommError(f"Device never ACK'd to {command}", command)
示例#12
0
 def read(self, n_bytes: int = 0) -> bytes:
     try:
         if n_bytes <= 0:
             self.buffer.extend(self.serial.read_all())
             msg = bytes(self.buffer)
             self.buffer = bytearray()
             return msg
         else:
             if len(self.buffer) < n_bytes:
                 self.buffer.extend(self.serial.read(n_bytes - len(self.buffer)))
             if len(self.buffer) < n_bytes:
                 msg = bytes(self.buffer)
                 self.buffer = bytearray()
             else:
                 msg, self.buffer = bytes(self.buffer[:n_bytes]), self.buffer[n_bytes:]
             return msg
     except serial.SerialException as e:
         logger(__name__).debug(e)
         raise PortConnectionException(e)
示例#13
0
 def get_remote_templates(self,
                          auto_check_freq: Optional[timedelta] = None,
                          force_check: bool = False,
                          **kwargs):
     if auto_check_freq is None:
         auto_check_freq = getattr(self, 'update_frequency',
                                   cli_config().update_frequency)
     logger(__name__).info(
         f'Last check of {self.name} was {self.last_remote_update} '
         f'({datetime.now() - self.last_remote_update} vs {auto_check_freq}).'
     )
     if force_check or datetime.now(
     ) - self.last_remote_update > auto_check_freq:
         with ui.Notification():
             ui.echo(f'Updating {self.name}... ', nl=False)
             self.update_remote_templates(**kwargs)
             ui.echo('Done', color='green')
     for t in self.remote_templates:
         t.metadata['origin'] = self.name
     return self.remote_templates
 def perform_upgrade(self) -> UpgradeResult:
     instructions: UpgradeInstruction = self.platform_instructions.get(
         self.platform, NothingInstruction())
     logger(__name__).debug(self.__dict__)
     logger(__name__).debug(f'Platform: {self.platform}')
     logger(__name__).debug(instructions.__dict__)
     return instructions.perform_upgrade()
示例#15
0
def test():
    ui.echo('Hello World!')
    with ui.Notification():
        ui.echo('Hello from another box')
    ui.echo('Back on the other one', nl=False)
    ui.echo('Whoops I missed a newline')
    with ui.Notification():
        ui.echo('Yet another box')
        with ui.progressbar(range(20)) as bar:
            for _ in bar:
                time.sleep(0.1)
        ui.echo('more below the ', nl=False)
        ui.echo('progressbar')
    ui.echo('Back in the other notification')

    logger(__name__).warning('Hello')
    try:
        raise Exception('Hey')
    except Exception as e:
        logger(__name__).exception(e)

    ui.finalize('test', {'hello': 'world'}, human_prefix='Created ')
示例#16
0
    def get_manifest(self, force: bool = False) -> UpgradeManifestV1:
        if not force and not self.has_stale_manifest:
            return self._manifest

        ui.echo('Fetching upgrade manifest...')
        import requests
        import jsonpickle
        import json

        channel_url = f'https://purduesigbots.github.io/pros-mainline/{self.release_channel.value}'
        self._manifest = None

        manifest_urls = [
            f"{channel_url}/{manifest.__name__}.json" for manifest in manifests
        ]
        for manifest_url in manifest_urls:
            resp = requests.get(manifest_url)
            if resp.status_code == 200:
                try:
                    self._manifest = jsonpickle.decode(resp.text, keys=True)
                    logger(__name__).debug(self._manifest)
                    self._last_check = datetime.now()
                    self.save()
                    break
                except json.decoder.JSONDecodeError as e:
                    logger(__name__).warning(
                        f'Failed to decode {manifest_url}')
                    logger(__name__).debug(e)
            else:
                logger(__name__).debug(
                    f'Failed to get {manifest_url} ({resp.status_code})')
        if not self._manifest:
            manifest_list = "\n".join(manifest_urls)
            logger(__name__).warning(
                f'Could not access any upgrade manifests from any of:\n{manifest_list}'
            )
        return self._manifest
示例#17
0
 def get(self):
     logger(__name__).info('STM32: Get')
     self._txrx_command(0x00)
     n_bytes = self.port.read(1)[0]
     assert n_bytes == 11
     data = self.port.read(n_bytes + 1)
     logger(__name__).info(f'STM32 Bootloader version 0x{data[0]:x}')
     self.commands = data[1:]
     logger(__name__).debug(f'STM32 Bootloader commands are: {bytes_to_str(data[1:])}')
     assert self.port.read(1)[0] == self.ACK_BYTE
示例#18
0
 def has_stale_manifest(self):
     if self._manifest is None:
         logger(__name__).debug(
             'Upgrade manager\'s manifest is nonexistent')
     if datetime.now() - self._last_check > cli_config().update_frequency:
         logger(__name__).debug(
             f'Upgrade manager\'s last check occured at {self._last_check}.'
         )
         logger(__name__).debug(
             f'Was longer ago than update frequency ({cli_config().update_frequency}) allows.'
         )
     return (self._manifest is None) or (datetime.now() - self._last_check >
                                         cli_config().update_frequency)
示例#19
0
 def trigger(self, event, *args, **kw):
     logger(__name__).debug(
         f'Triggered {self.uuid} ({type(self).__name__}) "{event}" event: {args} {kw}'
     )
     return super().trigger(event, *args, **kw)
示例#20
0
 def destroy(self):
     logger(__name__).debug(
         f'Destroying {self.__class__.__name__} to {self.serial.name}')
     self.serial.close()
示例#21
0
def list_all_comports():
    ports = list_ports.comports()
    logger(__name__).debug('Connected: {}'.format(';'.join([str(p.__dict__) for p in ports])))
    return ports
示例#22
0
 def erase_all(self):
     logger(__name__).info('STM32: Erase all pages')
     if not self.commands[6] == 0x43:
         raise VEXCommError('Standard erase not supported on this device (only extended erase)')
     self._txrx_command(0x43)
     self._txrx_command(0xff)
示例#23
0
 def commit(self,
            label: str = 'Committing transaction',
            remove_empty_directories: bool = True):
     with ui.progressbar(length=len(self._rm_files) + len(self._add_files),
                         label=label) as pb:
         for file in sorted(self._rm_files,
                            key=lambda p: p.count('/') + p.count('\\'),
                            reverse=True):
             file_path = os.path.join(self.location, file)
             if os.path.isfile(file_path):
                 logger(__name__).info(f'Removing {file}')
                 os.remove(os.path.join(self.location, file))
             else:
                 logger(__name__).info(f'Not removing nonexistent {file}')
             pardir = os.path.abspath(os.path.join(file_path, os.pardir))
             while remove_empty_directories and len(
                     os.listdir(pardir)) == 0:
                 logger(__name__).info(
                     f'Removing {os.path.relpath(pardir, self.location)}')
                 os.rmdir(pardir)
                 pardir = os.path.abspath(os.path.join(pardir, os.pardir))
                 if pardir == self.location:
                     # Don't try and recursively delete folders outside the scope of the
                     # transaction directory
                     break
             pb.update(1)
         for file in self._add_files:
             source = os.path.join(self._add_srcs[file], file)
             destination = os.path.join(self.location, file)
             if os.path.isfile(source):
                 if not os.path.isdir(os.path.dirname(destination)):
                     logger(__name__).debug(
                         f'Creating directories: f{destination}')
                     os.makedirs(os.path.dirname(destination),
                                 exist_ok=True)
                 logger(__name__).info(f'Adding {file}')
                 shutil.copy(os.path.join(self._add_srcs[file], file),
                             os.path.join(self.location, file))
             else:
                 logger(__name__).info(
                     f"Not copying {file} because {source} doesn't exist.")
             pb.update(1)
示例#24
0
 def get_read_protection_status(self):
     logger(__name__).info('STM32: Get ID & Read Protection Status')
     self._txrx_command(0x01)
     data = self.port.read(3)
     logger(__name__).debug(f'STM32 Bootloader Get Version & Read Protection Status is: {bytes_to_str(data)}')
     assert self.port.read(1)[0] == self.ACK_BYTE
示例#25
0
 def get_id(self):
     logger(__name__).info('STM32: Get PID')
     self._txrx_command(0x02)
     n_bytes = self.port.read(1)[0]
     pid = self.port.read(n_bytes + 1)
     logger(__name__).debug(f'STM32 Bootloader PID is {pid}')