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 5import re 6import time 7 8import common 9from autotest_lib.client.bin import utils 10from autotest_lib.client.cros.cellular import air_state_verifier 11from autotest_lib.client.cros.cellular import base_station_interface 12from autotest_lib.client.cros.cellular import cellular 13from autotest_lib.client.cros.cellular import cellular_logging 14from autotest_lib.client.cros.cellular import cellular_system_error 15 16POLL_SLEEP = 0.2 17 18log = cellular_logging.SetupCellularLogging('base_station_pxt') 19 20 21class 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 199class 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 215CALL:UPLink:TXPower:LEVel:MAXimum 24 216CALL: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(""" 221CALL:SCHannel:FORWard:DRATe BPS153600 222CALL: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(""" 227CALL:CELL:CONTrol:CATTribute:ISTate:PCCCycle ATSP 228# Default data application 229CALL:APPLication:SESSion DPAPlication 230# Give DUT 100% of channel 231CALL:CELL:APPLication:ATDPackets 100 232""") 233 234 GPRS_MAX = _Parse(""" 235call:bch:scel gprs 236call:pdtch:mslot:config d1u1 237call:cell:tbflow:t3192 ms1500 238""") 239 240 EGPRS_MAX = _Parse(""" 241call:bch:scel egprs 242call:pdtch:mslot:config d4u1 243call:cell:tbflow:t3192 ms1500 244""") 245 246 CAT_08 = _Parse(""" 247call:pow:stat ON 248call:ms:pow:targ 0 249call:cell:rlc:rees OFF 250call:hsdpa:ms:hsdschannel:cat:control:auto off 251call:hsdpa:ms:hsdschannel:cat:man 8 252call:hsdpa:service:psdata:hsdschannel:config cqiv 253call:hsdpa:service:psdata:cqi 22 254call:serv:gprs:rab PHSP 255call:serv:rbt:rab HSDP12 256call:serv:psd:srb:mapp UEDD 257call:hsup:serv:psd:edpd:ccod:max T2T4 258call:hsup:edch:tti MS10 259call:hsup:serv:psd:ergc:inf:stat Off 260""") 261 262 CAT_10 = _Parse(""" 263call:pow:stat ON 264call:ms:pow:targ 0 265call:cell:rlc:rees OFF 266call:hsdpa:ms:hsdschannel:cat:control:auto off 267call:hsdpa:ms:hsdschannel:cat:man 10 268call:serv:gprs:rab PHSP 269call:serv:rbt:rab HSDP12 270call:hsdpa:service:psdata:hsdschannel:config cqiv 271call:hsdpa:service:psdata:cqi 22 272call:serv:psd:srb:mapp UEDD 273call:hsup:serv:psd:edpd:ccod:max T2T4 274call:hsup:edch:tti MS2 275call:hsup:serv:psd:ergc:inf:stat Off 276""") 277 278 279class 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