Home | History | Annotate | Download | only in cellular
      1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import re
      6 import time
      7 
      8 import common
      9 from autotest_lib.client.bin import utils
     10 from autotest_lib.client.cros.cellular import air_state_verifier
     11 from autotest_lib.client.cros.cellular import base_station_interface
     12 from autotest_lib.client.cros.cellular import cellular
     13 from autotest_lib.client.cros.cellular import cellular_logging
     14 from autotest_lib.client.cros.cellular import cellular_system_error
     15 
     16 POLL_SLEEP = 0.2
     17 
     18 log = cellular_logging.SetupCellularLogging('base_station_pxt')
     19 
     20 
     21 class BaseStationPxt(base_station_interface.BaseStationInterface):
     22     """Wrap an Agilent PXT"""
     23 
     24     def __init__(self, scpi_connection, no_initialization=False):
     25         """
     26         Creates a PXT call-box object.
     27         TODO(byronk): Make a factory that returns a call_box, of either
     28         a 8960 or a PXT, or a...
     29 
     30         @param scpi_connection:  The scpi port to send commands over.
     31         @param no_initialization: Don't do anything. Useful for unit testing
     32         and debugging when you don't want to run all the usual functions.
     33         """
     34         # TODO(byronk): Use variables longer then 1 char.
     35         self.c = scpi_connection
     36         if no_initialization:
     37             return
     38         self.checker_context = self.c.checker_context
     39         with self.checker_context:
     40             self._Verify()
     41             self._Reset()
     42 
     43     def _Verify(self):
     44         idn = self.c.Query('*IDN?')
     45         if 'E6621' not in idn:
     46             raise cellular_system_error.BadScpiCommand(
     47                 'Not actually a E6621 PXT:  *IDN? says ' + idn)
     48 
     49     def _Reset(self):
     50         self.c.Reset()
     51         self.Stop()
     52 
     53     def _IsIdle(self):
     54         bs_active = self.c.Query('BSE:SIMULator?')
     55         return bs_active == 'STOP'
     56 
     57     def Close(self):
     58         self.c.Close()
     59 
     60     def GetAirStateVerifier(self):
     61         return air_state_verifier.AirStateVerifierBasestation(self)
     62 
     63     def GetDataCounters(self):
     64         raise NotImplementedError
     65 
     66     def GetRatUeDataStatus(self):
     67         """Get the radio-access-technology-specific status of the UE.
     68 
     69         Unlike GetUeDataStatus, below, this returns a status that depends
     70         on the RAT being used.
     71         """
     72         status = self.c.Query('BSE:STATus:ACELL?')
     73         rat = \
     74             ConfigDictionaries.FORMAT_TO_DATA_STATUS_TYPE[self.format][status]
     75         return rat
     76 
     77     def GetUeDataStatus(self):
     78         """Get the UeGenericDataStatus status of the device."""
     79         rat = self.GetRatUeDataStatus()
     80         return cellular.RatToGenericDataStatus[rat]
     81 
     82     def ResetDataCounters(self):
     83         # Keep this here until the implementation of this class
     84         # is done. If we never hit this, then we can safely remove it,
     85         # but we should think twice about that. The 8960 needs it,
     86         # it seems likely that the PXT should.
     87         raise NotImplementedError
     88 
     89     def ClearErrors(self):
     90         self.c.RetrieveErrors()
     91 
     92     def LogStats(self):
     93         # Keep this here until the implementation of this class
     94         # is done. If we never hit this, then we can safely remove it,
     95         # but we should think twice about that. The 8960 needs it,
     96         # it seems likely that the PXT should.
     97         raise NotImplementedError
     98 
     99     def SetBsIpV4(self, ip1, ip2):
    100         return  # TODO(byronk): Configure the PXT to find.crbug.com:/235643
    101 
    102     def SetBsNetmaskV4(self, netmask):
    103         return  # TODO(byronk): Configure the PXT to find. crbug.com:/235643
    104 
    105     def SetPlmn(self, mcc, mnc):
    106         raise NotImplementedError
    107 
    108     def SetPower(self, dbm):
    109         # TODO(byronk): Setting the RF output of the PXT. crbug.com/235655
    110         # and 8960 call boxes to OFF should be off
    111         if dbm <= cellular.Power.OFF:
    112             self.c.SendStanza(['AMPLitude:ALL -120'])
    113         else:
    114             self.c.SendStanza(['AMPLitude:ALL %s' % dbm])
    115 
    116     def SetTechnology(self, technology):
    117         # TODO(byronk):  The set technology step likely belongs in the
    118         # constructor.
    119 
    120         # Print out a helpful message on a key error.
    121         try:
    122             self.format = ConfigDictionaries.TECHNOLOGY_TO_FORMAT[technology]
    123         except KeyError:
    124             raise KeyError('%s not in %s ' % (
    125                 technology,
    126                 ConfigDictionaries.TECHNOLOGY_TO_FORMAT))
    127         self.technology = technology
    128 
    129     def SetUeDnsV4(self, dns1, dns2):
    130         """Set the DNS values provided to the UE.  Emulator must be stopped."""
    131         return  # TODO(byronk): Configure the PXT to find. crbug.com/235643
    132                 # the data server
    133 
    134     def SetUeIpV4(self, ip1, ip2=None):
    135         """
    136         Set the IP addresses provided to the UE. Emulator must be stopped.
    137         """
    138         return  # TODO(byronk) crbug.com:/235643: Configure the PXT to find
    139                 # the data server
    140 
    141     def Start(self):
    142         commands = [
    143             '*CLS',
    144             'STATus:PRESet',
    145             # Enable conn checks
    146             'BSE:CONFig:RRC:CTIMer:STATus ON',
    147             # Check freq (secs)
    148             'BSE:CONFig:RRC:CTIMer:LENGth 5',
    149             'SIGN:MODE BSE',
    150             'SCENArio:LOAD "FDD_Combined_v6.3.lbmf"',
    151             'BSE:CONF:PROF 20MH',
    152             'FREQ:BAND 13',
    153             'BSE:SIMULator RUN'
    154         ]
    155         self.c.SendStanza(commands)
    156 
    157     def Stop(self):
    158         self.c.SendStanza(['BSE:SIMULator STOP'])
    159         # Make sure the call status goes to idle before continuing.
    160         utils.poll_for_condition(
    161             self._IsIdle,
    162             timeout=cellular.DEFAULT_TIMEOUT,
    163             exception=cellular_system_error.BadState(
    164                 'PXT did not enter IDLE state'))
    165 
    166     def SupportedTechnologies(self):
    167         return [cellular.Technology.LTE]
    168 
    169     def WaitForStatusChange(self,
    170                             interested=None,
    171                             timeout=cellular.DEFAULT_TIMEOUT):
    172         """When UE status changes (to a value in |interested|),
    173         return the value.
    174 
    175         Arguments:
    176             interested: if non-None, only transitions to these states will
    177               cause a return
    178             timeout: in seconds.
    179         Returns: state
    180         Raises: cellular_system_error.InstrumentTimeout
    181         """
    182         start = time.time()
    183         # TODO(byronk): consider utils.poll_for_condition()
    184         while time.time() - start <= timeout:
    185             state = self.GetUeDataStatus()
    186             if state in interested:
    187                 return state
    188             time.sleep(POLL_SLEEP)
    189 
    190         state = self.GetUeDataStatus()
    191         if state in interested:
    192             return state
    193 
    194         raise cellular_system_error.InstrumentTimeout(
    195             'Timed out waiting for state in %s.  State was %s.' %
    196             (interested, state))
    197 
    198 
    199 class ConfigStanzas(object):
    200     # p 22 of http://cp.literature.agilent.com/litweb/pdf/5989-5932EN.pdf
    201 
    202     def _Parse( command_sequence):
    203         """Split and remove comments from a config stanza."""
    204         return [line for line in command_sequence.splitlines()
    205                 if line and not line.startswith('#')]
    206 
    207     LTE = _Parse(""" """)
    208 
    209     # TODO(byronk): ConfigStanza should not be. These belong somewhere in
    210     # the PXT class.
    211     WCDMA_MAX = _Parse("""
    212 # RAB3: 64 Up/384 down
    213 # http://wireless.agilent.com/rfcomms/refdocs/
    214 #        wcdma/wcdmala_hpib_call_service.html#CACBDEAH
    215 CALL:UPLink:TXPower:LEVel:MAXimum 24
    216 CALL:SERVICE:GPRS:RAB GPRSRAB3
    217 """)
    218 
    219     # p 20 of http://cp.literature.agilent.com/litweb/pdf/5989-5932EN.pdf
    220     CDMA_2000_MAX = _Parse("""
    221 CALL:SCHannel:FORWard:DRATe BPS153600
    222 CALL:CELL:SOPTion:RCONfig3 SOFS33
    223 """)
    224 
    225     # p 19 of http://cp.literature.agilent.com/litweb/pdf/5989-5932EN.pdf
    226     EVDO_1X_MAX = _Parse("""
    227 CALL:CELL:CONTrol:CATTribute:ISTate:PCCCycle ATSP
    228 # Default data application
    229 CALL:APPLication:SESSion DPAPlication
    230 # Give DUT 100% of channel
    231 CALL:CELL:APPLication:ATDPackets 100
    232 """)
    233 
    234     GPRS_MAX = _Parse("""
    235 call:bch:scel gprs
    236 call:pdtch:mslot:config d1u1
    237 call:cell:tbflow:t3192 ms1500
    238 """)
    239 
    240     EGPRS_MAX = _Parse("""
    241 call:bch:scel egprs
    242 call:pdtch:mslot:config d4u1
    243 call:cell:tbflow:t3192 ms1500
    244 """)
    245 
    246     CAT_08 = _Parse("""
    247 call:pow:stat ON
    248 call:ms:pow:targ 0
    249 call:cell:rlc:rees OFF
    250 call:hsdpa:ms:hsdschannel:cat:control:auto off
    251 call:hsdpa:ms:hsdschannel:cat:man 8
    252 call:hsdpa:service:psdata:hsdschannel:config cqiv
    253 call:hsdpa:service:psdata:cqi 22
    254 call:serv:gprs:rab PHSP
    255 call:serv:rbt:rab HSDP12
    256 call:serv:psd:srb:mapp UEDD
    257 call:hsup:serv:psd:edpd:ccod:max T2T4
    258 call:hsup:edch:tti MS10
    259 call:hsup:serv:psd:ergc:inf:stat Off
    260 """)
    261 
    262     CAT_10 = _Parse("""
    263 call:pow:stat ON
    264 call:ms:pow:targ 0
    265 call:cell:rlc:rees OFF
    266 call:hsdpa:ms:hsdschannel:cat:control:auto off
    267 call:hsdpa:ms:hsdschannel:cat:man 10
    268 call:serv:gprs:rab PHSP
    269 call:serv:rbt:rab HSDP12
    270 call:hsdpa:service:psdata:hsdschannel:config cqiv
    271 call:hsdpa:service:psdata:cqi 22
    272 call:serv:psd:srb:mapp UEDD
    273 call:hsup:serv:psd:edpd:ccod:max T2T4
    274 call:hsup:edch:tti MS2
    275 call:hsup:serv:psd:ergc:inf:stat Off
    276 """)
    277 
    278 
    279 class ConfigDictionaries(object):
    280     TECHNOLOGY_TO_FORMAT_RAW = {
    281         cellular.Technology.GPRS: 'GSM/GPRS',
    282         cellular.Technology.EGPRS: 'GSM/GPRS',
    283 
    284         cellular.Technology.WCDMA: 'WCDMA',
    285         cellular.Technology.HSDPA: 'WCDMA',
    286         cellular.Technology.HSUPA: 'WCDMA',
    287         cellular.Technology.HSDUPA: 'WCDMA',
    288         cellular.Technology.HSPA_PLUS: 'WCDMA',
    289 
    290         cellular.Technology.CDMA_2000: 'IS-2000/IS-95/AMPS',
    291 
    292         cellular.Technology.EVDO_1X: 'IS-856',
    293 
    294         cellular.Technology.LTE: 'LTE',
    295     }
    296 
    297     # Put each value in "" marks to quote it for GPIB
    298     TECHNOLOGY_TO_FORMAT = dict([
    299         (x, '"%s"' % y) for
    300         x, y in TECHNOLOGY_TO_FORMAT_RAW.iteritems()])
    301 
    302     TECHNOLOGY_TO_CONFIG_STANZA = {
    303         cellular.Technology.CDMA_2000: ConfigStanzas.CDMA_2000_MAX,
    304         cellular.Technology.EVDO_1X: ConfigStanzas.EVDO_1X_MAX,
    305         cellular.Technology.GPRS: ConfigStanzas.GPRS_MAX,
    306         cellular.Technology.EGPRS: ConfigStanzas.EGPRS_MAX,
    307         cellular.Technology.WCDMA: ConfigStanzas.WCDMA_MAX,
    308         cellular.Technology.HSDPA: ConfigStanzas.CAT_08,
    309         cellular.Technology.HSUPA: ConfigStanzas.CAT_08,
    310         cellular.Technology.HSDUPA: ConfigStanzas.CAT_08,
    311         cellular.Technology.HSPA_PLUS: ConfigStanzas.CAT_10,
    312         cellular.Technology.LTE: ConfigStanzas.LTE,
    313     }
    314     # TODO(byronk): remove these. Not used for LTE. Check for external deps
    315     # http://wireless.agilent.com/rfcomms/refdocs/
    316     #        gsmgprs/prog_synch_callstategprs.html#CHDDFBAJ
    317     # NB:  We have elided a few states of the GSM state machine here.
    318     CALL_STATUS_DATA_TO_STATUS_GSM_GPRS = {
    319         'IDLE': cellular.UeGsmDataStatus.IDLE,
    320         'ATTG': cellular.UeGsmDataStatus.ATTACHING,
    321         'DET': cellular.UeGsmDataStatus.DETACHING,
    322         'ATT': cellular.UeGsmDataStatus.ATTACHED,
    323         'STAR': cellular.UeGsmDataStatus.ATTACHING,
    324         'END': cellular.UeGsmDataStatus.PDP_DEACTIVATING,
    325         'TRAN': cellular.UeGsmDataStatus.PDP_ACTIVE,
    326         'PDPAG': cellular.UeGsmDataStatus.PDP_ACTIVATING,
    327         'PDP': cellular.UeGsmDataStatus.PDP_ACTIVE,
    328         'PDPD': cellular.UeGsmDataStatus.PDP_DEACTIVATING,
    329         'DCON': cellular.UeGsmDataStatus.PDP_ACTIVE,
    330         'SUSP': cellular.UeGsmDataStatus.IDLE,
    331     }
    332 
    333     # http://wireless.agilent.com/rfcomms/refdocs/
    334     #        wcdma/wcdma_gen_call_proc_status.html#CJADGAHG
    335     CALL_STATUS_DATA_TO_STATUS_WCDMA = {
    336         'IDLE': cellular.UeGsmDataStatus.IDLE,
    337         'ATTG': cellular.UeGsmDataStatus.ATTACHING,
    338         'DET': cellular.UeGsmDataStatus.DETACHING,
    339         'OFF': cellular.UeGsmDataStatus.NONE,
    340         'PDPAG': cellular.UeGsmDataStatus.PDP_ACTIVATING,
    341         'PDP': cellular.UeGsmDataStatus.PDP_ACTIVE,
    342         'PDPD': cellular.UeGsmDataStatus.PDP_DEACTIVATING,
    343     }
    344 
    345     # http://wireless.agilent.com/rfcomms/refdocs/
    346     #        cdma2k/cdma2000_hpib_call_status.html#CJABGBCF
    347     CALL_STATUS_DATA_TO_STATUS_CDMA_2000 = {
    348         'OFF': cellular.UeC2kDataStatus.OFF,
    349         'DORM': cellular.UeC2kDataStatus.DORMANT,
    350         'DCON': cellular.UeC2kDataStatus.DATA_CONNECTED,
    351     }
    352 
    353     # http://wireless.agilent.com/rfcomms/refdocs/
    354     #        1xevdo/1xevdo_hpib_call_status.html#BABCGBCD
    355     CALL_STATUS_DATA_TO_STATUS_EVDO = {
    356         'CCL': cellular.UeEvdoDataStatus.CONNECTION_CLOSING,
    357         'CNEG': cellular.UeEvdoDataStatus.CONNECTION_NEGOTIATE,
    358         'CREQ': cellular.UeEvdoDataStatus.CONNECTION_REQUEST,
    359         'DCON': cellular.UeEvdoDataStatus.DATA_CONNECTED,
    360         'DORM': cellular.UeEvdoDataStatus.DORMANT,
    361         'HAND': cellular.UeEvdoDataStatus.HANDOFF,
    362         'IDLE': cellular.UeEvdoDataStatus.IDLE,
    363         'PAG': cellular.UeEvdoDataStatus.PAGING,
    364         'SCL': cellular.UeEvdoDataStatus.SESSION_CLOSING,
    365         'SNEG': cellular.UeEvdoDataStatus.SESSION_NEGOTIATE,
    366         'SOP': cellular.UeEvdoDataStatus.SESSION_OPEN,
    367         'UREQ': cellular.UeEvdoDataStatus.UATI_REQUEST,
    368     }
    369 
    370     #lte status from BSE:STATus:ACELL? on the PXT
    371     #OFF | IDLE | CON | REG |
    372     #LOOP | REL | UNAV
    373 
    374     CALL_STATUS_DATA_TO_STATUS_LTE = {
    375         'OFF': cellular.UeLteDataStatus.OFF,
    376         'IDLE': cellular.UeLteDataStatus.IDLE,
    377         'CON': cellular.UeLteDataStatus.CONNECTED,
    378         'REG': cellular.UeLteDataStatus.REGISTERED,
    379         'LOOP': cellular.UeLteDataStatus.LOOPBACK,
    380         'REL': cellular.UeLteDataStatus.RELEASE,
    381         'UNAV': cellular.UeLteDataStatus.UNAVAILABLE,
    382     }
    383     FORMAT_TO_DATA_STATUS_TYPE = {
    384         '"GSM/GPRS"': CALL_STATUS_DATA_TO_STATUS_GSM_GPRS,
    385         '"WCDMA"': CALL_STATUS_DATA_TO_STATUS_WCDMA,
    386         '"IS-2000/IS-95/AMPS"': CALL_STATUS_DATA_TO_STATUS_CDMA_2000,
    387         '"IS-856"': CALL_STATUS_DATA_TO_STATUS_EVDO,
    388         '"LTE"': CALL_STATUS_DATA_TO_STATUS_LTE,
    389     }
    390