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)
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)
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
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)
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)
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)
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)
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)
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)
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)