Added iperf and netperf to DUTs, cleaned modems
BUG=chromium:272493
TEST=run_all_tests.py
Change-Id: Iec34502f4a8b8cfec2cac8458350556566710b4b
Reviewed-on: https://chromium-review.googlesource.com/182871
Reviewed-by: Ben Chan <[email protected]>
Tested-by: Byron Kubert <[email protected]>
Commit-Queue: Byron Kubert <[email protected]>
diff --git a/self_tests/unit_tests_software/test_network_data_source.py b/self_tests/unit_tests_software/test_network_data_source.py
index a3da097..6939011 100644
--- a/self_tests/unit_tests_software/test_network_data_source.py
+++ b/self_tests/unit_tests_software/test_network_data_source.py
@@ -61,4 +61,8 @@
"""
config = network_data_source.NetworkDataSource.get_default_config()
with LocalIperf(config) as iperf:
- network_data_source.NetworkDataSource(iperf.config)
+ nds = network_data_source.NetworkDataSource(iperf.config)
+ results = nds.run_iperf_download_test()
+ assert results is not None
+ print 'results:'
+ print (results)
diff --git a/self_tests/unit_tests_with_hardware/test_chrome_dut.py b/self_tests/unit_tests_with_hardware/test_chrome_dut.py
new file mode 100644
index 0000000..19e22ee
--- /dev/null
+++ b/self_tests/unit_tests_with_hardware/test_chrome_dut.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Testing the chrome dut object, with real hardware
+"""
+
+from wireless_automation.aspects import wireless_automation_error
+from wireless_automation.duts import chrome_dut
+
+import unittest
+
+
+class test_chrome_dut(unittest.TestCase):
+ """
+ Test the chrome dut with real hardware
+ """
+ def setUp(self):
+ # Build a DUT
+ dut_config = chrome_dut.ChromeDut.get_default_config()
+ self.dut = chrome_dut.ChromeDut(dut_config, low_level_modem_driver=None)
+
+ def test_localhost_iperf_with_no_server_raises_connection_failure(self):
+ with self.assertRaises(wireless_automation_error.ConnectionFailure):
+ results = self.dut.run_iperf_throughput_test('10.0.0.1')
+
+ def test_localhost_iperf_with_server_returns_high_throughput(self):
+ self.dut.start_local_iperf_server()
+ results = self.dut.run_iperf_throughput_test('localhost',
+ transfer_seconds=3)
+ assert results > 100
diff --git a/self_tests/unittests/test_chrome_device_factory.py b/self_tests/unittests/test_chrome_device_factory.py
deleted file mode 100644
index c65c9a9..0000000
--- a/self_tests/unittests/test_chrome_device_factory.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-# A stub file to remind us to write this class.
-
-#from wireless_automation.chrome_device import chrome_device_factory
-#from wireless_automation.chrome_device import chrome_device_base
-#import unittest
-#
-#
-#class test_DeviceFactory(unittest.TestCase):
-# def setUp(self):
-# pass
-#
-# def tearDown(self):
-# pass
-#
-# def test_make_one(self):
-# config = chrome_device_factory.DutFactory.get_default_config()
-# cd = chrome_device_factory.DutFactory(config)
-# assert isinstance(cd, chrome_device_base.DutInterface)
-#
-# def _bad_config_breaks(self):
-# config = chrome_device_factory.DutFactory.get_default_config()
-# config['bad_value'] = 'here'
-# cd = chrome_device_factory.DutFactory(config)
diff --git a/wireless_automation/chrome_device/chrome_device_factory.py b/wireless_automation/chrome_device/chrome_device_factory.py
deleted file mode 100644
index 310f3ce..0000000
--- a/wireless_automation/chrome_device/chrome_device_factory.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-How to build the right dut
-"""
-
-from wireless_automation.aspects.wireless_automation_logging import \
- setup_logging
-from wireless_automation.chrome_device import chrome_device_base
-from wireless_automation.chrome_device.modems import modem_factory
-
-
-class ChromeDeviceFactory(object):
- """
- TODO:
- A place holder, this class should return an object composed
- of all the objected needed to talk to the chromebook systems:
- shill, modemmanager, the modem direct, open and close switch,
- power reporting, etc.
- """
- log = setup_logging('ChromeDevice')
-
- def __init__(self):
- pass
-
- @classmethod
- def get_chrome_device(cls):
- """
- @param cls: The class.
- @return: A ChromeDevice with it's inner parts populated
- """
- cls.log.info('making new Chrome Device')
- # Only one choice now.
- config = chrome_device_base.ChromeDevice.get_default_config()
- modem = modem_factory.ModemFactory.get_modem()
- device = chrome_device_base.ChromeDevice(config)
- device.modem = modem
- return device
diff --git a/wireless_automation/duts/chrome_devices/__init__.py b/wireless_automation/duts/chrome_devices/__init__.py
deleted file mode 100644
index 55ce177..0000000
--- a/wireless_automation/duts/chrome_devices/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Chrome device specific code.
-"""
diff --git a/wireless_automation/duts/chrome_devices/modems/__init__.py b/wireless_automation/duts/chrome_devices/modems/__init__.py
deleted file mode 100644
index de1ccfa..0000000
--- a/wireless_automation/duts/chrome_devices/modems/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Modem code.
-"""
diff --git a/wireless_automation/duts/chrome_devices/modems/gobi3k.py b/wireless_automation/duts/chrome_devices/modems/gobi3k.py
deleted file mode 100644
index b4ecf25..0000000
--- a/wireless_automation/duts/chrome_devices/modems/gobi3k.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-A placeholder for a gobi3k modem controller
-"""
diff --git a/wireless_automation/duts/chrome_devices/wifi/__init__.py b/wireless_automation/duts/chrome_devices/wifi/__init__.py
deleted file mode 100644
index bdc9842..0000000
--- a/wireless_automation/duts/chrome_devices/wifi/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Wifi code.
-"""
diff --git a/wireless_automation/duts/chrome_dut.py b/wireless_automation/duts/chrome_dut.py
new file mode 100644
index 0000000..e91544d
--- /dev/null
+++ b/wireless_automation/duts/chrome_dut.py
@@ -0,0 +1,259 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+ChromeOS Device Under Test.
+"""
+
+import subprocess
+
+from wireless_automation.duts import dut_interface
+from wireless_automation.aspects import wireless_automation_logging
+from wireless_automation.aspects import wireless_automation_error
+import os
+
+from wireless_automation.utils import run_shell_command
+
+
+class ChromeDut(dut_interface.DutInterface):
+ """
+ ChromeOS specific dut functions.
+ """
+
+ def __init__(self, config, low_level_modem_driver=None):
+ dut_interface.DutInterface.__init__(self, config)
+ self.log = wireless_automation_logging.setup_logging('ChromeDut')
+ self.modem_driver = low_level_modem_driver
+ self.fake_hardware = config['fake_hardware']
+
+ def cellular_modem_reset(self):
+ """
+ Reset the cellular modem using OS level tools.
+ """
+ cmd = ["modem", "reset"]
+ self._send_shell_command(cmd)
+
+ def cellular_controllers_stop(self):
+ """
+ stop all the daemons that may talk to the modem.
+ Used before controlling the modem with low level tools.
+ """
+ cmd = ["stop", "shill"]
+ self._send_shell_command(cmd)
+
+ def cellular_connect(self, technology='LTE'):
+ """
+ connect the cellular modem using OS level tools
+ """
+ cmd = ["modem", "connect"]
+ self._send_shell_command(cmd)
+
+ def _send_shell_command_list(self, cmds):
+ for cmd in cmds:
+ self.log.info(cmd)
+ self._send_shell_command(cmd)
+
+ def _send_shell_command(self, cmd):
+ """
+ Run a shell command on the dut
+ """
+ self.log.debug(cmd)
+ shell_env = os.environ
+ self.log.info(cmd)
+ command = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=shell_env)
+ (std_out, std_err) = command.communicate()
+ self.log.debug(std_out)
+ self.log.debug(std_err)
+
+ def start_local_netperf_server(self, timeout_secs=5):
+ """
+ Start a local netperf server.
+ This is not very robust yet, just used in some unit tests.
+ :timeout: seconds
+ :return:
+ """
+ cmd1 = ['killall', 'netserver']
+ cmd2 = ['timeout', str(timeout_secs), 'netserver']
+ self._send_shell_command_list([cmd1, cmd2])
+
+ def start_local_iperf_server(self, port=5001, timeout_secs=5):
+ """
+ Start a local iperf server.
+ This is not very robust yet, just used in some unit tests.
+ :param port: port number, default=5001
+ :return:
+ """
+ cmd1 = ['killall', '-9', 'iperf'] # -9 because iperf hangs
+ cmd2 = ['timeout', str(timeout_secs), 'iperf',
+ '--daemon', '-s', '--port', str(port),
+ '2>/dev/null',
+ '1>/dev/null', '&']
+ for cmd in [cmd1, cmd2]:
+ self.log.info(cmd)
+ # This hangs for an unkown reason.
+ #self._send_shell_command_list([cmd1, cmd2])
+ # Use os.system until the CL with utils/run_shell_command lands
+ os.system(' '.join(cmd))
+
+ def parse_netperf_output(self, out_str):
+ out = out_str.rstrip()
+ out = out.split()
+ if len(out) < 5:
+ msg = ('Netperf returned a too short result : %s ' % out)
+ self.log.error(msg)
+ raise wireless_automation_error.BadState(msg)
+ try:
+ results = {"rx_socket_bytes": float(out[0]),
+ "tx_socket_bytes": float(out[1]),
+ "message_size_bytes": float(out[2]),
+ "time": float(out[3]),
+ "Mbits_sec": float(out[4]),
+ }
+ except ValueError:
+ self.log.info('netperf results : "%s" ' % out_str)
+ mesg = 'Netperf test returned non floats as values'
+ self.log.error(mesg)
+ raise wireless_automation_error.ConnectionFailure(mesg)
+ if results['Mbits_sec'] == '0':
+ mesg = ('Netperf test returned 0 bytes transferred.'
+ ' Maybe the netperf server was down?')
+ self.log.error(mesg)
+ raise wireless_automation_error.ConnectionFailure(mesg)
+ return results
+
+ def _check_throughput_params(self, direction):
+ valid = ['uplink', 'downlink']
+ if direction not in valid:
+ msg = "netperf test can not run direction = '%s', only %s " % \
+ (direction, valid)
+ raise wireless_automation_error.BadExternalConfig(msg)
+
+ def run_netperf_throughput_test(self, server_ip, port=12865,
+ transfer_seconds=10, direction='uplink'):
+ """
+ Run a netperf speed test.
+ :param server_ip:
+ :param port: port to use
+ :param transfer_seconds: seconds to run the test
+ :param direction: uplink or downlink
+ :return: Mega bits per second for the direction specified.
+ """
+ self._check_throughput_params(direction)
+
+ if direction == 'uplink':
+ netperf_test = 'TCP_STREAM'
+ else:
+ netperf_test = 'TCP_MAERTS'
+ self._ping_host_or_raise(server_ip)
+
+ if self.fake_hardware:
+ self.log.info('Fake running a download test..')
+ return 123.456
+
+ self.log.info('Starting the download test..')
+ cmd = ["netperf", server_ip,
+ "-P", "0", # Don't print any headers in the output
+ "-l", str(transfer_seconds),
+ "-t", str(netperf_test),
+ "-p", str(port)
+ ]
+ self.log.info(' '.join(cmd))
+ netperf = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ # communicate() blocks until there are results
+ (out_str, out_e) = netperf.communicate()
+ self.log.info('netperf stderr: %s ' % out_e)
+ results = self.parse_netperf_output(out_str)
+
+ self.log.info('Netperf %s Mbps: %s' % (direction, results['Mbits_sec']))
+ return results['Mbits_sec']
+
+ def _parse_iperf_output(self, direction, out, transfer_seconds):
+ out = out.rstrip()
+ out = out.split(',')
+ if len(out) < 8:
+ mesg = 'iperf returned too short of a result : %s ' % out
+ self.log.error(mesg)
+ raise wireless_automation_error.ConnectionFailure(mesg)
+ results = {"date": out[0],
+ "source_ip": out[1],
+ "source_port": out[2],
+ "dest_ip": out[3],
+ "dest_port": out[4],
+ "id": out[5],
+ "seconds": out[6],
+ "bytes": out[7],
+ "bytes_per_second": out[8],
+ }
+ if results['bytes'] == '0':
+ mesg = ('Iperf test returned 0 bytes transferred.'
+ ' Maybe the iperf server was down?')
+ self.log.error(mesg)
+ raise wireless_automation_error.ConnectionFailure(mesg)
+ # Calc the rate. Sometimes iperf doesn't return the
+ # last element in the list, but we seem to have bytes
+ # and seconds all the time.
+ bits_per_second = 8 * float(results['bytes']) / transfer_seconds
+ mega_bits_per_seconds = bits_per_second / 1e6
+ self.log.info('iperf %s Mbps: %s' % (direction, mega_bits_per_seconds))
+ return mega_bits_per_seconds
+
+ def run_iperf_throughput_test(self, iperf_server_ip, iperf_port=5001,
+ direction='uplink', transfer_seconds=10):
+ """
+ Use Iperf to test throughput speeds. This expects there to be
+ a iperf server running at the iperf_server_ip.
+ :param iperf_server_ip: IP of the server that has iperf in server mode
+ :param iperf_port: Port that iperf is using on the server
+ :param bidirectional:
+ How to test both direction['no','serial,'parallel' ]
+ :param transfer_seconds:
+ :return:
+ """
+ self._check_throughput_params(direction)
+ self._ping_host_or_raise(iperf_server_ip)
+ if self.fake_hardware:
+ self.log.info('Fake running a download test..')
+ return 123.456
+
+ self.log.info('Starting the download test..')
+ cmd = ["iperf",
+ "--client", iperf_server_ip,
+ "--reportstyle", "C",
+ "--time", str(transfer_seconds),
+ "--port", str(iperf_port)]
+ if direction == 'downlink':
+ cmd.extend(['--tradeoff'])
+
+ self.log.info(' '.join(cmd))
+ shell_cmd = run_shell_command.Command(cmd)
+ shell_cmd.run(timeout=transfer_seconds + 5, shell=False)
+ out = shell_cmd.output
+ mega_bits_per_seconds = self._parse_iperf_output(direction,
+ out,
+ transfer_seconds)
+ return mega_bits_per_seconds
+
+ def _ping_host_or_raise(self, ip_address):
+ """
+ Check if the net/iperf host is reachable.
+ :return: Raises an exception if ping can't connect
+ """
+ if self.fake_hardware:
+ return
+ cmd = "ping -c 1 -w 2 " + ip_address + " > /dev/null 2>&1"
+ self.log.debug(cmd)
+ if self.fake_hardware:
+ self.log.debug("In Fake mode, don't actually ping")
+ return
+ response = os.system(cmd)
+ #and then check the response...
+ if response == 0:
+ self.log.debug('ping %s worked' % ip_address)
+ return
+ else:
+ self.log.debug('ping %s failed' % ip_address)
+ raise wireless_automation_error.ConnectionFailure(
+ 'net/iperf host is not responding to ping: %s ' % ip_address)
diff --git a/wireless_automation/duts/dummy_modem.py b/wireless_automation/duts/dummy_modem.py
deleted file mode 100644
index b347ccb..0000000
--- a/wireless_automation/duts/dummy_modem.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-A dummy modem class, to provide modem functionality on workstations that
-have no modems.
-"""
-
-from wireless_automation.duts import modem_interface
-
-
-class DummyModem(modem_interface.ModemInterface):
- """
- A dummy modem class.
-
- """
- CONFIGSPEC = ['name = string(default="DummyMode")']
-
- def __init__(self, config):
- """
- @param config: a Config object.
- """
- super(DummyModem, self).__init__(config)
-
- def power_on(self):
- """
- Turn on a powered modem.
- """
- pass
-
- def power_off(self):
- """
- Turn off the modem, but do not disconnect the power lines.
- """
- pass
-
- def register(self):
- """
- Register with the network.
- """
- pass
-
- def deregister(self):
- """
- Deregister with the network.
- """
- pass
-
- def connect(self):
- """
- Connect
- """
-
- pass
-
- def disconnect(self):
- """
- Disconnect from the network.
- """
- pass
-
- def go_to_low_power(self):
- """
- Put the modem to sleep.
- @return:
- """
- pass
-
- def hard_power_cycle(self, block=True):
- """
- Powers off the modem by killing the power lines to it.
- Or as close to that as possible. This should be a
- the hardest reset available. Then powers the modem back up.
- This blocks until the modem is responsive.
-
- @block: return only after the modem responsive
- """
- pass
-
- def is_modem_there(self):
- """
- Can the modem be reached. If the modem is off or
- non responsive, returns a False.
- @return: Boolean.
- """
- pass
-
- def config_for_pxt(self):
- """
- Configs the modem to talk to the PXT call box.
- """
- pass
diff --git a/wireless_automation/duts/dut_factory.py b/wireless_automation/duts/dut_factory.py
deleted file mode 100644
index 1a2d640..0000000
--- a/wireless_automation/duts/dut_factory.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-How to build the right dut
-"""
-
-from wireless_automation.aspects import configurable
-from wireless_automation.aspects.wireless_automation_logging import \
- setup_logging
-from wireless_automation.duts import dut_interface
-from wireless_automation.duts.chrome_devices.modems import modem_factory
-
-
-class DutFactory(configurable.Configurable):
- """
- Composes a DUT from the parts specified in the config.
- """
- CONFIGSPEC = \
- ['type=option("chrome","android","iOS",default="chrome")'] + \
- configurable.nest_configspecs([
- ('DutInterface', dut_interface.DutInterface)
- ])
- log = setup_logging('DutInterface')
-
- def __init__(self, config):
- super(DutFactory, self).__init__(config)
-
- @classmethod
- def get_dut(cls):
- """
- @param cls: The class.
- @return: A DutInterface with it's inner parts populated
- """
- cls.log.info('making new Chrome Device')
- # Only one choice now.
- config = dut_interface.DutInterface.get_default_config()
- modem = modem_factory.ModemFactory.get_modem()
- device = dut_interface.DutInterface(config)
- device.modem = modem
- return device
-
-
-def build_one(config):
- """
- Dut factory function.
- @param config:
- @return:
- """
- factory = DutFactory(config)
- return factory.get_dut()
diff --git a/wireless_automation/duts/dut_interface.py b/wireless_automation/duts/dut_interface.py
index 0fe277c..6c935c2 100644
--- a/wireless_automation/duts/dut_interface.py
+++ b/wireless_automation/duts/dut_interface.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
-Base class for all chrome_devices
+Base class for all modem_drivers
"""
from wireless_automation.aspects import configurable
@@ -13,21 +13,52 @@
Interface definition for Devices Under Test. Could be Chromebooks,
could be iOS phones, could be Android devices.
"""
- CONFIGSPEC = ['modem_interface=option("altair","dummy",default="dummy")']
+ CONFIGSPEC = ['fake_hardware=boolean(default=False)']
- def __init__(self, config):
+ def __init__(self, config, low_level_modem_driver=None):
"""
- @param config: Configurable object.
- @return: DutInterface
+ :param config: ConfigObj that contains setup info
+ :param low_level_modem_driver: driver to control the
+ modem directly. Using this is optional, the dut
+ has methods to control the modem. The driver is
+ needed only when these methods are not detailed
+ enough. The method stop
+ :return:
"""
super(DutInterface, self).__init__(config)
- self.modem = None
+ self.modem = low_level_modem_driver
+ self.fake_hardware = config['fake_hardware']
- @staticmethod
- def measure_download_speed(url):
+ def cellular_connect(self, technology):
"""
- @param url: Where to download from.
- @return: Speed of the download
+ Instruct the dut to connect it's cellular system
+ to the specified technology.
+ This is not a command given directly to the modem.
+ This instruct the dut to use it's normal methods
+ to establish a connection. In ChromeOS, this would
+ be done by shill.
+ :param technology:
+ :return:
"""
- str(url)
- return 1
+ raise NotImplementedError
+
+ def cellular_controllers_stop(self):
+ """
+ Turn off any software that may try to control the modem.
+ Use this before using any modem driver.
+ For example: in ChromeOS this stops Shill and ModemManager.
+ """
+ raise NotImplementedError
+
+ def run_iperf_throughput_test(self, iperf_server_ip, iperf_port=5001,
+ direction='uplink', seconds=10):
+ """
+ Run one iperf test from the device we are on to
+ the iperf server running on iperf_server_ip.
+ This assumes the server is ready and waiting.
+
+ :param iperf_server_ip: Address of server
+ :param seconds: seconds to run the test.
+ :return: a dict of results.
+ """
+ raise NotImplementedError
diff --git a/wireless_automation/duts/chrome_devices/modems/modem_factory.py b/wireless_automation/duts/modem_factory.py
similarity index 93%
rename from wireless_automation/duts/chrome_devices/modems/modem_factory.py
rename to wireless_automation/duts/modem_factory.py
index e13694c..78e1a60 100644
--- a/wireless_automation/duts/chrome_devices/modems/modem_factory.py
+++ b/wireless_automation/duts/modem_factory.py
@@ -7,7 +7,7 @@
"""
from wireless_automation.aspects import configurable
-from wireless_automation.duts import dummy_modem
+from wireless_automation.duts.modem_drivers import dummy_modem
class ModemFactory(configurable.Configurable):
diff --git a/wireless_automation/duts/modem_interface.py b/wireless_automation/duts/modem_interface.py
deleted file mode 100644
index f0039d5..0000000
--- a/wireless_automation/duts/modem_interface.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-Base class for all modems.
-"""
-
-from wireless_automation.aspects import configurable
-
-
-class ModemInterface(configurable.Configurable):
- """
- A base class for controlling the modem.
-
- """
-
- def __init__(self, config):
- """
- @param config: Config object.
- """
- super(ModemInterface, self).__init__(config)
-
- def power_on(self):
- """
- Turn on a powered modem.
- """
- raise NotImplementedError
-
- def power_off(self):
- """
- Turn off the modem, but do not disconnect the power lines.
- """
- raise NotImplementedError
-
- def register(self):
- """
- Register with the network.
- """
- raise NotImplementedError
-
- def deregister(self):
- """
- Deregister with the network.
- """
- raise NotImplementedError
-
- def connect(self):
- """
- Connect
- """
-
- raise NotImplementedError
-
- def disconnect(self):
- """
- Disconnect from the network.
- """
- raise NotImplementedError
-
- def go_to_low_power(self):
- """
- Put the modem to sleep.
- @return:
- """
- raise NotImplementedError
-
- def hard_power_cycle(self, block=True):
- """
- Powers off the modem by killing the power lines to it.
- Or as close to that as possible. This should be a
- the hardest reset available. Then powers the modem back up.
- This blocks until the modem is responsive.
-
- @block: return only after the modem responsive
- """
- raise NotImplementedError
-
- def is_modem_there(self):
- """
- Can the modem be reached. If the modem is off or
- non responsive, returns a False.
- @return: Boolean.
- """
- raise NotImplementedError
-
- def config_for_pxt(self):
- """
- Configs the modem to talk to the PXT call box.
- """
- raise NotImplementedError