Exemple #1
0
def test_find_microbit_unknown_os():
    """
    Raises a NotImplementedError if the host OS is not supported.
    """
    with mock.patch('os.name', 'foo'):
        with pytest.raises(NotImplementedError) as ex:
            uflash.find_microbit()
    assert ex.value.args[0] == 'OS "foo" not supported.'
Exemple #2
0
def test_find_microbit_unknown_os():
    """
    Raises a NotImplementedError if the host OS is not supported.
    """
    with mock.patch('os.name', 'foo'):
        with pytest.raises(NotImplementedError) as ex:
            uflash.find_microbit()
    assert ex.value.args[0] == 'OS "foo" not supported.'
def flash(pythonfile):
    drive = uflash.find_microbit()
    tryn = 0
    while drive == "":
        if tryn == 1:
            print("Please plug in a microbit")
        tryn = tryn + 1
        input()
        drive = uflash.find_microbit()
    pyfilenoext = pythonfile[:-3]
    os.system("cd " + os.getcwd())
    os.system('py2hex "' + pythonfile + '"')
    print("Moving to microbit.")
    shutil.move(pyfilenoext + ".hex", drive)
    print("Done!")
def flashF(folder):
    print("MicroBit is at: " + microfs.find_microbit()[0] +
          "\nMicroBit directory is at: " + uflash.find_microbit())
    try:
        mfiles = microfs.ls()
    except OSError as e:
        print(
            str(e) +
            "\nMicrobit is probably calibrating, calibrate and then try again\nIf it still does not work try to "
            "replug your microbit or close other programs that is accessing your microbit"
        )
        return "Could not write"
    print("Removing old stuff: " + str(mfiles))
    for file in mfiles:
        microfs.rm(file)

    files = os.listdir(folder)
    print("Flashing new stuff: " + str(files))
    for file in files:
        microfs.put(folder + "\\" + file)

    print("Flashed new stuff: " + str(microfs.ls()) + "\n")

    time.sleep(0.1)
    print("Done!" + "\n" + "Don't forget to name your main file \"main.py\"" +
          "\n" + InternalTools.bcolors.BOLD +
          "Reset your MicroBit to apply changes!")
Exemple #5
0
def test_find_microbit_nt_removable_only():
    """
    We should only be considering removable drives as candidates for
    micro:bit devices. (Especially so as to avoid interrogating disconnected
    network drives).

    Have every drive claim to be a micro:bit, but only drive B: claim
    to be removable
    """
    def _drive_type(letter):
        if letter == "B:\\":
            return 2  # removable
        else:
            return 4  # network

    mock_windll = mock.MagicMock()
    mock_windll.kernel32 = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW.return_value = None
    mock_windll.kernel32.GetDriveTypeW = mock.MagicMock()
    mock_windll.kernel32.GetDriveTypeW.side_effect = _drive_type
    with mock.patch('os.name', 'nt'):
        with mock.patch('os.path.exists', return_value=True):
            return_value = ctypes.create_unicode_buffer('MICROBIT')
            with mock.patch('ctypes.create_unicode_buffer',
                            return_value=return_value):
                ctypes.windll = mock_windll
                assert uflash.find_microbit() == 'B:\\'
Exemple #6
0
def test_find_microbit_posix_missing():
    """
    Simulate being on os.name == 'posix' and a call to "mount" returns a
    no records associated with a micro:bit device.
    """
    with open('tests/mount_missing.txt', 'rb') as fixture_file:
        fixture = fixture_file.read()
        with mock.patch('os.name', 'posix'):
            with mock.patch('uflash.check_output', return_value=fixture):
                assert uflash.find_microbit() is None
Exemple #7
0
def test_find_microbit_posix_exists():
    """
    Simulate being on os.name == 'posix' and a call to "mount" returns a
    record indicating a connected micro:bit device.
    """
    with open('tests/mount_exists.txt', 'rb') as fixture_file:
        fixture = fixture_file.read()
        with mock.patch('os.name', 'posix'):
            with mock.patch('uflash.check_output', return_value=fixture):
                assert uflash.find_microbit() == '/media/ntoll/MICROBIT'
Exemple #8
0
def test_find_microbit_posix_exists():
    """
    Simulate being on os.name == 'posix' and a call to "mount" returns a
    record indicating a connected micro:bit device.
    """
    with open('tests/mount_exists.txt', 'rb') as fixture_file:
        fixture = fixture_file.read()
        with mock.patch('os.name', 'posix'):
            with mock.patch('uflash.check_output', return_value=fixture):
                assert uflash.find_microbit() == '/media/ntoll/MICROBIT'
Exemple #9
0
def test_find_microbit_posix_missing():
    """
    Simulate being on os.name == 'posix' and a call to "mount" returns a
    no records associated with a micro:bit device.
    """
    with open('tests/mount_missing.txt', 'rb') as fixture_file:
        fixture = fixture_file.read()
        with mock.patch('os.name', 'posix'):
            with mock.patch('uflash.check_output', return_value=fixture):
                assert uflash.find_microbit() is None
Exemple #10
0
def flash_io_runtime():
    """Flashes MicroPython with the default IO .hex"""
    try:
        microbit_path = uflash.find_microbit()
        if microbit_path:
            _BITIO_RUNTIME = os.path.join(os.path.dirname(__file__), "res",
                                          "bitio.hex")
            uflash.flash(path_to_runtime=_BITIO_RUNTIME)
            showinfo("Flashing micro:bit",
                     "Flashing the I/O .hex to micro:bit")
    except Exception:
        error_msg = traceback.format_exc(0) + '\n'
        showerror("Error", error_msg)
Exemple #11
0
def test_find_microbit_nt_missing():
    """
    Simulate being on os.name == 'nt' and a disk with a volume name 'MICROBIT'
    does not exist for a micro:bit device.
    """
    mock_windll = mock.MagicMock()
    mock_windll.kernel32 = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW.return_value = None
    with mock.patch('os.name', 'nt'):
        with mock.patch('os.path.exists', return_value=True):
            return_value = ctypes.create_unicode_buffer(1024)
            with mock.patch('ctypes.create_unicode_buffer',
                            return_value=return_value):
                ctypes.windll = mock_windll
                assert uflash.find_microbit() is None
Exemple #12
0
def test_find_microbit_nt_missing():
    """
    Simulate being on os.name == 'nt' and a disk with a volume name 'MICROBIT'
    does not exist for a micro:bit device.
    """
    mock_windll = mock.MagicMock()
    mock_windll.kernel32 = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW.return_value = None
    with mock.patch('os.name', 'nt'):
        with mock.patch('os.path.exists', return_value=True):
            return_value = ctypes.create_unicode_buffer(1024)
            with mock.patch('ctypes.create_unicode_buffer',
                            return_value=return_value):
                ctypes.windll = mock_windll
                assert uflash.find_microbit() is None
Exemple #13
0
def test_find_microbit_nt_exists():
    """
    Simulate being on os.name == 'nt' and a disk with a volume name 'MICROBIT'
    exists indicating a connected micro:bit device.
    """
    mock_windll = mock.MagicMock()
    mock_windll.kernel32 = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW = mock.MagicMock()
    mock_windll.kernel32.GetVolumeInformationW.return_value = None
    #
    # Have every drive claim to be removable
    #
    mock_windll.kernel32.GetDriveTypeW = mock.MagicMock()
    mock_windll.kernel32.GetDriveTypeW.return_value = 2
    with mock.patch('os.name', 'nt'):
        with mock.patch('os.path.exists', return_value=True):
            return_value = ctypes.create_unicode_buffer('MICROBIT')
            with mock.patch('ctypes.create_unicode_buffer',
                            return_value=return_value):
                ctypes.windll = mock_windll
                assert uflash.find_microbit() == 'A:\\'
Exemple #14
0
    def readyMicroBit(self, printb=False):
        # shutil.copyfile(os.getcwd() + "\\src\\" + "microbitserialsystem.hex", self.microbitpath+"SerialSystem.hex")
        # shutil.copy
        if printb:
            print("Downloading HEX")
        url = readymicrobithexurl
        r = requests.get(url)
        if printb:
            print("Downloaded HEX")
            print("Fixing HEX")
        content = ""
        # contentb = r.content
        # contentb = str(contentb)
        # contentb = contentb[:-1]
        # contentb = contentb[2:]
        # contentsplit = contentb.split("\\n")
        # for i in contentsplit:
        #     content = content + i + "\n"
        content = r.content.decode("UTF-8")
        if printb:
            print("Fixed HEX\n" + content)
            print("Moving HEX to microbit")

        try:
            file = open("SerialSystem.hex", "w")

            file.write(content)

            file.close()

            shutil.move("SerialSystem.hex",
                        uflash.find_microbit() + "SerialSystem.hex")
        except shutil.Error as e:
            print(e)
            print("SerialSystem hex already installed")
            os.remove(os.getcwd() + "\\SerialSystem.hex")
        if printb:
            print("Moved HEX to microbit")
Exemple #15
0
class SerialSystem:
    ser = microfs.get_serial()
    ser.baudrate = 115200
    ser.close()

    microbitpath = uflash.find_microbit()
    before = {
        'Buttons': {
            'A': False,
            'B': False
        },
        'Temp': 20,
        'CompassHeading': 369,
        'Accelerometer': {
            'Y': 0,
            'X': 0,
            'Z': 0
        },
        'Brightness': 0
    }

    def close(self):
        self.ser.close()

    def open(self):
        try:
            self.ser.open()
        except serial.serialutil.SerialException as e:
            print(str(e))

    # FIXA
    def readyMicroBit(self, printb=False):
        # shutil.copyfile(os.getcwd() + "\\src\\" + "microbitserialsystem.hex", self.microbitpath+"SerialSystem.hex")
        # shutil.copy
        if printb:
            print("Downloading HEX")
        url = readymicrobithexurl
        r = requests.get(url)
        if printb:
            print("Downloaded HEX")
            print("Fixing HEX")
        content = ""
        # contentb = r.content
        # contentb = str(contentb)
        # contentb = contentb[:-1]
        # contentb = contentb[2:]
        # contentsplit = contentb.split("\\n")
        # for i in contentsplit:
        #     content = content + i + "\n"
        content = r.content.decode("UTF-8")
        if printb:
            print("Fixed HEX\n" + content)
            print("Moving HEX to microbit")

        try:
            file = open("SerialSystem.hex", "w")

            file.write(content)

            file.close()

            shutil.move("SerialSystem.hex",
                        uflash.find_microbit() + "SerialSystem.hex")
        except shutil.Error as e:
            print(e)
            print("SerialSystem hex already installed")
            os.remove(os.getcwd() + "\\SerialSystem.hex")
        if printb:
            print("Moved HEX to microbit")

    def display(self,
                screen=[[5, 6, 7, 6, 5], [6, 7, 8, 7, 6], [7, 8, 9, 8, 7],
                        [6, 7, 8, 7, 6], [5, 6, 7, 6, 5]]):
        fixedscreen = [0, 0, 0, 0, 0]
        yn = 0
        for y in screen:
            tempstring = ""
            xn = 0
            for x in y:
                tempstring = tempstring + str(screen[yn][xn])
                xn = xn + 1
            if y != 4:
                tempstring = tempstring + ":"
            fixedscreen[yn] = tempstring
            yn = yn + 1

        try:
            self.ser.open()
        except serial.serialutil.SerialException as e:
            pass  # print(str(e))
        self.ser.write(bytes("?" + str(fixedscreen).replace(" ", ""), 'utf-8'))

    def readRaw(self):
        try:
            self.ser.open()
        except serial.serialutil.SerialException as e:
            pass  # print(str(e))
        data_raw = self.ser.readline()
        try:
            if data_raw != b'':
                return (data_raw.decode("utf-8"))
        except UnicodeEncodeError as e:
            print("Skipping because of error: " + str(e))

    def read(self):
        try:
            self.ser.open()
        except serial.serialutil.SerialException as e:
            pass  # print(str(e))
        try:
            mbd = self.ser.readline().decode("UTF-8")
            mbd = mbd.replace("'", '"')
        except serial.serialutil.SerialException:
            return {"Error": "Can not find MicroBit"}
        except UnicodeDecodeError as e:
            mbd = ""
            time.sleep(0.5)
            print(e)
        except IndexError:
            return {"Error": "Unknown error"}
        if mbd.startswith("?"):
            mbds = mbd.split("?")
            try:
                result = json.loads(mbds[1])
                if result["Buttons"]["A"] == "true":
                    result["Buttons"]["A"] = True
                elif result["Buttons"]["A"] == "false":
                    result["Buttons"]["A"] = False

                if result["Buttons"]["B"] == "true":
                    result["Buttons"]["B"] = True
                elif result["Buttons"]["B"] == "false":
                    result["Buttons"]["B"] = False
            except json.decoder.JSONDecodeError as e:
                print(mbds[1])
                print(e)
                result = {
                    "Error":
                    "Cant convert Json (MicroBit probably is using wrong firmware)"
                }
        else:
            result = self.before

        self.before = result
        return result
import sys
import uflash

if len(sys.argv) > 1:
	filename = sys.argv[1]
else:
	print "Missing filename on command line."
	sys.exit(1)

print "File: " + filename

print "Looking for micro:bit..."

microbitPath = uflash.find_microbit()

if microbitPath == None:
	print "Cannot find micro:bit. Check that it is plugged in via USB."
	sys.exit(1)

print "micro:bit found @ " + microbitPath

print "uflash version " + uflash.get_version()

uflash.flash(filename, microbitPath)
Exemple #17
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)