# Copyright (c) 2012 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 dbus import dbus.types import logging import modem import pm_constants import utils from autotest_lib.client.cros.cellular import mm1_constants class ModemCdma(modem.Modem): """ Pseudomodem implementation of the org.freedesktop.ModemManager1.Modem.ModemCdma and org.freedesktop.ModemManager1.Modem.Simple interfaces. This class provides access to specific actions that may be performed in modems with CDMA capabilities. """ class CdmaNetwork(object): """ Stores carrier specific information needed for a CDMA network. """ def __init__(self, sid=99998, nid=0, activated=True, mdn='5555555555', standard='evdo'): self.sid = sid self.nid = nid self.standard = standard self.activated = activated self._mdn = mdn @property def mdn(self): """ @returns: The 'Mobile Directory Number' assigned to this modem by the carrier. If not activated, the first 6 digits will contain '0'. """ if self.activated: return self._mdn return '000000' + self._mdn[6:] def __init__(self, state_machine_factory=None, home_network=CdmaNetwork(), bus=None, device='pseudomodem0', roaming_networks=None, config=None): self.home_network = home_network self.cdma_activate_step = None modem.Modem.__init__(self, state_machine_factory, bus=bus, device=device, roaming_networks=roaming_networks, config=config) def _InitializeProperties(self): ip = modem.Modem._InitializeProperties(self) if self.home_network and self.home_network.activated: activation_state = \ mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED else: activation_state = \ mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED ip[mm1_constants.I_MODEM_CDMA] = { 'Meid' : 'A100000DCE2CA0', 'Esn' : 'EDD1EDD1', 'Sid' : dbus.types.UInt32(0), 'Nid' : dbus.types.UInt32(0), 'Cdma1xRegistrationState' : ( dbus.types.UInt32( mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)), 'EvdoRegistrationState' : ( dbus.types.UInt32( mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)), 'ActivationState' : dbus.types.UInt32(activation_state) } props = ip[mm1_constants.I_MODEM] props['SupportedCapabilities'] = [ dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_CDMA_EVDO) ] props['CurrentCapabilities'] = ( dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_CDMA_EVDO)) props['MaxBearers'] = dbus.types.UInt32(1) props['MaxActiveBearers'] = dbus.types.UInt32(1) props['EquipmentIdentifier'] = ip[mm1_constants.I_MODEM_CDMA]['Meid'] props['AccessTechnologies'] = ( dbus.types.UInt32(mm1_constants.MM_MODEM_ACCESS_TECHNOLOGY_EVDO0)) props['SupportedModes'] = [ dbus.types.Struct( [dbus.types.UInt32(mm1_constants.MM_MODEM_MODE_3G), dbus.types.UInt32(mm1_constants.MM_MODEM_MODE_4G)], signature='uu') ] props['CurrentModes'] = props['SupportedModes'][0] props['SupportedBands'] = [ dbus.types.UInt32( mm1_constants.MM_MODEM_BAND_CDMA_BC0_CELLULAR_800), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC1_PCS_1900), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC2_TACS), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC3_JTACS), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC4_KOREAN_PCS), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC5_NMT450), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC6_IMT2000), dbus.types.UInt32( mm1_constants.MM_MODEM_BAND_CDMA_BC7_CELLULAR_700), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC8_1800), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC9_900), dbus.types.UInt32( mm1_constants.MM_MODEM_BAND_CDMA_BC10_SECONDARY_800), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC11_PAMR_400) ] props['CurrentBands'] = [ dbus.types.UInt32( mm1_constants.MM_MODEM_BAND_CDMA_BC0_CELLULAR_800), dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC1_PCS_1900), ] if self.home_network: props['OwnNumbers'] = [self.home_network.mdn] else: props['OwnNumbers'] = [] return ip @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb') @dbus.service.method(mm1_constants.I_MODEM_CDMA, in_signature='s', async_callbacks=('return_cb', 'raise_cb')) def Activate(self, carrier, return_cb, raise_cb): """ Provisions the modem for use with a given carrier using the modem's OTA activation functionality, if any. @param carrier: Automatic activation code. @param return_cb: Asynchronous success callback. @param raise_cb: Asynchronous failure callback. Has to take an instance of Exception or Error. Emits: ActivationStateChanged """ logging.info('ModemCdma.Activate') machine = self._state_machine_factory.CreateMachine( pm_constants.STATE_MACHINE_CDMA_ACTIVATE, self, return_cb, raise_cb) machine.Start() @utils.log_dbus_method() @dbus.service.method(mm1_constants.I_MODEM_CDMA, in_signature='a{sv}') def ActivateManual(self, properties): """ Sets the modem provisioning data directly, without contacting the carrier over the air. Some modems will reboot after this call is made. @param properties: A dictionary of properties to set on the modem, including "mdn" and "min". Emits: ActivationStateChanged """ raise NotImplementedError() @dbus.service.signal(mm1_constants.I_MODEM_CDMA, signature='uua{sv}') def ActivationStateChanged( self, activation_state, activation_error, status_changes): """ The device activation state changed. @param activation_state: Current activation state, given as a MMModemCdmaActivationState. @param activation_error: Carrier-specific error code, given as a MMCdmaActivationError. @param status_changes: Properties that have changed as a result of this activation state chage, including "mdn" and "min". """ logging.info('ModemCdma: activation state changed: state: %u, error: ' '%u, status_changes: %s', activation_state, activation_error, str(status_changes)) def IsPendingActivation(self): """ @returns: True, if a CdmaActivationMachine is currently active. """ return self.cdma_activate_step and \ not self.cdma_activate_step.cancelled def ChangeActivationState(self, state, error): """ Changes the activation state of this modem to the one provided. If the requested state is MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED and a cdma_activation_machine.CdmaActivationMachine associated with this modem is currently active, then this method won't update the DBus properties until after the modem has reset. @param state: Requested activation state, given as a MMModemCdmaActivationState. @param error: Carrier-specific error code, given as a MMCdmaActivationError. """ status_changes = {} if state == mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED: self.home_network.activated = True status_changes['mdn'] = [self.home_network.mdn] self.Set(mm1_constants.I_MODEM, 'OwnNumbers', status_changes['mdn']) if self.IsPendingActivation(): logging.info("A CdmaActivationMachine is currently active. " "Deferring setting the 'ActivationState' property" " to ACTIVATED until after the reset is " "complete.") return self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'ActivationState', state) self.ActivationStateChanged(state, error, status_changes) def GetHomeNetwork(self): """ @returns: A instance of CdmaNetwork that represents the current home network that is assigned to this modem. """ return self.home_network def SetRegistered(self, network): """ Sets the modem to be registered on the given network. Configures the 'ActivationState', 'Sid', and 'Nid' properties accordingly. @param network: An instance of CdmaNetwork. """ logging.info('ModemCdma.SetRegistered') if network: state = mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_HOME sid = network.sid nid = network.nid if network.activated: activation_state = \ mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED else: activation_state = \ mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED else: state = mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN sid = 0 nid = 0 activation_state = \ mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'ActivationState', activation_state) self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'Sid', sid) self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'Nid', nid) self.SetRegistrationState(state) def SetRegistrationState(self, state): """ Sets the CDMA1x and EVDO registration states to the provided value. @param state: A MMModemCdmaRegistrationState value. """ self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'Cdma1xRegistrationState', state) self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'EvdoRegistrationState', state) # Inherited from modem.Modem. def RegisterWithNetwork( self, operator_id="", return_cb=None, raise_cb=None): """ Overridden from superclass. @param operator_id: See superclass. @param return_cb: See superclass. @param raise_cb: See superclass. """ logging.info('ModemCdma.RegisterWithNetwork') machine = self._state_machine_factory.CreateMachine( pm_constants.STATE_MACHINE_REGISTER_CDMA, self, operator_id, return_cb, raise_cb) machine.Start() def UnregisterWithNetwork(self): """ Overridden from superclass. """ logging.info('ModemCdma.UnregisterWithNetwork') if self.Get(mm1_constants.I_MODEM, 'State') != \ mm1_constants.MM_MODEM_STATE_REGISTERED: logging.info('Currently not registered. Nothing to do.') return logging.info('Setting state to ENABLED.') self.ChangeState(mm1_constants.MM_MODEM_STATE_ENABLED, mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED) logging.info('Unregistering.') self.SetRegistered(None) # Inherited from modem_simple.ModemSimple. @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb') def Connect(self, properties, return_cb, raise_cb): """ Overridden from superclass. @param properties @param return_cb @param raise_cb """ logging.info('ModemCdma.Connect') machine = self._state_machine_factory.CreateMachine( pm_constants.STATE_MACHINE_CONNECT_CDMA, self, properties, return_cb, raise_cb) machine.Start() # Inherited from modem_simple.ModemSimple. @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb') def Disconnect(self, bearer_path, return_cb, raise_cb, *return_cb_args): """ Overridden from superclass. @param bearer_path @param return_cb @param raise_cb @param return_cb_args """ logging.info('ModemCdma.Disconnect: %s', bearer_path) machine = self._state_machine_factory.CreateMachine( pm_constants.STATE_MACHINE_DISCONNECT, self, bearer_path, return_cb, raise_cb, return_cb_args) machine.Start() # Inherited from modem_simple.ModemSimple. @utils.log_dbus_method() def GetStatus(self): """ Overridden from superclass. """ modem_props = self.GetAll(mm1_constants.I_MODEM) cdma_props = self.GetAll(mm1_constants.I_MODEM_CDMA) retval = {} retval['state'] = modem_props['State'] if retval['state'] >= mm1_constants.MM_MODEM_STATE_REGISTERED: retval['signal-quality'] = modem_props['SignalQuality'][0] retval['bands'] = modem_props['CurrentBands'] retval['cdma-cdma1x-registration-state'] = \ cdma_props['Cdma1xRegistrationState'] retval['cdma-evdo-registration-state'] = \ cdma_props['EvdoRegistrationState'] retval['cdma-sid'] = cdma_props['Sid'] retval['cdma-nid'] = cdma_props['Nid'] return retval