From 629516244d33751d916fbf59b9b5c68f503f14ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Fierek?= Date: Wed, 15 Feb 2017 18:11:38 +0100 Subject: [PATCH] Add PDU controller that allows to reboot Nordic dev-kits. (#1201) --- .../autothreadharness/harness_case.py | 13 +-- ...pc_pdu_controller.py => pdu_controller.py} | 90 ++++++++++++++++--- .../pdu_controller_factory.py | 40 +++++++++ .../autothreadharness/settings_sample.py | 46 ++++++++-- 4 files changed, 162 insertions(+), 27 deletions(-) rename tools/harness-automation/autothreadharness/{apc_pdu_controller.py => pdu_controller.py} (66%) create mode 100644 tools/harness-automation/autothreadharness/pdu_controller_factory.py diff --git a/tools/harness-automation/autothreadharness/harness_case.py b/tools/harness-automation/autothreadharness/harness_case.py index 8bf3ec93f..2ad2ac6bc 100644 --- a/tools/harness-automation/autothreadharness/harness_case.py +++ b/tools/harness-automation/autothreadharness/harness_case.py @@ -42,7 +42,7 @@ import time import unittest from autothreadharness import settings -from autothreadharness.apc_pdu_controller import ApcPduController +from autothreadharness.pdu_controller_factory import PduControllerFactory from autothreadharness.harness_controller import HarnessController from autothreadharness.helpers import HistoryHelper from autothreadharness.open_thread_controller import OpenThreadController @@ -167,7 +167,7 @@ class HarnessCase(unittest.TestCase): if self.manual_reset: raw_input('Reset golden devices and press enter to continue..') return - elif not settings.APC_HOST: + elif not settings.PDU_CONTROLLER_TYPE: if settings.GOLDEN_DEVICE_TYPE != 'OpenThread': logger.warning('All golden devices may not be resetted') return @@ -188,9 +188,12 @@ class HarnessCase(unittest.TestCase): return tries = 3 + pdu_factory = PduControllerFactory() + while True: try: - apc = ApcPduController(settings.APC_HOST) + pdu = pdu_factory.create_pdu_controller(settings.PDU_CONTROLLER_TYPE) + pdu.open(**settings.PDU_CONTROLLER_OPEN_PARAMS) except EOFError: logger.warning('Failed to connect to telnet') tries = tries - 1 @@ -201,8 +204,8 @@ class HarnessCase(unittest.TestCase): logger.error('Fatal error: cannot connect to apc') raise else: - apc.reboot(settings.APC_OUTLET) - apc.close() + pdu.reboot(**settings.PDU_CONTROLLER_REBOOT_PARAMS) + pdu.close() break time.sleep(20) diff --git a/tools/harness-automation/autothreadharness/apc_pdu_controller.py b/tools/harness-automation/autothreadharness/pdu_controller.py similarity index 66% rename from tools/harness-automation/autothreadharness/apc_pdu_controller.py rename to tools/harness-automation/autothreadharness/pdu_controller.py index e6e5c2701..46a61dea0 100644 --- a/tools/harness-automation/autothreadharness/apc_pdu_controller.py +++ b/tools/harness-automation/autothreadharness/pdu_controller.py @@ -27,26 +27,47 @@ # POSSIBILITY OF SUCH DAMAGE. # - import logging +import os +import re import telnetlib import time -import re logger = logging.getLogger(__name__) -class ApcPduController(object): - def __init__(self, ip, port=23): - """Create APC PDU controller - Args: - ip (str), ip address or hostname - port (int), port number - """ - self.port = port - self.ip = ip +class PduController(object): + + def open(self, **params): + """Open PDU controller connection""" + raise NotImplementedError + + def reboot(self, **params): + """Reboot an outlet or a board passed as params""" + raise NotImplementedError + + def close(self): + """Close PDU controller connection""" + raise NotImplementedError + + +class DummyPduController(PduController): + """Dummy implementation which only says that PDU controller is not connected""" + + def open(self, **params): + pass + + def reboot(self, **params): + print('No PDU controller connected.') + + def close(self): + pass + + +class ApcPduController(PduController): + + def __init__(self): self.tn = None - self._init() def __del__(self): self.close() @@ -61,6 +82,21 @@ class ApcPduController(object): self.tn.write('apc\r\n') self.until_done() + def open(self, **params): + """Open telnet connection + + Args: + params (dict), must contain two parameters "ip" - ip address or hostname and "port" - port number + + Example: + params = {'port': 23, 'ip': 'localhost'} + """ + logger.info('opening telnet') + self.port = params['port'] + self.ip = params['ip'] + self.tn = None + self._init() + def close(self): """Close telnet connection""" logger.info('closing telnet') @@ -79,9 +115,17 @@ class ApcPduController(object): r = re.compile(regex, re.M) self.tn.expect([r]) - def reboot(self, outlet=1): + def reboot(self, **params): """Reboot outlet + + Args: + params (dict), must contain parameter "outlet" - outlet number + + Example: + params = {'outlet': 1} """ + outlet = params['outlet'] + # main menu self.tn.write('\x1b\r\n') self.until_done() @@ -117,6 +161,26 @@ class ApcPduController(object): self.tn.write('\r\n') self.until_done() + +class NordicBoardPduController(PduController): + + def open(self, **params): + pass + + def _pin_reset(self, serial_number): + os.system('nrfjprog -f NRF52 --snr {} -p'.format(serial_number)) + + def reboot(self, **params): + boards_serial_numbers = params['boards_serial_numbers'] + + for serial_number in boards_serial_numbers: + print('Resetting board with the serial number: {}'.format(serial_number)) + self._pin_reset(serial_number) + + def close(self): + pass + + if __name__ == '__main__': apc = ApcPduController('192.168.1.88') apc.reboot() diff --git a/tools/harness-automation/autothreadharness/pdu_controller_factory.py b/tools/harness-automation/autothreadharness/pdu_controller_factory.py new file mode 100644 index 000000000..9bfd2a247 --- /dev/null +++ b/tools/harness-automation/autothreadharness/pdu_controller_factory.py @@ -0,0 +1,40 @@ +# Copyright (c) 2016, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +import pdu_controller + + +class PduControllerFactory(object): + """Factory that creates PDU controllers.""" + + def create_pdu_controller(self, _type): + if _type == 'NORDIC_BOARD_PDU_CONTOLLER': + return pdu_controller.NordicBoardPduController() + elif _type == 'APC_PDU_CONTROLLER': + return pdu_controller.ApcPduController() + else: + return pdu_controller.DummyPduController() diff --git a/tools/harness-automation/autothreadharness/settings_sample.py b/tools/harness-automation/autothreadharness/settings_sample.py index 645897782..1384f2356 100644 --- a/tools/harness-automation/autothreadharness/settings_sample.py +++ b/tools/harness-automation/autothreadharness/settings_sample.py @@ -65,15 +65,6 @@ HARNESS_HOME = 'C:\\GRL\\Thread1.1' HARNESS_URL = 'http://127.0.0.1:8000' """str: Harness front-end url""" -APC_HOST = None -"""str: PDU controller host. - -Keep this None if no APC PDU available. -""" - -APC_OUTLET = 1 -"""int: PDU outlet, only needed when APC_HOST is not None.""" - TESTER_NAME = 'Thread Open' """str: Who are you""" @@ -87,3 +78,40 @@ It should be something like [('COM1', 'OpenThread'), ('COM2', 'ARM')] on Windows OUTPUT_PATH = '.\\output' """str: Path to store results and logs, MUST be writable.""" + +PDU_CONTROLLER_TYPE = None +"""str: Type of connected PDU controller. + +Keep this None if no PDU controller available. + +Types of supported PDU controllers: + - None - when no PDU controller connected + - 'APC_PDU_CONTROLLER' - when APC PDU controller connected + - 'NORDIC_BOARD_PDU_CONTOLLER' - when Nordic boards PDU controller connected +""" + +PDU_CONTROLLER_OPEN_PARAMS = {'port': 23, 'ip': '127.0.0.1'} +"""dict: Parameters pass to the "open" method of PDU controller. + +Example parameters for the 'APC_PDU_CONTROLLER': + {'port': 23, 'ip': '127.0.0.1'} + +Example parameters for the 'NORDIC_BOARD_PDU_CONTOLLER': + {} - empty dictionary +""" + +PDU_CONTROLLER_REBOOT_PARAMS = {'outlet': 1} +"""dict: Parameters pass to the "reboot" method of PDU controller. + +Example parameters for the 'APC_PDU_CONTROLLER': + {'outlet': 1} + +Example parameters for the 'NORDIC_BOARD_PDU_CONTOLLER': + {'boards_serial_numbers': ('12345123', ...)} +""" +HARNESS_VERSION = 35 +"""int: Version of the installed Thread Harness.""" + +GOLDEN_DEVICE_TYPE = 'OpenThread' +"""str: Type of the Golden Device.""" +