Esempio n. 1
0
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     # Grab the Python script.
     tab = self._view.current_tab
     if tab is None:
         # There is no active text editor.
         return
     python_script = tab.text().encode('utf-8')
     # Generate a hex file.
     python_hex = uflash.hexlify(python_script)
     micropython_hex = uflash.embed_hex(uflash._RUNTIME, python_hex)
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit:
         hex_file = os.path.join(path_to_microbit, 'micropython.hex')
         uflash.save_hex(micropython_hex, hex_file)
         message = 'Flashing "{}" onto the micro:bit.'.format(tab.label)
         information = ("When the yellow LED stops flashing the device"
                        " will restart and your script will run. If there"
                        " is an error, you'll see a helpful message scroll"
                        " across the device's display.")
         self._view.show_message(message, information, 'Information')
     else:
         message = 'Could not find an attached BBC micro:bit.'
         self._view.show_message(message)
Esempio n. 2
0
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     # Grab the Python script.
     tab = self._view.current_tab
     if tab is None:
         # There is no active text editor
         return
     python_script = tab.text().encode("utf-8")
     # Generate a hex file
     python_hex = uflash.hexlify(python_script)
     micropython_hex = uflash.embed_hex(uflash._RUNTIME, python_hex)
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit:
         hex_file = os.path.join(path_to_microbit, "micropython.hex")
         uflash.save_hex(micropython_hex, hex_file)
         message = 'Flashing "{}" onto the micro:bit.'.format(tab.label)
         information = (
             "When the yellow LED stops flashing the device"
             " will restart and your script will run. If there"
             " is an error, you'll see a helpful message scroll"
             " across the device's display."
         )
         self._view.show_message(message, information, "Information")
     else:
         message = "Could not find an attached BBC micro:bit."
         self._view.show_message(message)
Esempio n. 3
0
 def find_microbit(self):
     """
     Finds a micro:bit path, serial port and board ID.
     """
     port = None
     board_id = None
     path_to_microbit = uflash.find_microbit()
     logger.info("Path to micro:bit: {}".format(path_to_microbit))
     if self.editor.current_device:
         port = self.editor.current_device.port
         serial_number = self.editor.current_device.serial_number
         # The board ID are the first 4 hex digits for the USB serial number
         board_id = int(serial_number[:4], 16)
         logger.info("Serial port: {}".format(port))
         logger.info("Device serial number: {}".format(serial_number))
         logger.info("Board ID: 0x{:x}".format(board_id))
     return path_to_microbit, port, board_id
Esempio n. 4
0
    def flash(self):
        """
        Takes the currently active tab, compiles the Python script therein into
        a hex file and flashes it all onto the connected device.

        WARNING: This method is getting more complex due to several edge
        cases. Ergo, it's a target for refactoring.
        """
        user_defined_microbit_path = None
        self.python_script = ''
        logger.info('Preparing to flash script.')
        # The first thing to do is check the script is valid and of the
        # expected length.
        # Grab the Python script.
        tab = self.view.current_tab
        if tab is None:
            # There is no active text editor. Exit.
            return
        # Check the script's contents.
        python_script = tab.text().encode('utf-8')
        logger.debug('Python script:')
        logger.debug(python_script)
        # Check minification status.
        minify = False
        if uflash.get_minifier():
            minify = self.editor.minify
        # Attempt and handle minification.
        if len(python_script) >= uflash._MAX_SIZE:
            message = _('Unable to flash "{}"').format(tab.label)
            if minify and can_minify:
                orginal = len(python_script)
                script = python_script.decode('utf-8')
                try:
                    mangled = nudatus.mangle(script).encode('utf-8')
                except TokenError as e:
                    msg, (line, col) = e.args
                    logger.debug('Minify failed')
                    logger.exception(e)
                    message = _("Problem with script")
                    information = _("{} [{}:{}]").format(msg, line, col)
                    self.view.show_message(message, information, 'Warning')
                    return
                saved = orginal - len(mangled)
                percent = saved / orginal * 100
                logger.debug(
                    'Script minified, {} bytes ({:.2f}%) saved:'.format(
                        saved, percent))
                logger.debug(mangled)
                python_script = mangled
                if len(python_script) >= 8192:
                    information = _("Our minifier tried but your "
                                    "script is too long!")
                    self.view.show_message(message, information, 'Warning')
                    return
            elif minify and not can_minify:
                information = _("Your script is too long and the minifier"
                                " isn't available")
                self.view.show_message(message, information, 'Warning')
                return
            else:
                information = _("Your script is too long!")
                self.view.show_message(message, information, 'Warning')
                return
        # By this point, there's a valid Python script in "python_script".
        # Assign this to an attribute for later processing in a different
        # method.
        self.python_script = python_script
        # Next step: find the microbit port and serial number.
        path_to_microbit = uflash.find_microbit()
        logger.info('Path to micro:bit: {}'.format(path_to_microbit))
        port = None
        serial_number = None
        try:
            port, serial_number = self.find_device()
            logger.info('Serial port: {}'.format(port))
            logger.info('Device serial number: {}'.format(serial_number))
        except Exception as ex:
            logger.warning('Unable to make serial connection to micro:bit.')
            logger.warning(ex)
        # Determine the location of the BBC micro:bit. If it can't be found
        # fall back to asking the user to locate it.
        if path_to_microbit is None:
            # Ask the user to locate the device.
            path_to_microbit = self.view.get_microbit_path(HOME_DIRECTORY)
            user_defined_microbit_path = path_to_microbit
            logger.debug('User defined path to micro:bit: {}'.format(
                user_defined_microbit_path))
        # Check the path and that it exists simply because the path maybe based
        # on stale data.
        if path_to_microbit and os.path.exists(path_to_microbit):
            force_flash = False  # If set to true, fully flash the device.
            # If there's no port but there's a path_to_microbit, then we're
            # probably running on Windows with an old device, so force flash.
            if not port:
                force_flash = True
            if not self.python_script.strip():
                # If the script is empty, this is a signal to simply force a
                # flash.
                logger.info("Python script empty. Forcing flash.")
                force_flash = True
            logger.info("Checking target device.")
            # Get the version of MicroPython on the device.
            try:
                version_info = microfs.version()
                logger.info(version_info)
                board_info = version_info['version'].split()
                if (board_info[0] == 'micro:bit'
                        and board_info[1].startswith('v')):
                    # New style versions, so the correct information will be
                    # in the "release" field.
                    try:
                        # Check the release is a correct semantic version.
                        semver.parse(version_info['release'])
                        board_version = version_info['release']
                    except ValueError:
                        # If it's an invalid semver, set to unknown version to
                        # force flash.
                        board_version = '0.0.1'
                else:
                    # 0.0.1 indicates an old unknown version. This is just a
                    # valid arbitrary flag for semver comparison a couple of
                    # lines below.
                    board_version = '0.0.1'
                logger.info('Board MicroPython: {}'.format(board_version))
                logger.info('Mu MicroPython: {}'.format(
                    uflash.MICROPYTHON_VERSION))
                # If there's an older version of MicroPython on the device,
                # update it with the one packaged with Mu.
                if semver.compare(board_version,
                                  uflash.MICROPYTHON_VERSION) < 0:
                    force_flash = True
            except Exception:
                # Could not get version of MicroPython. This means either the
                # device has a really old version of MicroPython or is running
                # something else. In any case, flash MicroPython onto the
                # device.
                logger.warning('Could not detect version of MicroPython.')
                force_flash = True
            # Check use of custom runtime.
            rt_hex_path = self.editor.microbit_runtime.strip()
            message = _('Flashing "{}" onto the micro:bit.').format(tab.label)
            if (rt_hex_path and os.path.exists(rt_hex_path)):
                message = message + _(" Runtime: {}").format(rt_hex_path)
                force_flash = True  # Using a custom runtime, so flash it.
            else:
                rt_hex_path = None
                self.editor.microbit_runtime = ''
            # Check for use of user defined path (to save hex onto local
            # file system.
            if user_defined_microbit_path:
                force_flash = True
            # If we need to flash the device with a clean hex, do so now.
            if force_flash:
                logger.info('Flashing new MicroPython runtime onto device')
                self.editor.show_status_message(message, 10)
                self.set_buttons(flash=False)
                if user_defined_microbit_path or not port:
                    # The user has provided a path to a location on the
                    # filesystem. In this case save the combined hex/script
                    # in the specified path_to_microbit.
                    # Or... Mu has a path to a micro:bit but can't establish
                    # a serial connection, so use the combined hex/script
                    # to flash the device.
                    self.flash_thread = DeviceFlasher([path_to_microbit],
                                                      self.python_script,
                                                      rt_hex_path)
                    # Reset python_script so Mu doesn't try to copy it as the
                    # main.py file.
                    self.python_script = ''
                else:
                    # We appear to need to flash a connected micro:bit device,
                    # so just flash the Python hex with no embedded Python
                    # script, since this will be copied over when the
                    # flashing operation has finished.
                    model_serial_number = int(serial_number[:4])
                    if rt_hex_path:
                        # If the user has specified a bespoke runtime hex file
                        # assume they know what they're doing and hope for the
                        # best.
                        self.flash_thread = DeviceFlasher([path_to_microbit],
                                                          b'', rt_hex_path)
                    elif model_serial_number in self.valid_serial_numbers:
                        # The connected board has a serial number that
                        # indicates the MicroPython hex bundled with Mu
                        # supports it. In which case, flash it.
                        self.flash_thread = DeviceFlasher([path_to_microbit],
                                                          b'', None)
                    else:
                        message = _('Unsupported BBC micro:bit.')
                        information = _("Your device is newer than this "
                                        "version of Mu. Please update Mu "
                                        "to the latest version to support "
                                        "this device.\n\n"
                                        "https://codewith.mu/")
                        self.view.show_message(message, information)
                        return
                if sys.platform == 'win32':
                    # Windows blocks on write.
                    self.flash_thread.finished.connect(self.flash_finished)
                else:
                    if user_defined_microbit_path:
                        # Call the flash_finished immediately the thread
                        # finishes if Mu is writing the hex file to a user
                        # defined location on the local filesystem.
                        self.flash_thread.finished.connect(self.flash_finished)
                    else:
                        # Other platforms don't block, so schedule the finish
                        # call for 10 seconds (approximately how long flashing
                        # the connected device takes).
                        self.flash_timer = QTimer()
                        self.flash_timer.timeout.connect(self.flash_finished)
                        self.flash_timer.setSingleShot(True)
                        self.flash_timer.start(10000)
                self.flash_thread.on_flash_fail.connect(self.flash_failed)
                self.flash_thread.start()
            else:
                try:
                    self.copy_main()
                except IOError as ioex:
                    # There was a problem with the serial communication with
                    # the device, so revert to forced flash... "old style".
                    # THIS IS A HACK! :-(
                    logger.warning('Could not copy file to device.')
                    logger.error(ioex)
                    logger.info('Falling back to old-style flashing.')
                    self.flash_thread = DeviceFlasher([path_to_microbit],
                                                      self.python_script,
                                                      rt_hex_path)
                    self.python_script = ''
                    if sys.platform == 'win32':
                        # Windows blocks on write.
                        self.flash_thread.finished.connect(self.flash_finished)
                    else:
                        self.flash_timer = QTimer()
                        self.flash_timer.timeout.connect(self.flash_finished)
                        self.flash_timer.setSingleShot(True)
                        self.flash_timer.start(10000)
                    self.flash_thread.on_flash_fail.connect(self.flash_failed)
                    self.flash_thread.start()
                except Exception as ex:
                    self.flash_failed(ex)
        else:
            # Try to be helpful... essentially there is nothing Mu can do but
            # prompt for patience while the device is mounted and/or do the
            # classic "have you tried switching it off and on again?" trick.
            # This one's for James at the Raspberry Pi Foundation. ;-)
            message = _('Could not find an attached BBC micro:bit.')
            information = _("Please ensure you leave enough time for the BBC"
                            " micro:bit to be attached and configured"
                            " correctly by your computer. This may take"
                            " several seconds."
                            " Alternatively, try removing and re-attaching the"
                            " device or saving your work and restarting Mu if"
                            " the device remains unfound.")
            self.view.show_message(message, information)
Esempio n. 5
0
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     logger.info('Flashing script.')
     # Grab the Python script.
     tab = self.view.current_tab
     if tab is None:
         # There is no active text editor.
         return
     python_script = tab.text().encode('utf-8')
     logger.debug('Python script:')
     logger.debug(python_script)
     if len(python_script) >= 8192:
         message = _('Unable to flash "{}"').format(tab.label)
         information = _("Your script is too long!")
         self.view.show_message(message, information, 'Warning')
         return
     # Determine the location of the BBC micro:bit. If it can't be found
     # fall back to asking the user to locate it.
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit is None:
         # Has the path to the device already been specified?
         if self.user_defined_microbit_path:
             path_to_microbit = self.user_defined_microbit_path
         else:
             # Ask the user to locate the device.
             path_to_microbit = self.view.get_microbit_path(HOME_DIRECTORY)
             # Store the user's specification of the path for future use.
             self.user_defined_microbit_path = path_to_microbit
             logger.debug('User defined path to micro:bit: {}'.format(
                          self.user_defined_microbit_path))
     # Check the path and that it exists simply because the path maybe based
     # on stale data.
     logger.debug('Path to micro:bit: {}'.format(path_to_microbit))
     if path_to_microbit and os.path.exists(path_to_microbit):
         logger.debug('Flashing to device.')
         # Flash the microbit
         rt_hex_path = self.get_hex_path()
         uflash.flash(paths_to_microbits=[path_to_microbit],
                      python_script=python_script,
                      path_to_runtime=rt_hex_path)
         message = _('Flashing "{}" onto the micro:bit.').format(tab.label)
         if (rt_hex_path is not None and os.path.exists(rt_hex_path)):
             message = message + _(" Runtime: {}").format(rt_hex_path)
         self.editor.show_status_message(message, 10)
     else:
         # Reset user defined path since it's incorrect.
         self.user_defined_microbit_path = None
         # Try to be helpful... essentially there is nothing Mu can do but
         # prompt for patience while the device is mounted and/or do the
         # classic "have you tried switching it off and on again?" trick.
         # This one's for James at the Raspberry Pi Foundation. ;-)
         message = _('Could not find an attached BBC micro:bit.')
         information = _("Please ensure you leave enough time for the BBC"
                         " micro:bit to be attached and configured"
                         " correctly by your computer. This may take"
                         " several seconds."
                         " Alternatively, try removing and re-attaching the"
                         " device or saving your work and restarting Mu if"
                         " the device remains unfound.")
         self.view.show_message(message, information)
Esempio n. 6
0
File: microbit.py Progetto: opt9/mu
    def flash(self):
        """
        Takes the currently active tab, compiles the Python script therein into
        a hex file and flashes it all onto the connected device.

        WARNING: This method is getting more complex due to several edge
        cases. Ergo, it's a target for refactoring.
        """
        user_defined_microbit_path = None
        self.python_script = ''
        logger.info('Preparing to flash script.')
        # The first thing to do is check the script is valid and of the
        # expected length.
        # Grab the Python script.
        tab = self.view.current_tab
        if tab is None:
            # There is no active text editor. Exit.
            return
        # Check the script's contents.
        python_script = tab.text().encode('utf-8')
        logger.debug('Python script:')
        logger.debug(python_script)
        # Check minification status.
        minify = False
        if uflash.get_minifier():
            minify = self.editor.minify
        # Attempt and handle minification.
        if len(python_script) >= uflash._MAX_SIZE:
            message = _('Unable to flash "{}"').format(tab.label)
            if minify and can_minify:
                orginal = len(python_script)
                script = python_script.decode('utf-8')
                try:
                    mangled = nudatus.mangle(script).encode('utf-8')
                except TokenError as e:
                    msg, (line, col) = e.args
                    logger.debug('Minify failed')
                    logger.exception(e)
                    message = _("Problem with script")
                    information = _("{} [{}:{}]").format(msg, line, col)
                    self.view.show_message(message, information, 'Warning')
                    return
                saved = orginal - len(mangled)
                percent = saved / orginal * 100
                logger.debug('Script minified, {} bytes ({:.2f}%) saved:'
                             .format(saved, percent))
                logger.debug(mangled)
                python_script = mangled
                if len(python_script) >= 8192:
                    information = _("Our minifier tried but your "
                                    "script is too long!")
                    self.view.show_message(message, information, 'Warning')
                    return
            elif minify and not can_minify:
                information = _("Your script is too long and the minifier"
                                " isn't available")
                self.view.show_message(message, information, 'Warning')
                return
            else:
                information = _("Your script is too long!")
                self.view.show_message(message, information, 'Warning')
                return
        # By this point, there's a valid Python script in "python_script".
        # Assign this to an attribute for later processing in a different
        # method.
        self.python_script = python_script
        # Next step: find the microbit port and serial number.
        path_to_microbit = uflash.find_microbit()
        logger.info('Path to micro:bit: {}'.format(path_to_microbit))
        port = None
        serial_number = None
        try:
            port, serial_number = self.find_device()
            logger.info('Serial port: {}'.format(port))
            logger.info('Device serial number: {}'.format(serial_number))
        except Exception as ex:
            logger.warning('Unable to make serial connection to micro:bit.')
            logger.warning(ex)
        # Determine the location of the BBC micro:bit. If it can't be found
        # fall back to asking the user to locate it.
        if path_to_microbit is None:
            # Ask the user to locate the device.
            path_to_microbit = self.view.get_microbit_path(HOME_DIRECTORY)
            user_defined_microbit_path = path_to_microbit
            logger.debug('User defined path to micro:bit: {}'.format(
                         user_defined_microbit_path))
        # Check the path and that it exists simply because the path maybe based
        # on stale data.
        if path_to_microbit and os.path.exists(path_to_microbit):
            force_flash = False  # If set to true, fully flash the device.
            # If there's no port but there's a path_to_microbit, then we're
            # probably running on Windows with an old device, so force flash.
            if not port:
                force_flash = True
            if not self.python_script.strip():
                # If the script is empty, this is a signal to simply force a
                # flash.
                logger.info("Python script empty. Forcing flash.")
                force_flash = True
            logger.info("Checking target device.")
            # Get the version of MicroPython on the device.
            try:
                version_info = microfs.version()
                logger.info(version_info)
                board_info = version_info['version'].split()
                if (board_info[0] == 'micro:bit' and
                        board_info[1].startswith('v')):
                    # New style versions, so the correct information will be
                    # in the "release" field.
                    try:
                        # Check the release is a correct semantic version.
                        semver.parse(version_info['release'])
                        board_version = version_info['release']
                    except ValueError:
                        # If it's an invalid semver, set to unknown version to
                        # force flash.
                        board_version = '0.0.1'
                else:
                    # 0.0.1 indicates an old unknown version. This is just a
                    # valid arbitrary flag for semver comparison a couple of
                    # lines below.
                    board_version = '0.0.1'
                logger.info('Board MicroPython: {}'.format(board_version))
                logger.info(
                    'Mu MicroPython: {}'.format(uflash.MICROPYTHON_VERSION))
                # If there's an older version of MicroPython on the device,
                # update it with the one packaged with Mu.
                if semver.compare(board_version,
                                  uflash.MICROPYTHON_VERSION) < 0:
                    force_flash = True
            except Exception:
                # Could not get version of MicroPython. This means either the
                # device has a really old version of MicroPython or is running
                # something else. In any case, flash MicroPython onto the
                # device.
                logger.warn('Could not detect version of MicroPython.')
                force_flash = True
            # Check use of custom runtime.
            rt_hex_path = self.editor.microbit_runtime.strip()
            message = _('Flashing "{}" onto the micro:bit.').format(tab.label)
            if (rt_hex_path and os.path.exists(rt_hex_path)):
                message = message + _(" Runtime: {}").format(rt_hex_path)
                force_flash = True  # Using a custom runtime, so flash it.
            else:
                rt_hex_path = None
                self.editor.microbit_runtime = ''
            # Check for use of user defined path (to save hex onto local
            # file system.
            if user_defined_microbit_path:
                force_flash = True
            # If we need to flash the device with a clean hex, do so now.
            if force_flash:
                logger.info('Flashing new MicroPython runtime onto device')
                self.editor.show_status_message(message, 10)
                self.set_buttons(flash=False)
                if user_defined_microbit_path or not port:
                    # The user has provided a path to a location on the
                    # filesystem. In this case save the combined hex/script
                    # in the specified path_to_microbit.
                    # Or... Mu has a path to a micro:bit but can't establish
                    # a serial connection, so use the combined hex/script
                    # to flash the device.
                    self.flash_thread = DeviceFlasher([path_to_microbit],
                                                      self.python_script,
                                                      rt_hex_path)
                    # Reset python_script so Mu doesn't try to copy it as the
                    # main.py file.
                    self.python_script = ''
                else:
                    # We appear to need to flash a connected micro:bit device,
                    # so just flash the Python hex with no embedded Python
                    # script, since this will be copied over when the
                    # flashing operation has finished.
                    model_serial_number = int(serial_number[:4])
                    if rt_hex_path:
                        # If the user has specified a bespoke runtime hex file
                        # assume they know what they're doing and hope for the
                        # best.
                        self.flash_thread = DeviceFlasher([path_to_microbit],
                                                          b'', rt_hex_path)
                    elif model_serial_number in self.valid_serial_numbers:
                        # The connected board has a serial number that
                        # indicates the MicroPython hex bundled with Mu
                        # supports it. In which case, flash it.
                        self.flash_thread = DeviceFlasher([path_to_microbit],
                                                          b'', None)
                    else:
                        message = _('Unsupported BBC micro:bit.')
                        information = _("Your device is newer than this "
                                        "version of Mu. Please update Mu "
                                        "to the latest version to support "
                                        "this device.\n\n"
                                        "https://codewith.mu/")
                        self.view.show_message(message, information)
                        return
                if sys.platform == 'win32':
                    # Windows blocks on write.
                    self.flash_thread.finished.connect(self.flash_finished)
                else:
                    if user_defined_microbit_path:
                        # Call the flash_finished immediately the thread
                        # finishes if Mu is writing the hex file to a user
                        # defined location on the local filesystem.
                        self.flash_thread.finished.connect(self.flash_finished)
                    else:
                        # Other platforms don't block, so schedule the finish
                        # call for 10 seconds (approximately how long flashing
                        # the connected device takes).
                        self.flash_timer = QTimer()
                        self.flash_timer.timeout.connect(self.flash_finished)
                        self.flash_timer.setSingleShot(True)
                        self.flash_timer.start(10000)
                self.flash_thread.on_flash_fail.connect(self.flash_failed)
                self.flash_thread.start()
            else:
                try:
                    self.copy_main()
                except IOError as ioex:
                    # There was a problem with the serial communication with
                    # the device, so revert to forced flash... "old style".
                    # THIS IS A HACK! :-(
                    logger.warning('Could not copy file to device.')
                    logger.error(ioex)
                    logger.info('Falling back to old-style flashing.')
                    self.flash_thread = DeviceFlasher([path_to_microbit],
                                                      self.python_script,
                                                      rt_hex_path)
                    self.python_script = ''
                    if sys.platform == 'win32':
                        # Windows blocks on write.
                        self.flash_thread.finished.connect(self.flash_finished)
                    else:
                        self.flash_timer = QTimer()
                        self.flash_timer.timeout.connect(self.flash_finished)
                        self.flash_timer.setSingleShot(True)
                        self.flash_timer.start(10000)
                    self.flash_thread.on_flash_fail.connect(self.flash_failed)
                    self.flash_thread.start()
                except Exception as ex:
                    self.flash_failed(ex)
        else:
            # Try to be helpful... essentially there is nothing Mu can do but
            # prompt for patience while the device is mounted and/or do the
            # classic "have you tried switching it off and on again?" trick.
            # This one's for James at the Raspberry Pi Foundation. ;-)
            message = _('Could not find an attached BBC micro:bit.')
            information = _("Please ensure you leave enough time for the BBC"
                            " micro:bit to be attached and configured"
                            " correctly by your computer. This may take"
                            " several seconds."
                            " Alternatively, try removing and re-attaching the"
                            " device or saving your work and restarting Mu if"
                            " the device remains unfound.")
            self.view.show_message(message, information)
Esempio n. 7
0
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     logger.info('Flashing script')
     # Grab the Python script.
     tab = self._view.current_tab
     if tab is None:
         # There is no active text editor.
         return
     python_script = tab.text().encode('utf-8')
     logger.debug('Python script:')
     logger.debug(python_script)
     if len(python_script) >= 8192:
         message = 'Unable to flash "{}"'.format(tab.label)
         information = ("Your script is too long!")
         self._view.show_message(message, information, 'Warning')
         return
     # Generate a hex file.
     python_hex = uflash.hexlify(python_script)
     logger.debug('Python hex:')
     logger.debug(python_hex)
     micropython_hex = uflash.embed_hex(uflash._RUNTIME, python_hex)
     # Determine the location of the BBC micro:bit. If it can't be found
     # fall back to asking the user to locate it.
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit is None:
         # Has the path to the device already been specified?
         if self.user_defined_microbit_path:
             path_to_microbit = self.user_defined_microbit_path
         else:
             # Ask the user to locate the device.
             path_to_microbit = self._view.get_microbit_path(HOME_DIRECTORY)
             # Store the user's specification of the path for future use.
             self.user_defined_microbit_path = path_to_microbit
             logger.debug('User defined path to micro:bit: {}'.format(
                          self.user_defined_microbit_path))
     # Check the path and that it exists simply because the path maybe based
     # on stale data.
     logger.debug('Path to micro:bit: {}'.format(path_to_microbit))
     if path_to_microbit and os.path.exists(path_to_microbit):
         logger.debug('Flashing to device.')
         hex_file = os.path.join(path_to_microbit, 'micropython.hex')
         uflash.save_hex(micropython_hex, hex_file)
         message = 'Flashing "{}" onto the micro:bit.'.format(tab.label)
         information = ("When the yellow LED stops flashing the device"
                        " will restart and your script will run. If there"
                        " is an error, you'll see a helpful message scroll"
                        " across the device's display.")
         self._view.show_message(message, information, 'Information')
     else:
         # Reset user defined path since it's incorrect.
         self.user_defined_microbit_path = None
         # Try to be helpful... essentially there is nothing Mu can do but
         # prompt for patience while the device is mounted and/or do the
         # classic "have you tried switching it off and on again?" trick.
         # This one's for James at the Raspberry Pi Foundation. ;-)
         message = 'Could not find an attached BBC micro:bit.'
         information = ("Please ensure you leave enough time for the BBC"
                        " micro:bit to be attached and configured correctly"
                        " by your computer. This may take several seconds."
                        " Alternatively, try removing and re-attaching the"
                        " device or saving your work and restarting Mu if"
                        " the device remains unfound.")
         self._view.show_message(message, information)
Esempio n. 8
0
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     logger.info('Flashing script.')
     # Grab the Python script.
     tab = self.view.current_tab
     if tab is None:
         # There is no active text editor.
         return
     python_script = tab.text().encode('utf-8')
     logger.debug('Python script:')
     logger.debug(python_script)
     if len(python_script) >= 8192:
         message = _('Unable to flash "{}"').format(tab.label)
         information = _("Your script is too long!")
         self.view.show_message(message, information, 'Warning')
         return
     # Determine the location of the BBC micro:bit. If it can't be found
     # fall back to asking the user to locate it.
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit is None:
         # Has the path to the device already been specified?
         if self.user_defined_microbit_path:
             path_to_microbit = self.user_defined_microbit_path
         else:
             # Ask the user to locate the device.
             path_to_microbit = self.view.get_microbit_path(HOME_DIRECTORY)
             # Store the user's specification of the path for future use.
             self.user_defined_microbit_path = path_to_microbit
             logger.debug('User defined path to micro:bit: {}'.format(
                          self.user_defined_microbit_path))
     # Check the path and that it exists simply because the path maybe based
     # on stale data.
     logger.debug('Path to micro:bit: {}'.format(path_to_microbit))
     if path_to_microbit and os.path.exists(path_to_microbit):
         logger.debug('Flashing to device.')
         # Flash the microbit
         rt_hex_path = self.get_hex_path()
         message = _('Flashing "{}" onto the micro:bit.').format(tab.label)
         if (rt_hex_path is not None and os.path.exists(rt_hex_path)):
             message = message + _(" Runtime: {}").format(rt_hex_path)
         self.editor.show_status_message(message, 10)
         self.view.button_bar.slots['flash'].setEnabled(False)
         self.flash_thread = DeviceFlasher([path_to_microbit],
                                           python_script, rt_hex_path)
         if sys.platform == 'win32':
             # Windows blocks on write.
             self.flash_thread.finished.connect(self.flash_finished)
         else:
             # Other platforms don't block, so schedule the finish call
             # for 10 seconds (approximately how long flashing the device
             # takes).
             self.flash_timer = QTimer()
             self.flash_timer.timeout.connect(self.flash_finished)
             self.flash_timer.setSingleShot(True)
             self.flash_timer.start(10000)
         self.flash_thread.on_flash_fail.connect(self.flash_failed)
         self.flash_thread.start()
     else:
         # Reset user defined path since it's incorrect.
         self.user_defined_microbit_path = None
         # Try to be helpful... essentially there is nothing Mu can do but
         # prompt for patience while the device is mounted and/or do the
         # classic "have you tried switching it off and on again?" trick.
         # This one's for James at the Raspberry Pi Foundation. ;-)
         message = _('Could not find an attached BBC micro:bit.')
         information = _("Please ensure you leave enough time for the BBC"
                         " micro:bit to be attached and configured"
                         " correctly by your computer. This may take"
                         " several seconds."
                         " Alternatively, try removing and re-attaching the"
                         " device or saving your work and restarting Mu if"
                         " the device remains unfound.")
         self.view.show_message(message, information)
Esempio n. 9
0
File: logic.py Progetto: ntoll/mu
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     logger.info('Flashing script')
     # Grab the Python script.
     tab = self._view.current_tab
     if tab is None:
         # There is no active text editor.
         return
     python_script = tab.text().encode('utf-8')
     logger.debug('Python script:')
     logger.debug(python_script)
     if len(python_script) >= 8192:
         message = 'Unable to flash "{}"'.format(tab.label)
         information = ("Your script is too long!.")
         self._view.show_message(message, information, 'Warning')
         return
     # Generate a hex file.
     python_hex = uflash.hexlify(python_script)
     logger.debug('Python hex:')
     logger.debug(python_hex)
     micropython_hex = uflash.embed_hex(uflash._RUNTIME, python_hex)
     # Determine the location of the BBC micro:bit. If it can't be found
     # fall back to asking the user to locate it.
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit is None:
         # Has the path to the device already been specified?
         if self.user_defined_microbit_path:
             path_to_microbit = self.user_defined_microbit_path
         else:
             # Ask the user to locate the device.
             path_to_microbit = self._view.get_microbit_path(HOME_DIRECTORY)
             # Store the user's specification of the path for future use.
             self.user_defined_microbit_path = path_to_microbit
             logger.debug('User defined path to micro:bit: {}'.format(
                          self.user_defined_microbit_path))
     # Check the path and that it exists simply because the path maybe based
     # on stale data.
     logger.debug('Path to micro:bit: {}'.format(path_to_microbit))
     if path_to_microbit and os.path.exists(path_to_microbit):
         logger.debug('Flashing to device.')
         hex_file = os.path.join(path_to_microbit, 'micropython.hex')
         uflash.save_hex(micropython_hex, hex_file)
         message = 'Flashing "{}" onto the micro:bit.'.format(tab.label)
         information = ("When the yellow LED stops flashing the device"
                        " will restart and your script will run. If there"
                        " is an error, you'll see a helpful message scroll"
                        " across the device's display.")
         self._view.show_message(message, information, 'Information')
     else:
         # Reset user defined path since it's incorrect.
         self.user_defined_microbit_path = None
         # Try to be helpful... essentially there is nothing Mu can do but
         # prompt for patience while the device is mounted and/or do the
         # classic "have you tried switching it off and on again?" trick.
         # This one's for James at the Raspberry Pi Foundation. ;-)
         message = 'Could not find an attached BBC micro:bit.'
         information = ("Please ensure you leave enough time for the BBC"
                        " micro:bit to be attached and configured correctly"
                        " by your computer. This may take several seconds."
                        " Alternatively, try removing and re-attaching the"
                        " device or saving your work and restarting Mu if"
                        " the device remains unfound.")
         self._view.show_message(message, information)
Esempio n. 10
0
 def flash(self):
     """
     Takes the currently active tab, compiles the Python script therein into
     a hex file and flashes it all onto the connected device.
     """
     logger.info('Flashing script.')
     # Grab the Python script.
     tab = self.view.current_tab
     if tab is None:
         # There is no active text editor.
         return
     python_script = tab.text().encode('utf-8')
     logger.debug('Python script:')
     logger.debug(python_script)
     # Check minification status.
     minify = False
     if uflash.get_minifier():
         minify = self.editor.minify
     if len(python_script) >= 8192:
         message = _('Unable to flash "{}"').format(tab.label)
         if minify and can_minify:
             orginal = len(python_script)
             script = python_script.decode('utf-8')
             try:
                 mangled = nudatus.mangle(script).encode('utf-8')
             except TokenError as e:
                 msg, (line, col) = e.args
                 logger.debug('Minify failed')
                 logger.exception(e)
                 message = _("Problem with script")
                 information = _("{} [{}:{}]").format(msg, line, col)
                 self.view.show_message(message, information, 'Warning')
                 return
             saved = orginal - len(mangled)
             percent = saved / orginal * 100
             logger.debug(
                 'Script minified, {} bytes ({:.2f}%) saved:'.format(
                     saved, percent))
             logger.debug(mangled)
             python_script = mangled
             if len(python_script) >= 8192:
                 information = _("Our minifier tried but your "
                                 "script is too long!")
                 self.view.show_message(message, information, 'Warning')
                 return
         elif minify and not can_minify:
             information = _("Your script is too long and the minifier"
                             " isn't available")
             self.view.show_message(message, information, 'Warning')
             return
         else:
             information = _("Your script is too long!")
             self.view.show_message(message, information, 'Warning')
             return
     # Determine the location of the BBC micro:bit. If it can't be found
     # fall back to asking the user to locate it.
     path_to_microbit = uflash.find_microbit()
     if path_to_microbit is None:
         # Has the path to the device already been specified?
         if self.user_defined_microbit_path:
             path_to_microbit = self.user_defined_microbit_path
         else:
             # Ask the user to locate the device.
             path_to_microbit = self.view.get_microbit_path(HOME_DIRECTORY)
             # Store the user's specification of the path for future use.
             self.user_defined_microbit_path = path_to_microbit
             logger.debug('User defined path to micro:bit: {}'.format(
                 self.user_defined_microbit_path))
     # Check the path and that it exists simply because the path maybe based
     # on stale data.
     logger.debug('Path to micro:bit: {}'.format(path_to_microbit))
     if path_to_microbit and os.path.exists(path_to_microbit):
         logger.debug('Flashing to device.')
         # Check use of custom runtime.
         rt_hex_path = self.editor.microbit_runtime.strip()
         message = _('Flashing "{}" onto the micro:bit.').format(tab.label)
         if (rt_hex_path and os.path.exists(rt_hex_path)):
             message = message + _(" Runtime: {}").format(rt_hex_path)
         else:
             rt_hex_path = None
             self.editor.microbit_runtime = ''
         self.editor.show_status_message(message, 10)
         self.set_buttons(flash=False)
         self.flash_thread = DeviceFlasher([path_to_microbit],
                                           python_script, rt_hex_path)
         if sys.platform == 'win32':
             # Windows blocks on write.
             self.flash_thread.finished.connect(self.flash_finished)
         else:
             # Other platforms don't block, so schedule the finish call
             # for 10 seconds (approximately how long flashing the device
             # takes).
             self.flash_timer = QTimer()
             self.flash_timer.timeout.connect(self.flash_finished)
             self.flash_timer.setSingleShot(True)
             self.flash_timer.start(10000)
         self.flash_thread.on_flash_fail.connect(self.flash_failed)
         self.flash_thread.start()
     else:
         # Reset user defined path since it's incorrect.
         self.user_defined_microbit_path = None
         # Try to be helpful... essentially there is nothing Mu can do but
         # prompt for patience while the device is mounted and/or do the
         # classic "have you tried switching it off and on again?" trick.
         # This one's for James at the Raspberry Pi Foundation. ;-)
         message = _('Could not find an attached BBC micro:bit.')
         information = _("Please ensure you leave enough time for the BBC"
                         " micro:bit to be attached and configured"
                         " correctly by your computer. This may take"
                         " several seconds."
                         " Alternatively, try removing and re-attaching the"
                         " device or saving your work and restarting Mu if"
                         " the device remains unfound.")
         self.view.show_message(message, information)