You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
14 KiB
391 lines
14 KiB
# 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.
|
|
|
|
import logging
|
|
import re
|
|
import time
|
|
import common
|
|
from autotest_lib.client.cros.cellular import cellular_logging
|
|
from autotest_lib.client.cros.cellular import cellular_system_error
|
|
from autotest_lib.client.cros.cellular import air_state_verifier
|
|
from autotest_lib.client.cros.cellular import base_station_interface
|
|
from autotest_lib.client.cros.cellular import cellular
|
|
from autotest_lib.client.bin import utils
|
|
|
|
POLL_SLEEP = 0.2
|
|
|
|
log = cellular_logging.SetupCellularLogging('base_station_8960')
|
|
|
|
class BaseStation8960(base_station_interface.BaseStationInterface):
|
|
"""Wrap an Agilent 8960 Series 10."""
|
|
|
|
def __init__(self, scpi_connection, no_initialization=False):
|
|
"""
|
|
Creates an 8960 call-box object.
|
|
TODO (byrok): make a factory that returns a call_box, of either
|
|
a 8960 or a PXT, or a...
|
|
|
|
@param scpi_connection: The scpi port to send commands over
|
|
@param no_initialization: Don't do anything. Useful for unit testing
|
|
and debugging when you don't want to run all the usual functions.
|
|
"""
|
|
self.c = scpi_connection
|
|
if no_initialization:
|
|
return
|
|
self.checker_context = self.c.checker_context
|
|
with self.checker_context:
|
|
self._Verify()
|
|
self._Reset()
|
|
self.SetPower(cellular.Power.DEFAULT)
|
|
|
|
def _Verify(self):
|
|
idn = self.c.Query('*IDN?')
|
|
if '8960 Series 10 E5515C' not in idn:
|
|
raise cellular_system_error.BadState(
|
|
'Not actually an 8960: *IDN? says ' + idn)
|
|
|
|
def _Reset(self):
|
|
self.c.Reset()
|
|
self.Stop()
|
|
# Perform a partial reset to workaround a problem with the 8960
|
|
# failing to accept CDMA connections after switching from a
|
|
# GSM technology.
|
|
self.c.SendStanza(['SYSTEM:PRESet3'])
|
|
|
|
def _IsIdle(self):
|
|
call_state = self.c.Query('CALL:STATus?')
|
|
data_state = self.c.Query('CALL:STATus:DATa?')
|
|
return call_state == 'IDLE' and data_state in ['IDLE', 'OFF']
|
|
|
|
def Close(self):
|
|
self.c.Close()
|
|
|
|
def GetAirStateVerifier(self):
|
|
return air_state_verifier.AirStateVerifierBasestation(self)
|
|
|
|
def GetDataCounters(self):
|
|
output = {}
|
|
for counter in ['OTATx', 'OTARx', 'IPTX', 'IPRX']:
|
|
result_text = self.c.Query('CALL:COUNT:DTMonitor:%s:DRATe?' %
|
|
counter)
|
|
result = [float(x) for x in result_text.rstrip().split(',')]
|
|
output[counter] = dict(zip(['Mean', 'Current', 'Max', 'Total'],
|
|
result))
|
|
logging.info('Data counters: %s', output)
|
|
return output
|
|
|
|
def GetRatUeDataStatus(self):
|
|
"""Get the radio-access-technology-specific status of the UE.
|
|
|
|
Unlike GetUeDataStatus, below, this returns a status that depends
|
|
on the RAT being used.
|
|
"""
|
|
status = self.c.Query('CALL:STATus:DATa?')
|
|
rat = \
|
|
ConfigDictionaries.FORMAT_TO_DATA_STATUS_TYPE[self.format][status]
|
|
return rat
|
|
|
|
def GetUeDataStatus(self):
|
|
"""Get the UeGenericDataStatus status of the device."""
|
|
rat = self.GetRatUeDataStatus()
|
|
return cellular.RatToGenericDataStatus[rat]
|
|
|
|
def ResetDataCounters(self):
|
|
self.c.SendStanza(['CALL:COUNt:DTMonitor:CLEar'])
|
|
|
|
def ClearErrors(self):
|
|
self.c.RetrieveErrors()
|
|
|
|
def LogStats(self):
|
|
self.c.Query("CALL:HSDPa:SERVice:PSData:HSDSchannel:CONFig?")
|
|
|
|
# Category reported by UE
|
|
self.c.Query("CALL:HSDPa:MS:REPorted:HSDSChannel:CATegory?")
|
|
# The category in use
|
|
self.c.Query("CALL:STATUS:MS:HSDSChannel:CATegory?")
|
|
self.c.Query("CALL:HSDPA:SERV:PSD:CQI?")
|
|
|
|
def SetBsIpV4(self, ip1, ip2):
|
|
self.c.SendStanza([
|
|
'SYSTem:COMMunicate:LAN:SELF:ADDRess:IP4 "%s"' % ip1,
|
|
'SYSTem:COMMunicate:LAN:SELF:ADDRess2:IP4 "%s"' % ip2,])
|
|
|
|
def SetBsNetmaskV4(self, netmask):
|
|
self.c.SendStanza([
|
|
'SYSTem:COMMunicate:LAN:SELF:SMASk:IP4 "%s"' % netmask,])
|
|
|
|
def SetPlmn(self, mcc, mnc):
|
|
# Doing this appears to set the WCDMa versions as well
|
|
self.c.SendStanza([
|
|
'CALL:MCCode %s' % mcc,
|
|
'CALL:MNCode %s' % mnc,])
|
|
|
|
def SetPower(self, dbm):
|
|
if dbm <= cellular.Power.OFF :
|
|
self.c.SendStanza([
|
|
'CALL:CELL:POWer:STATe off',])
|
|
else:
|
|
self.c.SendStanza([
|
|
'CALL:CELL:POWer %s' % dbm,])
|
|
|
|
def SetTechnology(self, technology):
|
|
# TODO(rochberg): Check that we're not already in chosen tech for
|
|
# speed boost
|
|
|
|
# Print out a helpful message on a key error.
|
|
try:
|
|
self.format = ConfigDictionaries.TECHNOLOGY_TO_FORMAT[technology]
|
|
except KeyError:
|
|
raise KeyError('%s not in %s ' %
|
|
(technology,
|
|
ConfigDictionaries.TECHNOLOGY_TO_FORMAT))
|
|
self.technology = technology
|
|
|
|
self.c.SimpleVerify('SYSTem:APPLication:FORMat', self.format)
|
|
# Setting the format will start the call box, we need to stop it so we
|
|
# can configure the new format.
|
|
self.Stop()
|
|
self.c.SendStanza(
|
|
ConfigDictionaries.TECHNOLOGY_TO_CONFIG_STANZA.get(technology, []))
|
|
|
|
def SetUeDnsV4(self, dns1, dns2):
|
|
"""Set the DNS values provided to the UE. Emulator must be stopped."""
|
|
stanza = ['CALL:MS:DNSServer:PRIMary:IP:ADDRess "%s"' % dns1]
|
|
if dns2:
|
|
stanza.append('CALL:MS:DNSServer:SECondary:IP:ADDRess "%s"' % dns2)
|
|
self.c.SendStanza(stanza)
|
|
|
|
def SetUeIpV4(self, ip1, ip2=None):
|
|
"""
|
|
Set the IP addresses provided to the UE. Emulator must be stopped.
|
|
"""
|
|
stanza = ['CALL:MS:IP:ADDRess1 "%s"' % ip1]
|
|
if ip2:
|
|
stanza.append('CALL:MS:IP:ADDRess2 "%s"' % ip2)
|
|
self.c.SendStanza(stanza)
|
|
|
|
def Start(self):
|
|
self.c.SendStanza(['CALL:OPERating:MODE CALL'])
|
|
|
|
def Stop(self):
|
|
self.c.SendStanza(['CALL:OPERating:MODE OFF'])
|
|
# Make sure the call status goes to idle before continuing.
|
|
utils.poll_for_condition(
|
|
self._IsIdle,
|
|
timeout=cellular.DEFAULT_TIMEOUT,
|
|
exception=cellular_system_error.BadState(
|
|
'8960 did not enter IDLE state'))
|
|
|
|
def SupportedTechnologies(self):
|
|
return [
|
|
cellular.Technology.GPRS,
|
|
cellular.Technology.EGPRS,
|
|
cellular.Technology.WCDMA,
|
|
cellular.Technology.HSDPA,
|
|
cellular.Technology.HSUPA,
|
|
cellular.Technology.HSDUPA,
|
|
cellular.Technology.HSPA_PLUS,
|
|
cellular.Technology.CDMA_2000,
|
|
cellular.Technology.EVDO_1X,
|
|
]
|
|
|
|
def WaitForStatusChange(self,
|
|
interested=None,
|
|
timeout=cellular.DEFAULT_TIMEOUT):
|
|
"""When UE status changes (to a value in interested), return the value.
|
|
|
|
Arguments:
|
|
interested: if non-None, only transitions to these states will
|
|
cause a return
|
|
timeout: in seconds.
|
|
Returns: state
|
|
Raises: cellular_system_error.InstrumentTimeout
|
|
"""
|
|
start = time.time()
|
|
while time.time() - start <= timeout:
|
|
state = self.GetUeDataStatus()
|
|
if state in interested:
|
|
return state
|
|
time.sleep(POLL_SLEEP)
|
|
|
|
state = self.GetUeDataStatus()
|
|
if state in interested:
|
|
return state
|
|
|
|
raise cellular_system_error.InstrumentTimeout(
|
|
'Timed out waiting for state in %s. State was %s' %
|
|
(interested, state))
|
|
|
|
def _Parse(command_sequence):
|
|
"""Split and remove comments from a config stanza."""
|
|
uncommented = [re.sub(r'\s*#.*', '', line)
|
|
for line in command_sequence.split('\n')]
|
|
|
|
# Return only nonempty lines
|
|
return [line for line in uncommented if line]
|
|
|
|
|
|
class ConfigStanzas(object):
|
|
# p 22 of http://cp.literature.agilent.com/litweb/pdf/5989-5932EN.pdf
|
|
WCDMA_MAX = _Parse("""
|
|
# RAB3: 64 Up/384 down
|
|
# http://wireless.agilent.com/rfcomms/refdocs/wcdma/wcdmala_hpib_call_service.html#CACBDEAH
|
|
CALL:UPLink:TXPower:LEVel:MAXimum 24
|
|
CALL:SERVICE:GPRS:RAB GPRSRAB3
|
|
""")
|
|
|
|
# p 20 of http://cp.literature.agilent.com/litweb/pdf/5989-5932EN.pdf
|
|
CDMA_2000_MAX = _Parse("""
|
|
CALL:SCHannel:FORWard:DRATe BPS153600
|
|
CALL:CELL:SOPTion:RCONfig3 SOFS33
|
|
""")
|
|
|
|
# p 19 of http://cp.literature.agilent.com/litweb/pdf/5989-5932EN.pdf
|
|
EVDO_1X_MAX = _Parse("""
|
|
CALL:CELL:CONTrol:CATTribute:ISTate:PCCCycle ATSP
|
|
# Default data application
|
|
CALL:APPLication:SESSion DPAPlication
|
|
# Give DUT 100% of channel
|
|
CALL:CELL:APPLication:ATDPackets 100
|
|
""")
|
|
|
|
GPRS_MAX = _Parse("""
|
|
call:bch:scel gprs
|
|
call:pdtch:mslot:config d1u1
|
|
call:cell:tbflow:t3192 ms1500
|
|
""")
|
|
|
|
EGPRS_MAX = _Parse("""
|
|
call:bch:scel egprs
|
|
call:pdtch:mslot:config d4u1
|
|
call:cell:tbflow:t3192 ms1500
|
|
""")
|
|
|
|
CAT_08 = _Parse("""
|
|
call:pow:stat ON
|
|
call:ms:pow:targ 0
|
|
call:cell:rlc:rees OFF
|
|
call:hsdpa:ms:hsdschannel:cat:control:auto off
|
|
call:hsdpa:ms:hsdschannel:cat:man 8
|
|
call:hsdpa:service:psdata:hsdschannel:config cqiv
|
|
call:hsdpa:service:psdata:cqi 22
|
|
call:serv:gprs:rab PHSP
|
|
call:serv:rbt:rab HSDP12
|
|
call:serv:psd:srb:mapp UEDD
|
|
call:hsup:serv:psd:edpd:ccod:max T2T4
|
|
call:hsup:edch:tti MS10
|
|
call:hsup:serv:psd:ergc:inf:stat Off
|
|
""")
|
|
|
|
CAT_10 = _Parse("""
|
|
call:pow:stat ON
|
|
call:ms:pow:targ 0
|
|
call:cell:rlc:rees OFF
|
|
call:hsdpa:ms:hsdschannel:cat:control:auto off
|
|
call:hsdpa:ms:hsdschannel:cat:man 10
|
|
call:serv:gprs:rab PHSP
|
|
call:serv:rbt:rab HSDP12
|
|
call:hsdpa:service:psdata:hsdschannel:config cqiv
|
|
call:hsdpa:service:psdata:cqi 22
|
|
call:serv:psd:srb:mapp UEDD
|
|
call:hsup:serv:psd:edpd:ccod:max T2T4
|
|
call:hsup:edch:tti MS2
|
|
call:hsup:serv:psd:ergc:inf:stat Off
|
|
""")
|
|
|
|
class ConfigDictionaries(object):
|
|
TECHNOLOGY_TO_FORMAT_RAW = {
|
|
cellular.Technology.GPRS: 'GSM/GPRS',
|
|
cellular.Technology.EGPRS: 'GSM/GPRS',
|
|
|
|
cellular.Technology.WCDMA: 'WCDMA',
|
|
cellular.Technology.HSDPA: 'WCDMA',
|
|
cellular.Technology.HSUPA: 'WCDMA',
|
|
cellular.Technology.HSDUPA: 'WCDMA',
|
|
cellular.Technology.HSPA_PLUS: 'WCDMA',
|
|
|
|
cellular.Technology.CDMA_2000: 'IS-2000/IS-95/AMPS',
|
|
|
|
cellular.Technology.EVDO_1X: 'IS-856',
|
|
}
|
|
|
|
# Put each value in "" marks to quote it for GPIB
|
|
TECHNOLOGY_TO_FORMAT = dict([
|
|
(x, '"%s"' % y) for
|
|
x, y in TECHNOLOGY_TO_FORMAT_RAW.iteritems()])
|
|
|
|
TECHNOLOGY_TO_CONFIG_STANZA = {
|
|
cellular.Technology.CDMA_2000: ConfigStanzas.CDMA_2000_MAX,
|
|
cellular.Technology.EVDO_1X: ConfigStanzas.EVDO_1X_MAX,
|
|
cellular.Technology.GPRS: ConfigStanzas.GPRS_MAX,
|
|
cellular.Technology.EGPRS: ConfigStanzas.EGPRS_MAX,
|
|
cellular.Technology.WCDMA: ConfigStanzas.WCDMA_MAX,
|
|
cellular.Technology.HSDPA: ConfigStanzas.CAT_08,
|
|
cellular.Technology.HSUPA: ConfigStanzas.CAT_08,
|
|
cellular.Technology.HSDUPA: ConfigStanzas.CAT_08,
|
|
cellular.Technology.HSPA_PLUS: ConfigStanzas.CAT_10,
|
|
}
|
|
|
|
# http://wireless.agilent.com/rfcomms/refdocs/
|
|
# gsmgprs/prog_synch_callstategprs.html#CHDDFBAJ
|
|
# NB: We have elided a few states of the GSM state machine here.
|
|
CALL_STATUS_DATA_TO_STATUS_GSM_GPRS = {
|
|
'IDLE': cellular.UeGsmDataStatus.IDLE,
|
|
'ATTG': cellular.UeGsmDataStatus.ATTACHING,
|
|
'DET': cellular.UeGsmDataStatus.DETACHING,
|
|
'ATT': cellular.UeGsmDataStatus.ATTACHED,
|
|
'STAR': cellular.UeGsmDataStatus.ATTACHING,
|
|
'END': cellular.UeGsmDataStatus.PDP_DEACTIVATING,
|
|
'TRAN': cellular.UeGsmDataStatus.PDP_ACTIVE,
|
|
'PDPAG': cellular.UeGsmDataStatus.PDP_ACTIVATING,
|
|
'PDP': cellular.UeGsmDataStatus.PDP_ACTIVE,
|
|
'PDPD': cellular.UeGsmDataStatus.PDP_DEACTIVATING,
|
|
'DCON': cellular.UeGsmDataStatus.PDP_ACTIVE,
|
|
'SUSP': cellular.UeGsmDataStatus.IDLE,
|
|
}
|
|
|
|
# http://wireless.agilent.com/rfcomms/refdocs/
|
|
# wcdma/wcdma_gen_call_proc_status.html#CJADGAHG
|
|
CALL_STATUS_DATA_TO_STATUS_WCDMA = {
|
|
'IDLE': cellular.UeGsmDataStatus.IDLE,
|
|
'ATTG': cellular.UeGsmDataStatus.ATTACHING,
|
|
'DET': cellular.UeGsmDataStatus.DETACHING,
|
|
'OFF': cellular.UeGsmDataStatus.NONE,
|
|
'PDPAG': cellular.UeGsmDataStatus.PDP_ACTIVATING,
|
|
'PDP': cellular.UeGsmDataStatus.PDP_ACTIVE,
|
|
'PDPD': cellular.UeGsmDataStatus.PDP_DEACTIVATING,
|
|
}
|
|
|
|
# http://wireless.agilent.com/rfcomms/refdocs/
|
|
# cdma2k/cdma2000_hpib_call_status.html#CJABGBCF
|
|
CALL_STATUS_DATA_TO_STATUS_CDMA_2000 = {
|
|
'OFF': cellular.UeC2kDataStatus.OFF,
|
|
'DORM': cellular.UeC2kDataStatus.DORMANT,
|
|
'DCON': cellular.UeC2kDataStatus.DATA_CONNECTED,
|
|
}
|
|
|
|
# http://wireless.agilent.com/rfcomms/refdocs/
|
|
# 1xevdo/1xevdo_hpib_call_status.html#BABCGBCD
|
|
CALL_STATUS_DATA_TO_STATUS_EVDO = {
|
|
'CCL': cellular.UeEvdoDataStatus.CONNECTION_CLOSING,
|
|
'CNEG': cellular.UeEvdoDataStatus.CONNECTION_NEGOTIATE,
|
|
'CREQ': cellular.UeEvdoDataStatus.CONNECTION_REQUEST,
|
|
'DCON': cellular.UeEvdoDataStatus.DATA_CONNECTED,
|
|
'DORM': cellular.UeEvdoDataStatus.DORMANT,
|
|
'HAND': cellular.UeEvdoDataStatus.HANDOFF,
|
|
'IDLE': cellular.UeEvdoDataStatus.IDLE,
|
|
'PAG': cellular.UeEvdoDataStatus.PAGING,
|
|
'SCL': cellular.UeEvdoDataStatus.SESSION_CLOSING,
|
|
'SNEG': cellular.UeEvdoDataStatus.SESSION_NEGOTIATE,
|
|
'SOP': cellular.UeEvdoDataStatus.SESSION_OPEN,
|
|
'UREQ': cellular.UeEvdoDataStatus.UATI_REQUEST,
|
|
}
|
|
|
|
FORMAT_TO_DATA_STATUS_TYPE = {
|
|
'"GSM/GPRS"': CALL_STATUS_DATA_TO_STATUS_GSM_GPRS,
|
|
'"WCDMA"': CALL_STATUS_DATA_TO_STATUS_WCDMA,
|
|
'"IS-2000/IS-95/AMPS"': CALL_STATUS_DATA_TO_STATUS_CDMA_2000,
|
|
'"IS-856"': CALL_STATUS_DATA_TO_STATUS_EVDO,
|
|
}
|