diff --git a/mbed_host_tests/__init__.py b/mbed_host_tests/__init__.py index dda8da3..3205181 100644 --- a/mbed_host_tests/__init__.py +++ b/mbed_host_tests/__init__.py @@ -135,6 +135,7 @@ def flash_dev(disk=None, result = host_tests_plugins.call_plugin('CopyMethod', copy_method, image_path=image_path, + serial=port, destination_disk=disk) sleep(program_cycle_s) return result diff --git a/mbed_host_tests/host_tests_plugins/__init__.py b/mbed_host_tests/host_tests_plugins/__init__.py index 567c7c6..cae08de 100644 --- a/mbed_host_tests/host_tests_plugins/__init__.py +++ b/mbed_host_tests/host_tests_plugins/__init__.py @@ -36,6 +36,8 @@ import module_reset_silabs import module_copy_stlink import module_reset_stlink +import module_copy_jn51xx +import module_reset_jn51xx # Plugin registry instance @@ -55,6 +57,8 @@ HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_silabs.load_plugin()) HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_copy_stlink.load_plugin()) HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_stlink.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_copy_jn51xx.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_jn51xx.load_plugin()) # TODO: extend plugin loading to files with name module_*.py loaded ad-hoc diff --git a/mbed_host_tests/host_tests_plugins/host_test_plugins.py b/mbed_host_tests/host_tests_plugins/host_test_plugins.py index e6ea9fc..1c965fa 100644 --- a/mbed_host_tests/host_tests_plugins/host_test_plugins.py +++ b/mbed_host_tests/host_tests_plugins/host_test_plugins.py @@ -41,6 +41,7 @@ class HostTestPluginBase: type = "BasePlugin" # Plugin type: ResetMethod, Copymethod etc. capabilities = [] # Capabilities names: what plugin can achieve # (e.g. reset using some external command line tool) + required_parameters = [] # Parameters required for 'kwargs' in plugin APIs: e.g. self.execute() stable = False # Determine if plugin is stable and can be used ########################################################################### @@ -64,6 +65,17 @@ def execute(self, capability, *args, **kwargs): """ return False + def is_os_supported(self, os_name=None): + """! + @return Returns true if plugin works (supportes) under certain OS + @os_name String describing OS. + See self.mbed_os_support() and self.mbed_os_info() + @details In some cases a plugin will not work under particular OS + mainly because command / software used to implement plugin + functionality is not available e.g. on MacOS or Linux. + """ + return True + ########################################################################### # Interface helper methods - overload only if you need to have custom behaviour ########################################################################### @@ -130,8 +142,8 @@ def check_parameters(self, capability, *args, **kwargs): for parameter in self.required_parameters: if parameter not in kwargs: missing_parameters.append(parameter) - if len(missing_parameters) > 0: - self.print_plugin_error("execute parameter(s) '%s' missing!"% (', '.join(parameter))) + if len(missing_parameters): + self.print_plugin_error("execute parameter(s) '%s' missing!"% (', '.join(missing_parameters))) return False return True diff --git a/mbed_host_tests/host_tests_plugins/host_test_registry.py b/mbed_host_tests/host_tests_plugins/host_test_registry.py index 296e9e8..b2aaa0b 100644 --- a/mbed_host_tests/host_tests_plugins/host_test_registry.py +++ b/mbed_host_tests/host_tests_plugins/host_test_registry.py @@ -94,7 +94,7 @@ def get_string(self): @return Returns string formatted with PrettyTable """ from prettytable import PrettyTable - column_names = ['name', 'type', 'capabilities', 'stable'] + column_names = ['name', 'type', 'capabilities', 'stable', 'os_support', 'required_parameters'] pt = PrettyTable(column_names) for column in column_names: pt.align[column] = 'l' @@ -103,7 +103,9 @@ def get_string(self): type = self.PLUGINS[plugin_name].type stable = self.PLUGINS[plugin_name].stable capabilities = ', '.join(self.PLUGINS[plugin_name].capabilities) - row = [name, type, capabilities, stable] + is_os_supported = self.PLUGINS[plugin_name].is_os_supported() + required_parameters = ', '.join(self.PLUGINS[plugin_name].required_parameters) + row = [name, type, capabilities, stable, is_os_supported, required_parameters] pt.add_row(row) return pt.get_string() @@ -115,11 +117,15 @@ def get_dict(self): type = self.PLUGINS[plugin_name].type stable = self.PLUGINS[plugin_name].stable capabilities = self.PLUGINS[plugin_name].capabilities + is_os_supported = self.PLUGINS[plugin_name].is_os_supported() + required_parameters = self.PLUGINS[plugin_name].required_parameters result[plugin_name] = { "name" : name, "type" : type, "stable" : stable, - "capabilities" : capabilities + "capabilities" : capabilities, + "os_support" : is_os_supported, + "required_parameters" : required_parameters } return result diff --git a/mbed_host_tests/host_tests_plugins/module_copy_jn51xx.py b/mbed_host_tests/host_tests_plugins/module_copy_jn51xx.py new file mode 100644 index 0000000..581fab1 --- /dev/null +++ b/mbed_host_tests/host_tests_plugins/module_copy_jn51xx.py @@ -0,0 +1,80 @@ +""" +mbed SDK +Copyright (c) 2011-2015 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: Przemyslaw Wirkus +""" + +import os +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginCopyMethod_JN51xx(HostTestPluginBase): + + # Plugin interface + name = 'HostTestPluginCopyMethod_JN51xx' + type = 'CopyMethod' + capabilities = ['jn51xx'] + required_parameters = ['image_path', 'serial'] + + def is_os_supported(self, os_name=None): + """! In this implementation this plugin only is supporeted under Windows machines + """ + # If no OS name provided use host OS name + if not os_name: + os_name = self.mbed_os_support() + + # This plugin only works on Windows + if os_name and os_name.startswith('Windows'): + return True + return False + + def setup(self, *args, **kwargs): + """! Configure plugin, this function should be called before plugin execute() method is used. + """ + self.JN51XX_PROGRAMMER = 'JN51xxProgrammer.exe' + return True + + def execute(self, capability, *args, **kwargs): + """! Executes capability by name + + @param capability Capability name + @param args Additional arguments + @param kwargs Additional arguments + + @details Each capability e.g. may directly just call some command line program or execute building pythonic function + + @return Capability call return value + """ + result = False + if self.check_parameters(capability, *args, **kwargs) is True: + image_path = os.path.normpath(kwargs['image_path']) + serial_port = kwargs['serial'] + if capability == 'jn51xx': + # Example: + # JN51xxProgrammer.exe -s COM15 -f -V0 + cmd = [self.JN51XX_PROGRAMMER, + '-s', serial_port, + '-f', image_path, + '-V0' + ] + result = self.run_command(cmd) + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginCopyMethod_JN51xx() diff --git a/mbed_host_tests/host_tests_plugins/module_copy_stlink.py b/mbed_host_tests/host_tests_plugins/module_copy_stlink.py index e36dc51..302f58b 100644 --- a/mbed_host_tests/host_tests_plugins/module_copy_stlink.py +++ b/mbed_host_tests/host_tests_plugins/module_copy_stlink.py @@ -29,8 +29,20 @@ class HostTestPluginCopyMethod_Stlink(HostTestPluginBase): capabilities = ['stlink'] required_parameters = ['image_path'] + def is_os_supported(self, os_name=None): + """! In this implementation this plugin only is supporeted under Windows machines + """ + # If no OS name provided use host OS name + if not os_name: + os_name = self.mbed_os_support() + + # This plugin only works on Windows + if os_name and os_name.startswith('Windows'): + return True + return False + def setup(self, *args, **kwargs): - """ Configure plugin, this function should be called before plugin execute() method is used. + """! Configure plugin, this function should be called before plugin execute() method is used. """ self.ST_LINK_CLI = 'ST-LINK_CLI.exe' return True diff --git a/mbed_host_tests/host_tests_plugins/module_reset_jn51xx.py b/mbed_host_tests/host_tests_plugins/module_reset_jn51xx.py new file mode 100644 index 0000000..f001d65 --- /dev/null +++ b/mbed_host_tests/host_tests_plugins/module_reset_jn51xx.py @@ -0,0 +1,83 @@ +""" +mbed SDK +Copyright (c) 2011-2015 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: Przemyslaw Wirkus +""" + +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginResetMethod_JN51xx(HostTestPluginBase): + + # Plugin interface + name = 'HostTestPluginResetMethod_JN51xx' + type = 'ResetMethod' + capabilities = ['jn51xx'] + required_parameters = ['serial'] + stable = False + + def is_os_supported(self, os_name=None): + """! In this implementation this plugin only is supporeted under Windows machines + """ + # If no OS name provided use host OS name + if not os_name: + os_name = self.mbed_os_support() + + # This plugin only works on Windows + if os_name and os_name.startswith('Windows'): + return True + return False + + def setup(self, *args, **kwargs): + """! Configure plugin, this function should be called before plugin execute() method is used. + """ + # Note you need to have eACommander.exe on your system path! + self.JN51XX_PROGRAMMER = 'JN51xxProgrammer.exe' + return True + + def execute(self, capability, *args, **kwargs): + """! Executes capability by name + + @param capability Capability name + @param args Additional arguments + @param kwargs Additional arguments + + @details Each capability e.g. may directly just call some command line program or execute building pythonic function + + @return Capability call return value + """ + result = False + if self.check_parameters(capability, *args, **kwargs) is True: + if capability == 'jn51xx': + # Example: + # The device should be automatically reset before the programmer disconnects. + # Issuing a command with no file to program or read will put the device into + # programming mode and then reset it. E.g. + # $ JN51xxProgrammer.exe -s COM5 -V0 + # COM5: Detected JN5179 with MAC address 00:15:8D:00:01:24:E0:37 + serial_port = kwargs['serial'] + cmd = [self.JN51XX_PROGRAMMER, + '-s', serial_port, + '-V0' + ] + result = self.run_command(cmd) + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginResetMethod_JN51xx() diff --git a/mbed_host_tests/host_tests_plugins/module_reset_stlink.py b/mbed_host_tests/host_tests_plugins/module_reset_stlink.py index 686ea05..311a7b2 100644 --- a/mbed_host_tests/host_tests_plugins/module_reset_stlink.py +++ b/mbed_host_tests/host_tests_plugins/module_reset_stlink.py @@ -29,8 +29,20 @@ class HostTestPluginResetMethod_Stlink(HostTestPluginBase): required_parameters = [] stable = False + def is_os_supported(self, os_name=None): + """! In this implementation this plugin only is supporeted under Windows machines + """ + # If no OS name provided use host OS name + if not os_name: + os_name = self.mbed_os_support() + + # This plugin only works on Windows + if os_name and os_name.startswith('Windows'): + return True + return False + def setup(self, *args, **kwargs): - """ Configure plugin, this function should be called before plugin execute() method is used. + """! Configure plugin, this function should be called before plugin execute() method is used. """ # Note you need to have eACommander.exe on your system path! self.ST_LINK_CLI = 'ST-LINK_CLI.exe' diff --git a/mbed_host_tests/host_tests_runner/mbed_base.py b/mbed_host_tests/host_tests_runner/mbed_base.py index 2af4a39..f6bc08b 100644 --- a/mbed_host_tests/host_tests_runner/mbed_base.py +++ b/mbed_host_tests/host_tests_runner/mbed_base.py @@ -53,10 +53,24 @@ def __init__(self, options=None): self.copy_method = self.options.copy_method self.program_cycle_s = float(self.options.program_cycle_s if self.options.program_cycle_s is not None else 2.0) + # Serial port settings self.serial = None self.serial_baud = 9600 self.serial_timeout = 1 + # Users can use command to pass port speeds together with port name. E.g. COM4:9600:1 + # Format if PORT:SPEED:TIMEOUT + port_config = self.port.split(':') + if len(port_config) == 2: + # -p COM4:115200 + self.port = port_config[0] + self.serial_baud = int(port_config[1]) + elif len(port_config) == 3: + # -p COM4:115200:0.5 + self.port = port_config[0] + self.serial_baud = int(port_config[1]) + self.serial_timeout = float(port_config[2]) + # Test configuration in JSON format self.test_cfg = None if self.options.json_test_configuration is not None: @@ -240,7 +254,7 @@ def reset(self): # Flush serials to get only input after reset self.flush() if self.options.forced_reset_type: - result = ht_plugins.call_plugin('ResetMethod', self.options.forced_reset_type, disk=self.disk) + result = ht_plugins.call_plugin('ResetMethod', self.options.forced_reset_type, disk=self.disk, serial=self.port) else: result = ht_plugins.call_plugin('ResetMethod', 'default', serial=self.serial) # Give time to wait for the image loading @@ -248,21 +262,27 @@ def reset(self): self.reset_timeout(reset_tout_s) return result - def copy_image(self, image_path=None, disk=None, copy_method=None): + def copy_image(self, image_path=None, disk=None, copy_method=None, port=None): """! Closure for copy_image_raw() method. @return Returns result from copy plugin """ - # Set closure environment - image_path = image_path if image_path is not None else self.image_path - disk = disk if disk is not None else self.disk - copy_method = copy_method if copy_method is not None else self.copy_method + # Set-up closure environment + if not image_path: + image_path = self.image_path + if not disk: + disk = self.disk + if not copy_method: + copy_method = self.copy_method + if not port: + port = self.port + # Call proper copy method - result = self.copy_image_raw(image_path, disk, copy_method) + result = self.copy_image_raw(image_path, disk, copy_method, port) sleep(self.program_cycle_s) return result - def copy_image_raw(self, image_path=None, disk=None, copy_method=None): + def copy_image_raw(self, image_path=None, disk=None, copy_method=None, port=None): """! Copy file depending on method you want to use. Handles exception and return code from shell copy commands. @@ -277,7 +297,11 @@ def copy_image_raw(self, image_path=None, disk=None, copy_method=None): copy_method = 'shell' else: copy_method = 'shell' - result = ht_plugins.call_plugin('CopyMethod', copy_method, image_path=image_path, destination_disk=disk) + result = ht_plugins.call_plugin('CopyMethod', + copy_method, + image_path=image_path, + serial=port, + destination_disk=disk) return result; def flush(self):