def copy_file(self, source, destination): """ copy file from os """ self.logger.debug('read source file') try: with open(source, 'rb') as source_file: aux_source = source_file.read() except (IOError, OSError): self.logger.exception("File couldn't be read") raise FlashError(message="File couldn't be read", return_code=EXIT_CODE_FILE_COULD_NOT_BE_READ) self.logger.debug("SHA1: %s", hashlib.sha1(aux_source).hexdigest()) self.logger.debug("writing binary: %s (size=%i bytes)", destination, len(aux_source)) try: with open(destination, "wb", 0) as new_file: new_file.write(aux_source) new_file.flush() os.fsync(new_file.fileno()) except (IOError, OSError): self.logger.exception("File couldn't be copied") raise FlashError(message="File couldn't be copied", return_code=EXIT_CODE_OS_ERROR)
def try_pyocd_flash(self, source, target): """ try pyOCD flash """ try: from pyOCD.board import MbedBoard except ImportError: # python 3 compatibility # pylint: disable=superfluous-parens raise FlashError(message="PyOCD is missing", return_code=EXIT_CODE_PYOCD_NOT_INSTALLED) try: with MbedBoard.chooseBoard(board_id=target["target_id"]) as board: ocd_target = board.target ocd_flash = board.flash self.logger.debug("resetting device: %s", target["target_id"]) sleep(0.5) # small sleep for lesser HW ie raspberry ocd_target.reset() self.logger.debug("flashing device: %s", target["target_id"]) ocd_flash.flashBinary(source) self.logger.debug("resetting device: %s", target["target_id"]) sleep(0.5) # small sleep for lesser HW ie raspberry ocd_target.reset() return EXIT_CODE_SUCCESS except AttributeError as err: msg = "Flashing failed: {}. tid={}".format(err, target["target_id"]) self.logger.error(msg) raise FlashError(message="PyOCD flash failed", return_code=EXIT_CODE_FLASH_FAILED)
def _do_flash(flasher, build, target, method, no_reset): try: return flasher.flash( source=build, target=target, method=method, no_reset=no_reset) except KeyboardInterrupt: raise FlashError(message="Aborted by user", return_code=EXIT_CODE_KEYBOARD_INTERRUPT) except SystemExit: raise FlashError(message="Aborted by SystemExit event", return_code=EXIT_CODE_SYSTEM_INTERRUPT)
def flash(self, source, target, method, no_reset, target_filename=None): """flash device :param source: binary to be flashed :param target: target to be flashed :param method: method to use when flashing :param no_reset: do not reset flashed board at all :param target_filename: target filename (not in use) :return: 0 when flashing success """ cmd_script = tempfile.NamedTemporaryFile(delete=False) FlasherJLink._write_file_contents(cmd_script, source, no_reset) cmd_script.close() def remove_commander_script(): """ Removes the temporary file. Cannot use delete=True for NamedTemporaryFile since Windows doesn't allow another program to read it while not closed. """ os.remove(cmd_script.name) try: args = [ FlasherJLink.executable, "-if", "swd", "-speed", "auto", "-device", target["jlink_device_name"], "-SelectEmuBySN", target["target_id"], "-commanderscript", cmd_script.name ] except KeyError: remove_commander_script() raise FlashError(message="Invalid target", return_code=EXIT_CODE_FLASH_FAILED) try: self.logger.info("Flashing {} with command {}".format(target["target_id"], args)) returncode, output = self._start_and_wait_flash(args, FlasherJLink.executable) except queue.Empty: raise FlashError(message="No returncode from JLinkExe", return_code=EXIT_CODE_FLASH_FAILED) finally: remove_commander_script() if returncode != 0: self.logger.error("Flash of {} failed, with returncode {}" .format(target["target_id"], returncode)) msg = "Flash failed with JLink return code: {}".format(returncode) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) self.logger.info("Flash of {} succeeded".format(target["target_id"])) self.logger.debug(output) return EXIT_CODE_SUCCESS
def copy_file(self, source, destination): """ copy file from os """ self.logger.debug('read source file') with open(source, 'rb') as source_file: aux_source = source_file.read() if not aux_source: raise FlashError(message="File couldn't be read", return_code=EXIT_CODE_FILE_COULD_NOT_BE_READ) self.logger.debug("SHA1: %s", hashlib.sha1(aux_source).hexdigest()) if platform.system() == 'Windows': self.logger.debug("copying file: \"%s\" to \"%s\"", source, destination) os.system("copy \"%s\" \"%s\"" % (os.path.abspath(source), destination)) else: self.logger.debug("writing binary: %s (size=%i bytes)", destination, len(aux_source)) new_file = self.get_file(destination) os.write(new_file, aux_source) os.close(new_file)
def flash(self, source, target, method, no_reset): """copy file to the destination :param source: binary to be flashed :param target: target to be flashed :param method: method to use when flashing :param no_reset: do not reset flashed board at all """ if not isinstance(source, six.string_types): return if method == 'pyocd': self.logger.debug("pyOCD selected for flashing") return self.try_pyocd_flash(source, target) if method == 'edbg': raise FlashError(message="edbg is not supported for Mbed devices", return_code=EXIT_CODE_EGDB_NOT_SUPPORTED) return retry( logger=self.logger, func=self.try_drag_and_drop_flash, func_args=(source, target, no_reset), retries=FlasherMbed.DRAG_AND_DROP_FLASH_RETRIES, conditions=[EXIT_CODE_OS_ERROR, EXIT_CODE_DAPLINK_TRANSIENT_ERROR, EXIT_CODE_DAPLINK_SOFTWARE_ERROR])
def test_flash_fails(self, mock_build, mock_flasher, mocked_logger, mock_inspect, mock_bench_logger): mock_build_object = mock.MagicMock() mock_build_object.get_file = mock.MagicMock(return_value="Thisbin") mock_build.init = mock.MagicMock(return_value=mock_build_object) mock_inspect.return_value = MockArgspec(["logger"]) mocked_logger_for_flasher = mock.MagicMock() mocked_logger.return_value = mocked_logger_for_flasher mock_flasher_object = mock.MagicMock() mock_flasher.return_value = mock_flasher_object mock_flasher_object.flash = mock.MagicMock() mock_flasher_object.flash.side_effect = [ NotImplementedError, SyntaxError, 1 ] if FlashError is not None: mock_flasher_object.flash.side_effect = [ NotImplementedError, SyntaxError, 1, FlashError("Error", 10) ] dut = DutSerial(port="test", config={ "allocated": { "target_id": "thing" }, "application": "thing" }) with self.assertRaises(DutConnectionError): dut.flash("try") with self.assertRaises(DutConnectionError): dut.flash("try2") self.assertFalse(dut.flash("try3")) if FlashError is not None: with self.assertRaises(DutConnectionError): dut.flash("try4")
def flash_multiple(self, build, platform_name, method='simple', target_ids_or_prefix='', no_reset=None): """ :param build: build :param platform_name: platform name :param method: method :param target_ids_or_prefix: target ids or prefix :param no_reset: with/without reset :return: """ device_mapping_table = Common( self.logger).get_available_device_mapping(self._flashers) if not platform_name: Flash._verify_platform_coherence(device_mapping_table) if isinstance(target_ids_or_prefix, list): aux_device_mapping_table = Flash._map_by_target_id( device_mapping_table=device_mapping_table, platform_name=platform_name, target_ids=target_ids_or_prefix) elif target_ids_or_prefix: aux_device_mapping_table = Flash._map_by_prefix( device_mapping_table=device_mapping_table, platform_name=platform_name, prefix=target_ids_or_prefix) else: aux_device_mapping_table = Flash._map_by_platform( device_mapping_table=device_mapping_table, platform_name=platform_name) if aux_device_mapping_table: device_mapping_table = aux_device_mapping_table if not device_mapping_table: raise FlashError( message="no devices to flash", return_code=EXIT_CODE_COULD_NOT_MAP_TARGET_ID_TO_DEVICE) self.logger.debug(device_mapping_table) self.logger.info('Going to flash following devices:') for item in device_mapping_table: self.logger.info(item['target_id']) for device in device_mapping_table: self.flash(build=build, target_id=device['target_id'], platform_name=None, device_mapping_table=device_mapping_table, method=method, no_reset=no_reset) return EXIT_CODE_SUCCESS
def try_drag_and_drop_flash(self, source, target, target_filename, no_reset): """ Try to flash the target using drag and drop method. :param source: file to be flashed :param target: target board to be flashed :param no_reset: whether to reset the board after flash :return: 0 if success """ target = MbedCommon.refresh_target(target["target_id"]) if not target: raise FlashError(message="Target ID is missing", return_code=EXIT_CODE_TARGET_ID_MISSING) destination = MbedCommon.get_binary_destination( target["mount_point"], target_filename) try: if 'serial_port' in target and not no_reset: Reset(logger=self.logger).reset_board(target["serial_port"]) sleep(0.1) self.copy_file(source, destination) self.logger.debug("copy finished") target = MbedCommon.wait_for_file_disappear( target, target_filename) if not no_reset: Reset(logger=self.logger).reset_board(target["serial_port"]) sleep(0.4) # verify flashing went as planned self.logger.debug("verifying flash") return self.verify_flash_success( target, MbedCommon.get_binary_destination(target["mount_point"], target_filename)) # In python3 IOError is just an alias for OSError except (OSError, IOError) as error: msg = "File copy failed due to: {}".format(str(error)) self.logger.exception(msg) raise FlashError(message=msg, return_code=EXIT_CODE_OS_ERROR)
def flash(self, source, target, method, no_reset, target_filename=None): """flash device :param source: binary to be flashed :param target: target to be flashed :param method: method to use when flashing :param no_reset: do not reset flashed board at all :param target_filename: target filename (not in use) :return: 0 when flashing success """ try: args = [ FlasherSTLink.executable, "-c", "SN=" + target['target_id_usb_id'], # chip to be flash "-P", source, "0x08000000", # Loads file into device memory "-V" # Verifies that the programming operation was performed successfully. ] except KeyError: raise FlashError(message="Invalid target", return_code=EXIT_CODE_FLASH_FAILED) try: self.logger.info("Flashing {} with command {}".format( target["target_id"], args)) returncode, output = self._start_and_wait_flash( args, FlasherSTLink.executable) except queue.Empty: raise FlashError(message="No returncode from ST-LINK_CLI", return_code=EXIT_CODE_FLASH_FAILED) if returncode != 0: self.logger.error("Flash of {} failed, with returncode {}".format( target["target_id"], returncode)) self.logger.debug(output if output else "") msg = "Flash failed with STLink return code: {}".format(returncode) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) self.logger.info("Flash of {} succeeded".format(target["target_id"])) self.logger.debug(output) return EXIT_CODE_SUCCESS
def verify_flash_success(self, target, file_path): """ verify flash went well """ mount = target['mount_point'] if isfile(join(mount, 'FAIL.TXT')): fault = FlasherMbed._read_file(mount, "FAIL.TXT") self.logger.error("Flashing failed: %s. tid=%s", fault, target["target_id"]) try: errors = [error for error in DAPLINK_ERRORS if error in fault] assert len(errors) <= 1 raise FlashError(message=fault, return_code=DAPLINK_ERRORS[errors[0]]) except AssertionError: msg = "Found multiple errors from FAIL.TXT: {}".format(fault) self.logger.exception(msg) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) except IndexError: msg = "Error in FAIL.TXT is unknown: {}".format(fault) self.logger.exception(msg) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) if isfile(join(mount, 'ASSERT.TXT')): fault = FlasherMbed._read_file(mount, "ASSERT.TXT") msg = "Found ASSERT.TXT: {}".format(fault) self.logger.error("{} found ASSERT.txt: {}".format( target["target_id"], fault)) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) if isfile(file_path): msg = "File still present in mount point" self.logger.error("{} file still present in mount point".format( target["target_id"])) raise FlashError(message=msg, return_code=EXIT_CODE_FILE_STILL_PRESENT) self.logger.debug("ready") return EXIT_CODE_SUCCESS
def get_flasher(flasher=None): """ :param flasher: None, if not given a flasher :return: return available flasher if found, otherwise return exit code """ for available_flasher in AvailableFlashers: if available_flasher.name.lower() == flasher.lower(): return available_flasher raise FlashError(message="Requested flasher does not exist", return_code=EXIT_CODE_REQUESTED_FLASHER_DOES_NOT_EXIST)
def verify_flash_success(self, target, file_path): """ verify flash went well """ mount = target['mount_point'] if isfile(join(mount, 'FAIL.TXT')): fault = FlasherMbed._read_file(mount, "FAIL.TXT") self.logger.error("Flashing failed: %s. tid=%s", fault, target["target_id"]) try: errors = [error for error in DAPLINK_ERRORS if error in fault] assert len(errors) == 1 raise FlashError(message=fault, return_code=DAPLINK_ERRORS[errors[0]]) except AssertionError: msg = "Expected to find exactly one error in fault: {}".format( fault) self.logger.exception(msg) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) except KeyError: msg = "Did not find error with key {}".format(fault) self.logger.exception(msg) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) if isfile(join(mount, 'ASSERT.TXT')): fault = FlasherMbed._read_file(mount, "ASSERT.TXT") msg = "Flashing failed: {}. tid={}".format(fault, target) raise FlashError(message=msg, return_code=EXIT_CODE_FLASH_FAILED) if isfile(file_path): msg = "Flashing failed: File still present in mount point. tid info: {}".format( target) raise FlashError(message=msg, return_code=EXIT_CODE_FILE_STILL_PRESENT) self.logger.debug("ready") return EXIT_CODE_SUCCESS
def _verify_platform_coherence(device_mapping_table): """ Verify platform is same across devices. :param device_mapping_table: list of devices to verify :return: return code """ found_platform = '' for item in device_mapping_table: if not found_platform: found_platform = item['platform_name'] elif item['platform_name'] != found_platform: msg = "Multiple devices and platforms found, please specify " \ "preferred platform with -t <platform>." raise FlashError(message=msg, return_code=EXIT_CODE_PLATFORM_REQUIRED)
def copy_file(self, source, destination): """ copy file from os """ self.logger.debug('read source file') try: with open(source, 'rb') as source_file: aux_source = source_file.read() except (IOError, OSError): self.logger.exception("File couldn't be read") raise FlashError(message="File couldn't be read", return_code=EXIT_CODE_FILE_COULD_NOT_BE_READ) self.logger.debug("SHA1: %s", hashlib.sha1(aux_source).hexdigest()) try: if platform.system() == "Windows": self._copy_file_windows(source, destination) else: self._copy_file(aux_source, destination) except (IOError, OSError, subprocess.CalledProcessError): self.logger.exception("File couldn't be copied") raise FlashError(message="File couldn't be copied", return_code=EXIT_CODE_OS_ERROR)
def test_does_not_retry_on_daplink_user_error(self, mock_copy_file, mock_reset_board, mock_refresh_target): target = {"target_id": "a", "mount_point": ""} mock_copy_file.side_effect = FlashError( message="", return_code=EXIT_CODE_DAPLINK_USER_ERROR) mock_reset_board.return_value = True mock_refresh_target.return_value = target flasher = FlasherMbed() with self.assertRaises(FlashError) as cm: flasher.flash(source="", target=target, method="simple", no_reset=False) self.assertEqual(cm.exception.return_code, EXIT_CODE_DAPLINK_USER_ERROR) self.assertEqual(mock_copy_file.call_count, 1)
def reset_board(self, serial_port): """ Reset board """ try: port = EnhancedSerial(serial_port) except SerialException as err: self.logger.exception("reset could not be sent") # SerialException.message is type "string" # pylint: disable=no-member if err.message.find('could not open port') != -1: # python 3 compatibility # pylint: disable=superfluous-parens self.logger.error( "Reset could not be given. Close your Serial connection to device." ) raise FlashError(message="Reset failed", return_code=EXIT_CODE_RESET_FAIL) port.baudrate = 115200 port.timeout = 1 port.xonxoff = False port.rtscts = False port.flushInput() port.flushOutput() if port: self.logger.info("sendBreak to device to reboot") result = port.safe_send_break() if result: self.logger.info("reset completed") else: self.logger.info("reset failed") port.close()
def subcmd_flash_handler(self, args): """ flash command handler """ if not args.tid: msg = "Target_id is missing" raise FlashError(message=msg, return_code=EXIT_CODE_TARGET_ID_MISSING) check_file(self.logger, args.target_filename or args.input) check_file(self.logger, args.input) check_file_exists(self.logger, args.input) check_file_extension(self.logger, args.target_filename or args.input) flasher = Flash() available = Common(self.logger).get_available_device_mapping( flasher.get_all_flashers(), args.tid) available_target_ids = [] retcode = EXIT_CODE_SUCCESS if args.platform_name: if args.platform_name not in flasher.get_supported_targets(): self.logger.error("Not supported platform: %s", args.platform_name) self.logger.error("Supported platforms: %s", flasher.get_supported_targets()) raise FlashError(message="Platform {} not supported".format( args.platform_name), return_code=EXIT_CODE_NOT_SUPPORTED_PLATFORM) if 'all' in args.tid: retcode = flasher.flash(build=args.input, target_id='all', platform_name=args.platform_name, target_filename=args.target_filename, method=args.method, no_reset=args.no_reset) if len(available) <= 0: msg = "Could not find any connected device" raise FlashError(message=msg, return_code=EXIT_CODE_DEVICES_MISSING) available_platforms, target_ids_to_flash = \ self.prepare_platforms_and_targets(available, args.tid, available_target_ids) if not target_ids_to_flash: self.logger.error( "Could not find given target_id from attached devices") self.logger.error("Available target_ids: %s", available_target_ids) raise FlashError(message="Could not map device", return_code=EXIT_CODE_COULD_NOT_MAP_DEVICE) elif len(available_platforms) > 1: if not args.platform_name: self.logger.error( "More than one platform detected for given target_id") self.logger.error( "Please specify the platform with -t <PLATFORM_NAME>") self.logger.error("Found platforms: %s", available_platforms) raise FlashError( message= "More than one platform detected for given target id", return_code=EXIT_CODE_PLATFORM_REQUIRED) else: retcode = flasher.flash(build=args.input, target_id=target_ids_to_flash, target_filename=args.target_filename, platform_name=available_platforms[0], method=args.method, no_reset=args.no_reset) return retcode
def func(): self.call_count += 1 raise FlashError(message="", return_code=1)
def flash(self, build, target_id=None, platform_name=None, device_mapping_table=None, method='simple', no_reset=None, target_filename=None): """Flash (mbed) device :param build: string (file-path) :param target_id: target_id :param platform_name: platform_name, to flash multiple devices of same type :param device_mapping_table: individual devices mapping table :param method: method for flashing i.e. simple, pyocd or edbg :param no_reset: whether to reset the board after flash :param target_filename: optional Target filename """ k64f_target_id_length = 48 if target_id is None and platform_name is None: raise SyntaxError("target_id or target_name is required") target_filename = target_filename or build check_file(self.logger, target_filename) check_file(self.logger, build) check_file_extension(self.logger, target_filename) check_file_exists(self.logger, build) if (isinstance(target_id, list) or target_id.lower() == 'all' or (len(target_id) < k64f_target_id_length and device_mapping_table is None)): if isinstance(target_id, str) and target_id.lower() == 'all': target_id = '' return self.flash_multiple( build=build, platform_name=platform_name, method=method, target_ids_or_prefix=target_id, no_reset=no_reset, target_filename=target_filename) device_mapping_table = self._refine__device_mapping_table( device_mapping_table, target_id) try: if target_id: target_mbed = self.__find_by_target_id(target_id, device_mapping_table) else: target_mbed = self.__find_by_platform_name(platform_name, device_mapping_table) except KeyError: msg = "Could not find required device" self.logger.exception(msg) raise FlashError(message=msg, return_code=EXIT_CODE_COULD_NOT_MAP_TARGET_ID_TO_DEVICE) platform_name = self._get_platform_name(platform_name, target_mbed) self.logger.debug("Flashing: %s", target_mbed["target_id"]) flasher = self.__get_flasher(platform_name, target_mbed) retcode = Flash._do_flash(flasher=flasher, build=build, target=target_mbed, method=method, no_reset=no_reset, target_filename=target_filename) if retcode == EXIT_CODE_SUCCESS: self.logger.info("%s flash success", target_mbed["target_id"]) else: self.logger.warning("%s flash fails with code %d", target_mbed["target_id"], retcode) return retcode
def test_can_be_risen(self): with self.assertRaises(FlashError) as cm: raise FlashError(message="test", return_code=0) self.assertEqual(cm.exception.message, "test") self.assertEqual(cm.exception.return_code, 0)