Home | History | Annotate | Download | only in pseudomodem
      1 # Copyright (c) 2012 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 dbus
      6 import dbus.types
      7 import logging
      8 
      9 import modem
     10 import pm_constants
     11 import utils
     12 
     13 from autotest_lib.client.cros.cellular import mm1_constants
     14 
     15 class ModemCdma(modem.Modem):
     16     """
     17     Pseudomodem implementation of the
     18     org.freedesktop.ModemManager1.Modem.ModemCdma and
     19     org.freedesktop.ModemManager1.Modem.Simple interfaces. This class provides
     20     access to specific actions that may be performed in modems with CDMA
     21     capabilities.
     22 
     23     """
     24 
     25     class CdmaNetwork(object):
     26         """
     27         Stores carrier specific information needed for a CDMA network.
     28 
     29         """
     30         def __init__(self,
     31                      sid=99998,
     32                      nid=0,
     33                      activated=True,
     34                      mdn='5555555555',
     35                      standard='evdo'):
     36             self.sid = sid
     37             self.nid = nid
     38             self.standard = standard
     39             self.activated = activated
     40             self._mdn = mdn
     41 
     42 
     43         @property
     44         def mdn(self):
     45             """
     46             @returns: The 'Mobile Directory Number' assigned to this modem by
     47                     the carrier. If not activated, the first 6 digits will
     48                     contain '0'.
     49 
     50             """
     51             if self.activated:
     52                 return self._mdn
     53             return '000000' + self._mdn[6:]
     54 
     55 
     56     def __init__(self,
     57                  state_machine_factory=None,
     58                  home_network=CdmaNetwork(),
     59                  bus=None,
     60                  device='pseudomodem0',
     61                  roaming_networks=None,
     62                  config=None):
     63         self.home_network = home_network
     64         self.cdma_activate_step = None
     65         modem.Modem.__init__(self,
     66                              state_machine_factory,
     67                              bus=bus,
     68                              device=device,
     69                              roaming_networks=roaming_networks,
     70                              config=config)
     71 
     72 
     73     def _InitializeProperties(self):
     74         ip = modem.Modem._InitializeProperties(self)
     75         if self.home_network and self.home_network.activated:
     76             activation_state = \
     77                 mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED
     78         else:
     79             activation_state = \
     80                 mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED
     81         ip[mm1_constants.I_MODEM_CDMA] = {
     82             'Meid' : 'A100000DCE2CA0',
     83             'Esn' : 'EDD1EDD1',
     84             'Sid' : dbus.types.UInt32(0),
     85             'Nid' : dbus.types.UInt32(0),
     86             'Cdma1xRegistrationState' : (
     87             dbus.types.UInt32(
     88                 mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)),
     89             'EvdoRegistrationState' : (
     90             dbus.types.UInt32(
     91                 mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)),
     92             'ActivationState' : dbus.types.UInt32(activation_state)
     93         }
     94         props = ip[mm1_constants.I_MODEM]
     95         props['SupportedCapabilities'] = [
     96             dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_CDMA_EVDO)
     97         ]
     98         props['CurrentCapabilities'] = (
     99             dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_CDMA_EVDO))
    100         props['MaxBearers'] = dbus.types.UInt32(1)
    101         props['MaxActiveBearers'] = dbus.types.UInt32(1)
    102         props['EquipmentIdentifier'] = ip[mm1_constants.I_MODEM_CDMA]['Meid']
    103         props['AccessTechnologies'] = (
    104             dbus.types.UInt32(mm1_constants.MM_MODEM_ACCESS_TECHNOLOGY_EVDO0))
    105         props['SupportedModes'] = [
    106             dbus.types.Struct(
    107                 [dbus.types.UInt32(mm1_constants.MM_MODEM_MODE_3G),
    108                  dbus.types.UInt32(mm1_constants.MM_MODEM_MODE_4G)],
    109                 signature='uu')
    110         ]
    111         props['CurrentModes'] = props['SupportedModes'][0]
    112         props['SupportedBands'] = [
    113             dbus.types.UInt32(
    114                 mm1_constants.MM_MODEM_BAND_CDMA_BC0_CELLULAR_800),
    115             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC1_PCS_1900),
    116             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC2_TACS),
    117             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC3_JTACS),
    118             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC4_KOREAN_PCS),
    119             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC5_NMT450),
    120             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC6_IMT2000),
    121             dbus.types.UInt32(
    122                 mm1_constants.MM_MODEM_BAND_CDMA_BC7_CELLULAR_700),
    123             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC8_1800),
    124             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC9_900),
    125             dbus.types.UInt32(
    126                 mm1_constants.MM_MODEM_BAND_CDMA_BC10_SECONDARY_800),
    127             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC11_PAMR_400)
    128         ]
    129         props['CurrentBands'] = [
    130             dbus.types.UInt32(
    131                 mm1_constants.MM_MODEM_BAND_CDMA_BC0_CELLULAR_800),
    132             dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_CDMA_BC1_PCS_1900),
    133         ]
    134         if self.home_network:
    135             props['OwnNumbers'] = [self.home_network.mdn]
    136         else:
    137             props['OwnNumbers'] = []
    138 
    139         return ip
    140 
    141 
    142     @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb')
    143     @dbus.service.method(mm1_constants.I_MODEM_CDMA, in_signature='s',
    144                          async_callbacks=('return_cb', 'raise_cb'))
    145     def Activate(self, carrier, return_cb, raise_cb):
    146         """
    147         Provisions the modem for use with a given carrier using the modem's
    148         OTA activation functionality, if any.
    149 
    150         @param carrier: Automatic activation code.
    151         @param return_cb: Asynchronous success callback.
    152         @param raise_cb: Asynchronous failure callback. Has to take an instance
    153                          of Exception or Error.
    154         Emits:
    155             ActivationStateChanged
    156 
    157         """
    158         logging.info('ModemCdma.Activate')
    159         machine = self._state_machine_factory.CreateMachine(
    160                 pm_constants.STATE_MACHINE_CDMA_ACTIVATE,
    161                 self,
    162                 return_cb,
    163                 raise_cb)
    164         machine.Start()
    165 
    166 
    167     @utils.log_dbus_method()
    168     @dbus.service.method(mm1_constants.I_MODEM_CDMA, in_signature='a{sv}')
    169     def ActivateManual(self, properties):
    170         """
    171         Sets the modem provisioning data directly, without contacting the
    172         carrier over the air. Some modems will reboot after this call is made.
    173 
    174         @param properties: A dictionary of properties to set on the modem,
    175                            including "mdn" and "min".
    176         Emits:
    177             ActivationStateChanged
    178 
    179         """
    180         raise NotImplementedError()
    181 
    182 
    183     @dbus.service.signal(mm1_constants.I_MODEM_CDMA, signature='uua{sv}')
    184     def ActivationStateChanged(
    185             self,
    186             activation_state,
    187             activation_error,
    188             status_changes):
    189         """
    190         The device activation state changed.
    191 
    192         @param activation_state: Current activation state, given as a
    193                 MMModemCdmaActivationState.
    194         @param activation_error: Carrier-specific error code, given as a
    195                 MMCdmaActivationError.
    196         @param status_changes: Properties that have changed as a result of this
    197                 activation state chage, including "mdn" and "min".
    198 
    199         """
    200         logging.info('ModemCdma: activation state changed: state: %u, error: '
    201                      '%u, status_changes: %s',
    202                      activation_state,
    203                      activation_error,
    204                      str(status_changes))
    205 
    206 
    207     def IsPendingActivation(self):
    208         """
    209         @returns: True, if a CdmaActivationMachine is currently active.
    210 
    211         """
    212         return self.cdma_activate_step and \
    213             not self.cdma_activate_step.cancelled
    214 
    215 
    216     def ChangeActivationState(self, state, error):
    217         """
    218         Changes the activation state of this modem to the one provided.
    219 
    220         If the requested state is MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED and
    221         a cdma_activation_machine.CdmaActivationMachine associated with this
    222         modem is currently active, then this method won't update the DBus
    223         properties until after the modem has reset.
    224 
    225         @param state: Requested activation state, given as a
    226                 MMModemCdmaActivationState.
    227         @param error: Carrier-specific error code, given as a
    228                 MMCdmaActivationError.
    229 
    230         """
    231         status_changes = {}
    232         if state == mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
    233             self.home_network.activated = True
    234             status_changes['mdn'] = [self.home_network.mdn]
    235             self.Set(mm1_constants.I_MODEM, 'OwnNumbers', status_changes['mdn'])
    236 
    237             if self.IsPendingActivation():
    238                 logging.info("A CdmaActivationMachine is currently active. "
    239                              "Deferring setting the 'ActivationState' property"
    240                              " to ACTIVATED until after the reset is "
    241                              "complete.")
    242                 return
    243 
    244         self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'ActivationState', state)
    245         self.ActivationStateChanged(state, error, status_changes)
    246 
    247 
    248     def GetHomeNetwork(self):
    249         """
    250         @returns: A instance of CdmaNetwork that represents the
    251                 current home network that is assigned to this modem.
    252 
    253         """
    254         return self.home_network
    255 
    256 
    257     def SetRegistered(self, network):
    258         """
    259         Sets the modem to be registered on the given network. Configures the
    260         'ActivationState', 'Sid', and 'Nid' properties accordingly.
    261 
    262         @param network: An instance of CdmaNetwork.
    263 
    264         """
    265         logging.info('ModemCdma.SetRegistered')
    266         if network:
    267             state = mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_HOME
    268             sid = network.sid
    269             nid = network.nid
    270             if network.activated:
    271                 activation_state = \
    272                     mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED
    273             else:
    274                 activation_state = \
    275                     mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED
    276         else:
    277             state = mm1_constants.MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
    278             sid = 0
    279             nid = 0
    280             activation_state = \
    281                 mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED
    282         self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'ActivationState',
    283                        activation_state)
    284         self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'Sid', sid)
    285         self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'Nid', nid)
    286         self.SetRegistrationState(state)
    287 
    288 
    289     def SetRegistrationState(self, state):
    290         """
    291         Sets the CDMA1x and EVDO registration states to the provided value.
    292 
    293         @param state: A MMModemCdmaRegistrationState value.
    294 
    295         """
    296         self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'Cdma1xRegistrationState',
    297                        state)
    298         self.SetUInt32(mm1_constants.I_MODEM_CDMA, 'EvdoRegistrationState',
    299                        state)
    300 
    301 
    302     # Inherited from modem.Modem.
    303     def RegisterWithNetwork(
    304             self, operator_id="", return_cb=None, raise_cb=None):
    305         """ Overridden from superclass.
    306 
    307         @param operator_id: See superclass.
    308         @param return_cb: See superclass.
    309         @param raise_cb: See superclass.
    310 
    311         """
    312         logging.info('ModemCdma.RegisterWithNetwork')
    313         machine = self._state_machine_factory.CreateMachine(
    314                 pm_constants.STATE_MACHINE_REGISTER_CDMA,
    315                 self,
    316                 operator_id,
    317                 return_cb,
    318                 raise_cb)
    319         machine.Start()
    320 
    321 
    322     def UnregisterWithNetwork(self):
    323         """ Overridden from superclass. """
    324         logging.info('ModemCdma.UnregisterWithNetwork')
    325         if self.Get(mm1_constants.I_MODEM, 'State') != \
    326             mm1_constants.MM_MODEM_STATE_REGISTERED:
    327             logging.info('Currently not registered. Nothing to do.')
    328             return
    329         logging.info('Setting state to ENABLED.')
    330         self.ChangeState(mm1_constants.MM_MODEM_STATE_ENABLED,
    331             mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED)
    332         logging.info('Unregistering.')
    333         self.SetRegistered(None)
    334 
    335 
    336     # Inherited from modem_simple.ModemSimple.
    337     @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb')
    338     def Connect(self, properties, return_cb, raise_cb):
    339         """
    340         Overridden from superclass.
    341 
    342         @param properties
    343         @param return_cb
    344         @param raise_cb
    345 
    346         """
    347         logging.info('ModemCdma.Connect')
    348         machine = self._state_machine_factory.CreateMachine(
    349                 pm_constants.STATE_MACHINE_CONNECT_CDMA,
    350                 self,
    351                 properties,
    352                 return_cb,
    353                 raise_cb)
    354         machine.Start()
    355 
    356 
    357     # Inherited from modem_simple.ModemSimple.
    358     @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb')
    359     def Disconnect(self, bearer_path, return_cb, raise_cb, *return_cb_args):
    360         """
    361         Overridden from superclass.
    362 
    363         @param bearer_path
    364         @param return_cb
    365         @param raise_cb
    366         @param return_cb_args
    367 
    368         """
    369         logging.info('ModemCdma.Disconnect: %s', bearer_path)
    370         machine = self._state_machine_factory.CreateMachine(
    371                 pm_constants.STATE_MACHINE_DISCONNECT,
    372                 self,
    373                 bearer_path,
    374                 return_cb,
    375                 raise_cb,
    376                 return_cb_args)
    377         machine.Start()
    378 
    379 
    380     # Inherited from modem_simple.ModemSimple.
    381     @utils.log_dbus_method()
    382     def GetStatus(self):
    383         """ Overridden from superclass. """
    384         modem_props = self.GetAll(mm1_constants.I_MODEM)
    385         cdma_props = self.GetAll(mm1_constants.I_MODEM_CDMA)
    386         retval = {}
    387         retval['state'] = modem_props['State']
    388         if retval['state'] >= mm1_constants.MM_MODEM_STATE_REGISTERED:
    389             retval['signal-quality'] = modem_props['SignalQuality'][0]
    390             retval['bands'] = modem_props['CurrentBands']
    391             retval['cdma-cdma1x-registration-state'] = \
    392                 cdma_props['Cdma1xRegistrationState']
    393             retval['cdma-evdo-registration-state'] = \
    394                 cdma_props['EvdoRegistrationState']
    395             retval['cdma-sid'] = cdma_props['Sid']
    396             retval['cdma-nid'] = cdma_props['Nid']
    397         return retval
    398