Refactored the call box tree

BUG=chromium:272493
TEST=run_all_tests.py

Change-Id: I688aaa705bc923f9af97161401b787526de05d46
Reviewed-on: https://chromium-review.googlesource.com/182870
Reviewed-by: Ben Chan <benchan@chromium.org>
Tested-by: Byron Kubert <byronk@chromium.org>
Commit-Queue: Byron Kubert <byronk@chromium.org>
diff --git a/self_tests/unittests/test_call_box_fake.py b/self_tests/unit_tests_software/test_call_box_fake.py
similarity index 98%
rename from self_tests/unittests/test_call_box_fake.py
rename to self_tests/unit_tests_software/test_call_box_fake.py
index a21c067..c9d699b 100644
--- a/self_tests/unittests/test_call_box_fake.py
+++ b/self_tests/unit_tests_software/test_call_box_fake.py
@@ -6,7 +6,8 @@
 
 from wireless_automation.aspects import wireless_automation_error
 from wireless_automation.aspects import wireless_automation_logging
-from wireless_automation.instruments.call_box.call_box_fake import CallBoxFakePxt
+from wireless_automation.instruments.call_box.call_box_fake import \
+    CallBoxFakePxt
 
 log = wireless_automation_logging.setup_logging('call_box_pxt')
 
@@ -57,7 +58,6 @@
         self.pxt.set_power_dbm(power)
         assert self.pxt.get_power_dbm() == power
 
-
     def test_power_outside_range_should_raise(self):
         """
         test_power_outside_range_should_raise
diff --git a/self_tests/uniittests_with_hardware/call_box_pxt_test_with_hardware.py b/self_tests/unit_tests_with_hardware/test_call_box_pxt_with_hardware.py
similarity index 60%
rename from self_tests/uniittests_with_hardware/call_box_pxt_test_with_hardware.py
rename to self_tests/unit_tests_with_hardware/test_call_box_pxt_with_hardware.py
index c937073..54f3c3f 100644
--- a/self_tests/uniittests_with_hardware/call_box_pxt_test_with_hardware.py
+++ b/self_tests/unit_tests_with_hardware/test_call_box_pxt_with_hardware.py
@@ -7,20 +7,41 @@
 
 from wireless_automation.aspects import wireless_automation_error
 from wireless_automation.aspects.wireless_automation_logging import \
-        setup_logging
+    setup_logging
 from wireless_automation.instruments.call_box.agilent_pxt.call_box_pxt import \
-        CallBoxPxt
+    CallBoxPxt
+from wireless_automation.instruments.call_box.call_box_fake import \
+    CallBoxFakePxt
 
 log = setup_logging('pxt_hardware_test')
 
-class test_pxt(unittest.TestCase):
+
+class TestPxt(unittest.TestCase):
     """
     Test the PXT class.
     """
 
     def setUp(self):
-        config = CallBoxPxt.get_default_config()
-        self.pxt = CallBoxPxt(config)
+        self.config = CallBoxPxt.get_default_config()
+        self.config['scpi_ip_address'] = '172.22.50.236'
+
+    def tearDown(self):
+        self.pxt.close()
+
+    def test_fake_hardware_returns_fake(self):
+        """
+        New of the pxt call box acts as a factory, and can return
+        a fake if the config asks for it.
+        This tests the new() function of the CallBoxPxt.
+        """
+        self.config['fake_hardware'] = True
+        self.pxt = CallBoxPxt(self.config)
+        assert isinstance(self.pxt, CallBoxFakePxt)
+
+    def test_no_fake_hardware_returns_real_pxt(self):
+        self.config['fake_hardware'] = False
+        self.pxt = CallBoxPxt(self.config)
+        assert isinstance(self.pxt, CallBoxPxt)
 
     def test_most_real_pxt_functions(self):
         """
@@ -29,8 +50,7 @@
         do it once and have one large test function.
 
         """
-        #config = CallBoxFakePxt.get_default_config()
-        #self.pxt = CallBoxFakePxt(config)
+        self.pxt = CallBoxPxt(self.config)
         self.pxt.reset()
         self.pxt.start()
         power = -57
@@ -48,11 +68,11 @@
         """
         test_stop_raises_when_it_does_not_go_idle
         """
-        log.info('Testing stop raises when is_idle does not idle')
+        self.pxt = CallBoxPxt(self.config)
         #with mock.patch.object(self.pxt, 'is_idle'):
         self.pxt.is_idle = mock.MagicMock()
         self.pxt.is_idle.return_value = False
         self.pxt.scpi = mock.MagicMock()
-        print self.pxt.is_idle()
+        log.debug('PXT idle: %s ' % self.pxt.is_idle())
         with self.assertRaises(wireless_automation_error.InstrumentTimeout):
             self.pxt.stop()
diff --git a/self_tests/uniittests_with_hardware/prologix_scpi_driver_test_with_hardware.py b/self_tests/unit_tests_with_hardware/test_prologix_scpi_driver_with_hardware.py
similarity index 78%
rename from self_tests/uniittests_with_hardware/prologix_scpi_driver_test_with_hardware.py
rename to self_tests/unit_tests_with_hardware/test_prologix_scpi_driver_with_hardware.py
index fc2e34e..761be17 100644
--- a/self_tests/uniittests_with_hardware/prologix_scpi_driver_test_with_hardware.py
+++ b/self_tests/unit_tests_with_hardware/test_prologix_scpi_driver_with_hardware.py
@@ -10,8 +10,7 @@
 from wireless_automation.aspects import wireless_automation_error
 from wireless_automation.aspects import wireless_automation_logging
 from wireless_automation.instruments.prologix import prologix_scpi_driver
-
-
+from hardware_setup import scpi_instruments
 log = wireless_automation_logging.setup_logging('scpi_test')
 
 # TODO:(byronk):
@@ -19,13 +18,6 @@
 # TODO:(byronk):
 # replace SystemError with a specific exception crbug.com/225127
 
-scpi_instruments = [
-    # Agilent 8960 call box
-    {'name_part': "8960", 'gpib_addr': '14', 'ip': '172.22.50.118'},
-    # PXT is called 6621
-    {'name_part': "6621", 'gpib_addr': '14', 'ip': "172.22.50.244"}
-]
-
 
 class BasicPrologixTest(unittest.TestCase):
     """
@@ -36,11 +28,12 @@
         """
         Connect to the wrong port and check for the right error message.
         """
-        instr = copy.copy(scpi_instruments[0])
+        instr = copy.copy(scpi_instruments['pxt'])
         instr['ip'] = '192.168.0.0'  # str(int(instr['gpib_addr'])+1)
         log.debug(instr)
+        instr_dict = {'inst': instr}
         with self.assertRaises(Exception) as ex:
-            self._get_idns_and_verify(instruments=[instr], opc=True)
+            self._get_idns_and_verify(instruments=instr_dict, opc=True)
         self.assertIsInstance(ex.exception,
                               wireless_automation_error.SocketTimeout)
 
@@ -55,12 +48,12 @@
         """
         How does the code behave if we can't connect.
         """
-        instr = copy.copy(scpi_instruments[0])
+        instr = copy.copy(scpi_instruments['pxt'])
         instr['gpib_addr'] = 9  # str(int(instr['gpib_addr'])+1)
-        with self.assertRaises(Exception) as ex:
-            self._get_idns_and_verify(instruments=[instr], opc=True)
-        self.assertIsInstance(ex.exception,
-                              wireless_automation_error.InstrumentTimeout)
+        instr_dict = {'inst': instr}
+        ext_type = wireless_automation_error.InstrumentTimeout
+        with self.assertRaises(ext_type) as ex:
+            self._get_idns_and_verify(instruments=instr_dict, opc=True)
 
     @mock.patch.object(prologix_scpi_driver.PrologixScpiDriver, '_direct_query')
     def test_NonClearReadBufferBeforeInit(self, patched_driver):
@@ -69,16 +62,16 @@
         There is code to read the junk out until setting the ++addr works.
         Test that here.
         """
-        s = scpi_instruments[0]
-        patched_driver.side_effect = ['junk1', 'junk2', s['gpib_addr']]
+        instr = scpi_instruments['pxt']
+        patched_driver.side_effect = ['junk1', 'junk2', instr['gpib_addr']]
         driver = prologix_scpi_driver.PrologixScpiDriver(
-            hostname=s['ip'],
-            port=1234,
-            gpib_address=s['gpib_addr'],
+            hostname=instr['ip'],
+            port=instr['port'],
+            gpib_address=instr['gpib_addr'],
             read_timeout_seconds=2)
 
     def test_Reset(self):
-        for instr in scpi_instruments:
+        for instr in scpi_instruments.values():
             scpi_connection = self._open_prologix(instr, opc_on_stanza=True,
                                                   read_timeout_seconds=20)
             scpi_connection.query("*IDN?")
@@ -88,7 +81,7 @@
         """
         call FetchErrors
         """
-        for instr in scpi_instruments:
+        for instr in scpi_instruments.values():
             scpi_connection = self._open_prologix(instr, opc_on_stanza=True,
                                                   read_timeout_seconds=2)
             scpi_connection.retrieve_errors()
@@ -98,14 +91,15 @@
         """
         Send a bad command. We should fail gracefully.
         """
-        for instr in scpi_instruments:
+        for instr in scpi_instruments.values():
+            log.debug('Trying bad command on device : %s ' % instr)
             scpi_connection = self._open_prologix(instr, opc_on_stanza=True,
                                                   read_timeout_seconds=2)
             try:
                 scpi_connection.query('*IDN')
             except wireless_automation_error.InstrumentTimeout:
-                assert \
-                 "Should have raised a Instrument Timeout on a bad SCPI command"
+                assert ("Should have raised an Instrument Timeout "
+                        "on a bad SCPI command")
 
     def test_GetIdnOpcTrue(self):
         """
@@ -128,12 +122,13 @@
         Build the prologix object.
         """
         ip_addr = instr['ip']
-        name_part = instr['name_part']
+        name_part = instr['name']
         gpib_addr = instr['gpib_addr']
+        port = instr['port']
         log.debug("trying %s at %s" % (name_part, ip_addr))
         driver = prologix_scpi_driver.PrologixScpiDriver(
             hostname=ip_addr,
-            port=1234,
+            port=port,
             gpib_address=gpib_addr,
             read_timeout_seconds=read_timeout_seconds)
         self.scpi_connection = driver
@@ -144,12 +139,12 @@
         Get the idn string from all the instruments, and check that it
         contains the desired substring. This is a quick sanity check only.
         """
-        for instr in instruments:
+        for instr in instruments.values():
             scpi_connection = self._open_prologix(instr, opc_on_stanza=opc)
             response = scpi_connection.query('*IDN?')
             log.debug("looking for %s  in response string: %s " %
-                      (instr['name_part'], response))
-            assert instr['name_part'] in response
+                      (instr['name'], response))
+            assert instr['name'] in response
             self.scpi_connection.close()
 
 if __name__ == '__main__':
diff --git a/wireless_automation/instruments/call_box/agilent_pxt/call_box_pxt.py b/wireless_automation/instruments/call_box/agilent_pxt/call_box_pxt.py
index 710a394..ef23025 100644
--- a/wireless_automation/instruments/call_box/agilent_pxt/call_box_pxt.py
+++ b/wireless_automation/instruments/call_box/agilent_pxt/call_box_pxt.py
@@ -7,13 +7,13 @@
 
 import time
 
-from wireless_automation.aspects import configurable
 from wireless_automation.aspects import wireless_automation_error
 from wireless_automation.instruments.call_box import call_box_interface
+from wireless_automation.instruments.call_box import call_box_fake
 from wireless_automation.instruments.prologix import prologix_scpi_driver
 
 
-class CallBoxPxt(call_box_interface.CallBoxInterface):
+class CallBoxPxt(call_box_interface.CallBoxPxtInterface):
     """
     Object for the Agilent PXT, the LTE call box.
     """
@@ -22,25 +22,31 @@
     # to give correct answers, but stored here to keep all the
     # PXT knowledge in one place.
 
-    base_configspec = call_box_interface.CallBoxInterface.CONFIGSPEC
-    CONFIGSPEC = configurable.list_to_configspec(base_configspec)
-    CONFIGSPEC['scpi_ip_address'] = "ip_addr(default='172.22.50.244')"
-
-    ALL_STATES = ['STOP', 'OFF', 'IDLE', 'CON', 'REG', 'LOOP', 'REL', 'UNAV']
-    IDLE_STATES = ['STOP', 'IDLE', 'OFF']
-    REGISTERED_STATES = ['REG']
-    CONNECTED_STATES = ['CON']
-    EXAMPLE_ID_STRING = "Agilent Technologies,E6621A,MY51100107,6.4.0.7"
-    MATCH_IN_EXAMPLE_ID_STRING = 'E6621'
+    def __new__(cls, config):
+        """
+        Call Box Factory. Rreturn the dummy class if fake_hardware
+        is true, otherwise return an object of this class.
+        :param cls:
+        :param config:
+        :return:
+        """
+        assert isinstance(config['fake_hardware'], bool)
+        if config['fake_hardware']:
+            fake = call_box_fake.CallBoxFakePxt(config)
+            return fake
+        else:
+            return super(CallBoxPxt, cls).__new__(cls, config)
+            #return cls.__new__(cls, config)
 
     def __init__(self, config):
         super(CallBoxPxt, self).__init__(config)
+        self.log.info('Constructing : %s' % self.__class__)
         self.scpi = prologix_scpi_driver.PrologixScpiDriver(
-            hostname=config['scpi_ip_address'],
-            port=config['port'],
-            gpib_address=config['gpib_address'],
-            read_timeout_seconds=config['read_timeout_seconds'],
-            connect_timeout_seconds=config['connect_timeout_seconds']
+            hostname=self.scpi_ip_address,
+            port=self.scpi_ip_port,
+            gpib_address=self.gpib_address,
+            read_timeout_seconds=self.read_timeout_seconds,
+            connect_timeout_seconds=self.connect_timeout_seconds
         )
         # Make sure we can talk to it, and it's the right box
         assert self.MATCH_IN_EXAMPLE_ID_STRING in self.get_id()
@@ -78,6 +84,7 @@
 
     def close(self):
         self.scpi.close()
+        time.sleep(.5)  # Enough to let the prologix adapter to disconnect
 
     def is_connected(self):
         return self._get_cell_status() in self.CONNECTED_STATES
@@ -107,9 +114,21 @@
             # Check freq (secs)
             'BSE:CONFig:RRC:CTIMer:LENGth 5',
             'SIGN:MODE BSE',
+            # These two have to be done before loading
             'SCENArio:LOAD "FDD_Combined_v6.3.lbmf"',
-            'BSE:CONF:PROF 20MH',
-            'FREQ:BAND 13',
+            'BSE:CONFig:NAS:DEFault:EBConfig1:ADDRess:V4 "%s"' %
+                 self.dut_ip_address,
+            'BSE:CONFig:NAS:DEFault:EBConfig1:APN "%s"' % self.apn_name,
+            'BSE:CONFig:NAS:MCC %s' % self.mcc,
+            'BSE:CONFig:NAS:MNCDigits %s' % self.mnc_digits,
+            'BSE:CONFig:NAS:MNC %s' % self.mnc,
+            'BSE:EPC EMBed',
+            'BSE:CONF:PROFile %sMH' % self.bandwidth_mhz,
+            'FREQ:BAND %s' % self.band,
+            'BSE:CONFig:PHY:UL:GRANT:SPS:RB:START %s' %
+                 self.resource_block_start,
+            'BSE:CONFig:PHY:UL:GRANT:SPS:RB:SIZE %s' % self.resource_block_stop,
+            'BSE:CONF:PHY:UL:GRANT:MODE %s' % self.tx_data_mode,
             'BSE:SIMULator RUN'
         ]
         self.scpi.send_list(commands)
@@ -126,4 +145,8 @@
             'Idle State: %s' % self.IDLE_STATES)
 
     def __del__(self):
-        self.scpi.close()
+        try:
+            self.scpi.close()
+        # If the tear down process has already removed the scpi object
+        except AttributeError:
+            pass
diff --git a/wireless_automation/instruments/call_box/call_box_factory.py b/wireless_automation/instruments/call_box/call_box_factory.py
index dc07e7f..5f7cfff 100644
--- a/wireless_automation/instruments/call_box/call_box_factory.py
+++ b/wireless_automation/instruments/call_box/call_box_factory.py
@@ -25,7 +25,7 @@
     CONFIGSPEC = \
         ['call_box_model=option("pxt","8960","fake", default="fake")'] + \
         configurable.nest_configspecs([
-            ('CallBox', call_box_interface.CallBoxInterface)
+            ('LteCallBox', call_box_interface.CallBoxLteInterface)
         ])
 
     def __init__(self, config):
@@ -48,7 +48,7 @@
         """
         Returns one callbox, built to the incoming config
         :param config: Config
-        :return: a CallBox that implements CallBoxInterface
+        :return: a CallBox that implements CallBoxBaseInterface
         """
         factory = CallBoxFactory(config)
         return factory.builder()
diff --git a/wireless_automation/instruments/call_box/call_box_fake.py b/wireless_automation/instruments/call_box/call_box_fake.py
index eb1d30b..126b409 100644
--- a/wireless_automation/instruments/call_box/call_box_fake.py
+++ b/wireless_automation/instruments/call_box/call_box_fake.py
@@ -11,8 +11,6 @@
 from wireless_automation.aspects import wireless_automation_error
 from wireless_automation.aspects import wireless_automation_logging
 from wireless_automation.instruments.call_box import call_box_interface
-from wireless_automation.instruments.call_box.agilent_pxt \
-    import call_box_pxt
 
 LOGGER_NAME = 'call_box_fake'
 
@@ -43,7 +41,7 @@
     return _inner
 
 
-class CallBoxFakeBase(call_box_interface.CallBoxInterface):
+class CallBoxBaseFakeBase(call_box_interface.CallBoxBaseInterface):
     """
     A fake call box. Used for running tests on a workstation unconnected
     to a call box. This may be implemented more then once. Different brands
@@ -54,7 +52,7 @@
     @log_args_and_return_values
     def __init__(self, config):
         self.log = wireless_automation_logging.setup_logging(LOGGER_NAME)
-        super(CallBoxFakeBase, self).__init__(config)
+        super(CallBoxBaseFakeBase, self).__init__(config)
         self._power = None
         self._rf_on = None
         self.reset()
@@ -83,6 +81,10 @@
         return self._current_state in self.CONNECTED_STATES
 
     @log_args_and_return_values
+    def is_registered(self):
+        return self._current_state in self.REGISTERED_STATES
+
+    @log_args_and_return_values
     def _get_cell_status(self):
         """
         :return: The |current_state| of the call
@@ -103,7 +105,6 @@
     @log_args_and_return_values
     def is_rf_on(self):
         """
-
         @rtype : object
         """
         return self._rf_on
@@ -125,17 +126,19 @@
         self._current_state = self.IDLE_STATES[0]
 
 
-class CallBoxFakePxt(CallBoxFakeBase):
+class CallBoxFakePxt(CallBoxBaseFakeBase):
     """
     Map the real PXT values, so we test those.
     """
-    CONFIGSPEC = call_box_pxt.CallBoxPxt.CONFIGSPEC
-    ALL_STATES = call_box_pxt.CallBoxPxt.ALL_STATES
-    CONNECTED_STATES = call_box_pxt.CallBoxPxt.CONNECTED_STATES
-    IDLE_STATES = call_box_pxt.CallBoxPxt.IDLE_STATES
-    EXAMPLE_ID_STRING = call_box_pxt.CallBoxPxt.EXAMPLE_ID_STRING
+    CONFIGSPEC = call_box_interface.CallBoxPxtInterface.CONFIGSPEC
+    ALL_STATES = call_box_interface.CallBoxPxtInterface.ALL_STATES
+    CONNECTED_STATES = call_box_interface.CallBoxPxtInterface.CONNECTED_STATES
+    REGISTERED_STATES = \
+        call_box_interface.CallBoxBaseInterface.REGISTERED_STATES
+    IDLE_STATES = call_box_interface.CallBoxPxtInterface.IDLE_STATES
+    EXAMPLE_ID_STRING = call_box_interface.CallBoxPxtInterface.EXAMPLE_ID_STRING
     MATCH_IN_EXAMPLE_ID_STRING = \
-        call_box_pxt.CallBoxPxt.MATCH_IN_EXAMPLE_ID_STRING
+        call_box_interface.CallBoxPxtInterface.MATCH_IN_EXAMPLE_ID_STRING
 
     def __init__(self, config):
         super(CallBoxFakePxt, self).__init__(config)
diff --git a/wireless_automation/instruments/call_box/call_box_interface.py b/wireless_automation/instruments/call_box/call_box_interface.py
index 790dfb9..a7cd9e3 100644
--- a/wireless_automation/instruments/call_box/call_box_interface.py
+++ b/wireless_automation/instruments/call_box/call_box_interface.py
@@ -8,27 +8,58 @@
 from wireless_automation.aspects import configurable
 
 
-class CallBoxInterface(configurable.Configurable):
+#pylint: disable=too-many-instance-attributes
+# These classes have methods defined in their subclasses, but
+# pylint doesn't see that.
+#pylint: disable=abstract-method
+class CallBoxBaseInterface(configurable.Configurable):
     """
     An interface for cellular call boxes.
     """
     CONFIGSPEC = [
-        'channel=integer(min=0, max=9999, default=1)',
+        '#  Do not use real hardware, use a minimal fake',
+        'fake_hardware=boolean(default=False)',
+        '# Keep state or reset CallBox when constructed.',
+        '# Useful for staring a test and keeping the call box in its state',
+        '# on_init=option("maintain_state",'
+                          ' "reset_state",default="reset_state")',
+        '# Setup the SCPI adapter on the CallBox ',
         'scpi_ip_address=ip_addr(default=None)',
-        'port=integer(default=1234)',
+        'scpi_ip_port=integer(default=1234)',
+        '# The GPIB address the SCPI adapter thinks the CallBox is on',
         'gpib_address=integer(min=0, max=999, default=14)',
         'read_timeout_seconds=integer(min=0, max=100, default=3)',
-        'connect_timeout_seconds=integer(min=0, max=100, default=10)'
+        'connect_timeout_seconds=integer(min=0, max=100, default=10)',
+        '# Setup the CallBox',
+        'band=integer(min=0, max=100, default=13)',
+        'apn_name=string(default="internet")',
+        'mnc=string(default="01")',  # Try 010 for Spring
+        'mnc_digits=integer(min=2,max=3,default=2)',
+        'mcc=string(default="001")',
+        '#  The IP assigned to the DUT by the CallBox',
+        'dut_ip_address=ip_addr(default="192.168.88.51")'
     ]
     ALL_STATES = []              # List of possible states
-    IDLE_STATES = []             # The state that means it's idle
+    IDLE_STATES = []             # The states that mean it's idle
     REGISTERED_STATES = []
     CONNECTED_STATES = []        # The states that count as connected
-    EXAMPLE_ID_STRING = "CallBoxInterface"  # The ID string *IDN? returns
+    EXAMPLE_ID_STRING = "CallBoxBaseInterface"  # The ID string *IDN? returns
     MATCH_IN_EXAMPLE_ID_STRING = 'Interface'
 
     def __init__(self, config):
-        super(CallBoxInterface, self).__init__(config)
+        super(CallBoxBaseInterface, self).__init__(config)
+        self.fake_hardware = config['fake_hardware']
+        self.scpi_ip_address = config['scpi_ip_address']
+        self.scpi_ip_port = config['scpi_ip_port']
+        self.gpib_address = config['gpib_address']
+        self.read_timeout_seconds = config['read_timeout_seconds']
+        self.connect_timeout_seconds = config['connect_timeout_seconds']
+        self.band = config['band']
+        self.apn_name = config['apn_name']
+        self.mnc = config['mnc']
+        self.mnc_digits = config['mnc_digits']
+        self.mcc = config['mcc']
+        self.dut_ip_address = config['dut_ip_address']
 
     def get_id(self):
         """
@@ -128,3 +159,73 @@
         """
 
         raise NotImplementedError
+
+LTE_CONFIGSPEC = [
+    '#  LTE specific settings',
+    'resource_block_start=integer(min=0,max=100,default=0)',
+    'resource_block_stop=integer(min=0,max=100,default=100)',
+    'bandwidth_mhz=option("1.4","3","5","10","15","20",default="10")',
+    'tx_data_mode=option("auto","fixed_mac_padding",default="auto")'
+]
+
+
+class CallBoxLteInterface(CallBoxBaseInterface):
+    """
+    Paramaters are added here for all call box's with LTE
+    """
+    CONFIGSPEC = CallBoxBaseInterface.CONFIGSPEC + LTE_CONFIGSPEC
+
+    def __init__(self, config):
+        super(CallBoxLteInterface, self).__init__(config)
+        self.resource_block_start = config['resource_block_start']
+        self.resource_block_stop = config['resource_block_stop']
+        self.bandwidth_mhz = config['bandwidth_mhz']
+        self.tx_data_mode = config['tx_data_mode']
+
+
+#pylint: disable=interface-not-implemented
+class CallBoxPxtInterface(CallBoxLteInterface):
+    """
+    This defines the internal states for both the Pxt and it's Fake.
+    """
+    base_configspec = CallBoxLteInterface.CONFIGSPEC
+    CONFIGSPEC = configurable.list_to_configspec(base_configspec)
+    CONFIGSPEC['scpi_ip_address'] = "ip_addr(default='172.22.50.244')"
+
+    ALL_STATES = ['STOP', 'OFF', 'IDLE', 'CON', 'REG', 'LOOP', 'REL', 'UNAV']
+    IDLE_STATES = ['STOP', 'IDLE', 'OFF']
+    REGISTERED_STATES = ['REG']
+    CONNECTED_STATES = ['CON']
+    EXAMPLE_ID_STRING = "Agilent Technologies,E6621A,MY51100107,6.4.0.7"
+    MATCH_IN_EXAMPLE_ID_STRING = 'E6621'
+
+
+HSPA_CONFIGSPEC = ['# HSPA and HSPA + settings here',
+                   '# More settings ']
+
+
+class CallBoxHspa3gInterface(CallBoxBaseInterface):
+    """
+    Adding the 3G config parameters.
+    """
+    CONFIGSPEC = CallBoxLteInterface.CONFIGSPEC + HSPA_CONFIGSPEC
+
+    def __init__(self, config):
+        CallBoxBaseInterface.__init__(config)
+
+
+class CallBoxLteHspa3gInterface(CallBoxBaseInterface):
+    """
+    Adding the HSPA and the 3G paramaters
+    """
+    CONFIGSPEC = CallBoxLteInterface.CONFIGSPEC + \
+        LTE_CONFIGSPEC + HSPA_CONFIGSPEC
+
+    def __init__(self, config):
+        # LTE settings
+        CallBoxBaseInterface.__init__(config)
+        self.resource_block_start = config['resource_block_start']
+        self.resource_block_stop = config['resource_block_stop']
+        self.bandwidth_mhz = config['bandwidth_mhz']
+        self.tx_data_mode = config['tx_data_mode']
+        # HSPA Settings
diff --git a/wireless_automation/instruments/prologix/prologix_scpi_driver.py b/wireless_automation/instruments/prologix/prologix_scpi_driver.py
index 0d622a7..2a8aeed 100644
--- a/wireless_automation/instruments/prologix/prologix_scpi_driver.py
+++ b/wireless_automation/instruments/prologix/prologix_scpi_driver.py
@@ -32,8 +32,10 @@
     """
     all_open_connections = {}
 
-    def __init__(self, hostname=None, port=1234, gpib_address=14,  # pylint:disable=too-many-arguments
-                 read_timeout_seconds=30, connect_timeout_seconds=5):  # pylint:disable=too-many-arguments
+  #pylint:disable=too-many-arguments
+    def __init__(self, hostname=None, port=1234, gpib_address=14,
+                 read_timeout_seconds=30, connect_timeout_seconds=5):
+
         """Constructs a wrapper for the Prologix TCP<->GPIB bridge :
         Arguments:
             hostname: hostname of prologix device
@@ -51,6 +53,8 @@
         self.scpi_logger = wireless_automation_logging.setup_logging(
             logger_name, formatter_string, level='INFO')
 
+        self.scpi_logger.debug("Connecting to %s : %s ..." % (hostname, port))
+
         if hostname is None:
             raise wireless_automation_error.BadState(
                 'PrologixScpiDriver needs a hostname')
@@ -71,11 +75,12 @@
         self.socket = self._get_socket_to_port(hostname, port,
                                                connect_timeout_seconds)
         self.auto = None
-        self.set_auto(1)
+        self._set_auto(1)
         self._add_returns_to_responses()
-        self.set_gpib_address(gpib_address)
+        self._set_gpib_address(gpib_address)
         self.scpi_logger.debug('set read_timeout_seconds: %s ' %
                                self.read_timeout_seconds)
+    #pylint:enable=too-many-arguments
 
     @classmethod
     def _get_socket_to_port(cls, hostname, port, connect_timeout_seconds):
@@ -113,7 +118,7 @@
         self.send('++eot_enable 1')
         self.send('++eot_char 10')
 
-    def set_auto(self, auto):
+    def _set_auto(self, auto):
         """Controls Prologix read-after-write (aka 'auto') mode."""
         # Must be an int so we can send it as an arg to ++auto.
         self.auto = int(auto)
@@ -121,6 +126,8 @@
 
     def close(self):
         """Closes the socket."""
+        caller = list(self.scpi_logger.findCaller())
+        caller[0] = os.path.basename(caller[0])
         self.scpi_logger.info('Close called by :' + str(caller))
         try:
             self.scpi_logger.error('Closing prologix devices at : %s ' %
@@ -134,7 +141,7 @@
         except AttributeError:  # Maybe we close before we finish building.
             pass
 
-    def set_gpib_address(self, gpib_address):
+    def _set_gpib_address(self, gpib_address):
         """
         Sets the GPIB address to talk to on the GPIB bus. This is used
         to select which instrument on the GPIB bus to use.
@@ -240,8 +247,9 @@
                 break
 
             if '-420' in error and 'Query UNTERMINATED' in error:
-                # This is benign; the GPIB bridge asked for a response when
+                # The GPIB bridge asked for a response when
                 # the device didn't have one to give.
+                self.scpi_logger.error(error)
                 continue
 
             if '+292' in error and 'Data arrived on unknown SAPI' in error: