| # 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.service |
| import dbus.types |
| import gobject |
| import logging |
| import random |
| |
| import bearer |
| import dbus_std_ifaces |
| import messaging |
| import modem_simple |
| import pm_constants |
| import pm_errors |
| import sms_handler |
| import state_machine_factory as smf |
| import utils |
| |
| import common |
| from autotest_lib.client.cros.cellular import mm1_constants |
| from autotest_lib.client.cros.cellular import net_interface |
| |
| ALLOWED_BEARER_PROPERTIES = [ |
| 'apn', |
| 'operator-id', |
| 'allowed-modes', |
| 'preferred-mode', |
| 'bands', |
| 'ip-type', |
| 'user', |
| 'password', |
| 'allow-roaming', |
| 'rm-protocol', |
| 'number' |
| ] |
| |
| class Modem(dbus_std_ifaces.DBusProperties, |
| modem_simple.ModemSimple, |
| messaging.Messaging): |
| """ |
| Pseudomodem implementation of the org.freedesktop.ModemManager1.Modem |
| interface. This class serves as the abstract base class of all fake modem |
| implementations. |
| |
| """ |
| |
| SUPPORTS_MULTIPLE_OBJECT_PATHS = True |
| |
| def __init__(self, |
| state_machine_factory=None, |
| bus=None, |
| device='pseudomodem0', |
| device_port_type=mm1_constants.MM_MODEM_PORT_TYPE_AT, |
| index=0, |
| roaming_networks=None, |
| config=None): |
| """ |
| Initializes the fake modem object. kwargs can contain the optional |
| argument |config|, which is a dictionary of property-value mappings. |
| These properties will be added to the underlying property dictionary, |
| and must be one of the properties listed in the ModemManager Reference |
| Manual. See _InitializeProperties for all of the properties that belong |
| to this interface. Possible values for each are enumerated in |
| mm1_constants.py. |
| |
| """ |
| if state_machine_factory: |
| self._state_machine_factory = state_machine_factory |
| else: |
| self._state_machine_factory = smf.StateMachineFactory() |
| self.device = device |
| self.device_port_type = device_port_type |
| self.index = index |
| self.sim = None |
| |
| # The superclass construct will call _InitializeProperties |
| dbus_std_ifaces.DBusProperties.__init__(self, |
| mm1_constants.MM1 + '/Modem/' + str(index), bus, config) |
| |
| if roaming_networks is None: |
| roaming_networks = [] |
| self.roaming_networks = roaming_networks |
| |
| self.bearers = {} |
| self.active_bearers = {} |
| self.enable_step = None |
| self.disable_step = None |
| self.connect_step = None |
| self.disconnect_step = None |
| self.register_step = None |
| |
| self._modemmanager = None |
| self.resetting = False |
| |
| self._sms_handler = sms_handler.SmsHandler(self, bus) |
| |
| |
| def _InitializeProperties(self): |
| """ Sets up the default values for the properties. """ |
| props = { |
| 'Manufacturer' : 'Banana Technologies', # be creative here |
| 'Model' : 'Banana Peel 3000', # yep |
| 'Revision' : '1.0', |
| 'DeviceIdentifier' : 'Banana1234567890', |
| 'Device' : self.device, |
| 'Ports': [dbus.types.Struct( |
| [self.device, |
| dbus.types.UInt32(self.device_port_type)], |
| signature='su'), |
| dbus.types.Struct( |
| [net_interface.PseudoNetInterface.IFACE_NAME, |
| dbus.types.UInt32( |
| mm1_constants.MM_MODEM_PORT_TYPE_NET)], |
| signature='su')], |
| 'Drivers' : ['FakeDriver'], |
| 'Plugin' : 'Banana Plugin', |
| 'UnlockRequired' : |
| dbus.types.UInt32(mm1_constants.MM_MODEM_LOCK_NONE), |
| 'UnlockRetries' : dbus.Dictionary(signature='uu'), |
| 'State' : dbus.types.Int32(mm1_constants.MM_MODEM_STATE_DISABLED), |
| 'SignalQuality' : dbus.types.Struct( |
| [dbus.types.UInt32(100), True], |
| signature='ub'), |
| 'OwnNumbers' : ['5555555555'], |
| 'PowerState' : |
| dbus.types.UInt32(mm1_constants.MM_MODEM_POWER_STATE_ON), |
| 'SupportedIpFamilies' : |
| dbus.types.UInt32(mm1_constants.MM_BEARER_IP_FAMILY_ANY), |
| 'Bearers' : dbus.Array([], signature='o'), |
| |
| # specified by subclass: |
| 'SupportedCapabilities' : |
| [dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_NONE)], |
| 'CurrentCapabilities' : |
| dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_NONE), |
| 'MaxBearers' : dbus.types.UInt32(0), |
| 'MaxActiveBearers' : dbus.types.UInt32(0), |
| 'EquipmentIdentifier' : '', |
| 'AccessTechnologies' : |
| dbus.types.UInt32( |
| mm1_constants.MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN), |
| 'SupportedModes' : [ |
| dbus.types.Struct( |
| [dbus.types.UInt32( |
| mm1_constants.MM_MODEM_MODE_NONE), |
| dbus.types.UInt32( |
| mm1_constants.MM_MODEM_MODE_NONE)], |
| signature='uu') |
| ], |
| 'CurrentModes' : |
| dbus.types.Struct( |
| [dbus.types.UInt32( |
| mm1_constants.MM_MODEM_MODE_NONE), |
| dbus.types.UInt32( |
| mm1_constants.MM_MODEM_MODE_NONE)], |
| signature='uu'), |
| 'SupportedBands' : |
| [dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_UNKNOWN)], |
| 'CurrentBands' : |
| [dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_UNKNOWN)], |
| 'Sim' : dbus.types.ObjectPath(mm1_constants.ROOT_PATH) |
| } |
| return { |
| mm1_constants.I_MODEM : props, |
| mm1_constants.I_MODEM_SIMPLE : {} |
| } |
| |
| |
| def IncrementPath(self): |
| """ |
| Increments the current index at which this modem is exposed on DBus. |
| E.g. if the current path is org/freedesktop/ModemManager/Modem/0, the |
| path will change to org/freedesktop/ModemManager/Modem/1. |
| |
| Calling this method does not remove the object from its current path, |
| which means that it will be available via both the old and the new |
| paths. This is currently only used by Reset, in conjunction with |
| dbus_std_ifaces.DBusObjectManager.[Add|Remove]. |
| |
| """ |
| self.index += 1 |
| path = mm1_constants.MM1 + '/Modem/' + str(self.index) |
| logging.info('Modem coming back as: ' + path) |
| self.SetPath(path) |
| |
| |
| @property |
| def manager(self): |
| """ |
| The current modemmanager.ModemManager instance that is managing this |
| modem. |
| |
| @returns: A modemmanager.ModemManager object. |
| |
| """ |
| return self._modemmanager |
| |
| |
| @manager.setter |
| def manager(self, manager): |
| """ |
| Sets the current modemmanager.ModemManager instance that is managing |
| this modem. |
| |
| @param manager: A modemmanager.ModemManager object. |
| |
| """ |
| self._modemmanager = manager |
| |
| |
| @property |
| def sms_handler(self): |
| """ |
| @returns: sms_handler.SmsHandler responsible for handling SMS. |
| |
| """ |
| return self._sms_handler |
| |
| |
| def IsPendingEnable(self): |
| """ |
| @returns: True, if a current enable state machine is active and hasn't |
| been cancelled. |
| |
| """ |
| return self.enable_step and not self.enable_step.cancelled |
| |
| |
| def IsPendingDisable(self): |
| """ |
| @returns: True, if a current disable state machine is active and hasn't |
| been cancelled. |
| |
| """ |
| return self.disable_step and not self.disable_step.cancelled |
| |
| |
| def IsPendingConnect(self): |
| """ |
| @returns: True, if a current connect state machine is active and hasn't |
| been cancelled. |
| |
| """ |
| return self.connect_step and not self.connect_step.cancelled |
| |
| |
| def IsPendingDisconnect(self): |
| """ |
| @returns: True, if a current disconnect state machine is active and |
| hasn't been cancelled. |
| |
| """ |
| return self.disconnect_step and not self.disconnect_step.cancelled |
| |
| |
| def IsPendingRegister(self): |
| """ |
| @returns: True, if a current register state machine is active and hasn't |
| been cancelled. |
| |
| """ |
| return self.register_step and not self.register_step.cancelled |
| |
| |
| def CancelAllStateMachines(self): |
| """ Cancels all state machines that are active. """ |
| if self.IsPendingEnable(): |
| self.enable_step.Cancel() |
| if self.IsPendingDisable(): |
| self.disable_step.Cancel() |
| if self.IsPendingConnect(): |
| self.connect_step.Cancel() |
| if self.IsPendingDisconnect(): |
| self.disconnect_step.Cancel() |
| if self.IsPendingRegister(): |
| self.register_step.Cancel() |
| |
| |
| def SetSignalQuality(self, quality): |
| """ |
| Sets the 'SignalQuality' property to the given value. |
| |
| @param quality: An integer value in the range 0-100. |
| Emits: |
| PropertiesChanged |
| |
| """ |
| self.Set(mm1_constants.I_MODEM, 'SignalQuality', (dbus.types.Struct( |
| [dbus.types.UInt32(quality), True], signature='ub'))) |
| |
| |
| def ChangeState(self, state, reason): |
| """ |
| Changes the modem state and emits the StateChanged signal. |
| |
| @param state: A MMModemState value. |
| @param reason: A MMModemStateChangeReason value. |
| Emits: |
| PropertiesChanged |
| StateChanged |
| |
| """ |
| old_state = self.Get(mm1_constants.I_MODEM, 'State') |
| self.SetInt32(mm1_constants.I_MODEM, 'State', state) |
| self.StateChanged(old_state, state, dbus.types.UInt32(reason)) |
| |
| |
| def SetSIM(self, sim): |
| """ |
| Assigns a SIM object to this Modem. It exposes the SIM object via DBus |
| and sets 'Sim' property of this Modem to the path of the SIM. |
| |
| @param sim: An instance of sim.SIM. |
| Emits: |
| PropertiesChanged |
| |
| """ |
| self.sim = sim |
| if not sim: |
| val = mm1_constants.ROOT_PATH |
| else: |
| val = sim.path |
| self.sim.SetBus(self.bus) |
| self.sim.modem = self |
| self.UpdateLockStatus() |
| self.Set(mm1_constants.I_MODEM, 'Sim', dbus.types.ObjectPath(val)) |
| |
| |
| def SetBus(self, bus): |
| """ |
| Overridden from dbus_std_ifaces.DBusProperties. |
| |
| @param bus |
| |
| """ |
| dbus_std_ifaces.DBusProperties.SetBus(self, bus) |
| self._state_machine_factory.SetBus(bus) |
| self._sms_handler.bus = bus |
| |
| |
| def UpdateLockStatus(self): |
| """ |
| Tells the modem to update the current lock status. This method will |
| update the modem state and the relevant modem properties. |
| |
| """ |
| if not self.sim: |
| logging.info('SIM lock is the only kind of lock that is currently ' |
| 'supported. No SIM present, nothing to do.') |
| return |
| self.SetUInt32(mm1_constants.I_MODEM, 'UnlockRequired', |
| self.sim.lock_type) |
| self.Set(mm1_constants.I_MODEM, 'UnlockRetries', |
| self.sim.unlock_retries) |
| if self.sim.locked: |
| def _SetLocked(): |
| logging.info('There is a SIM lock in place. Setting state to ' |
| 'LOCKED') |
| self.ChangeState( |
| mm1_constants.MM_MODEM_STATE_LOCKED, |
| mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN) |
| |
| # If the modem is currently in an enabled state, disable it before |
| # setting the modem state to LOCKED. |
| if (self.Get(mm1_constants.I_MODEM, 'State') >= |
| mm1_constants.MM_MODEM_STATE_ENABLED): |
| logging.info('SIM got locked. Disabling modem.') |
| self.Enable(False, return_cb=_SetLocked) |
| else: |
| _SetLocked() |
| elif (self.Get(mm1_constants.I_MODEM, 'State') == |
| mm1_constants.MM_MODEM_STATE_LOCKED): |
| # Change the state to DISABLED. Shill will see the property change |
| # and automatically attempt to enable the modem. |
| logging.info('SIM became unlocked! Setting state to INITIALIZING.') |
| self.ChangeState(mm1_constants.MM_MODEM_STATE_INITIALIZING, |
| mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN) |
| logging.info('SIM became unlocked! Setting state to DISABLED.') |
| self.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLED, |
| mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN) |
| |
| |
| @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb') |
| @dbus.service.method(mm1_constants.I_MODEM, |
| in_signature='b', async_callbacks=('return_cb', |
| 'raise_cb')) |
| def Enable(self, enable, return_cb=None, raise_cb=None): |
| """ |
| Enables or disables the modem. |
| |
| When enabled, the modem's radio is powered on and data sessions, voice |
| calls, location services, and Short Message Service may be available. |
| |
| When disabled, the modem enters low-power state and no network-related |
| operations are available. |
| |
| @param enable: True to enable the modem and False to disable it. |
| @param return_cb: The asynchronous callback to invoke on success. |
| @param raise_cb: The asynchronous callback to invoke on failure. Has to |
| take a python Exception or Error as its single argument. |
| |
| """ |
| if enable: |
| logging.info('Modem enable') |
| machine = self._state_machine_factory.CreateMachine( |
| pm_constants.STATE_MACHINE_ENABLE, |
| self, |
| return_cb, |
| raise_cb) |
| else: |
| logging.info('Modem disable') |
| machine = self._state_machine_factory.CreateMachine( |
| pm_constants.STATE_MACHINE_DISABLE, |
| self, |
| return_cb, |
| raise_cb) |
| machine.Start() |
| |
| |
| def RegisterWithNetwork( |
| self, operator_id="", return_cb=None, raise_cb=None): |
| """ |
| Register with the network specified by the given |operator_id|. |
| |operator_id| should be an MCCMNC value (for 3GPP) or an empty string. |
| An implementation of this method must set the state to SEARCHING first, |
| and eventually to REGISTERED, also setting technology specific |
| registration state properties. Technology specific error cases need to |
| be handled here (such as activation, the presence of a valid SIM card, |
| etc). |
| |
| Must be implemented by a subclass. |
| |
| @param operator_id: String containing the operator code. This method |
| will typically initiate a network scan, yielding a list of |
| networks. If |operator_id| is non-empty, the modem will register |
| with the network in the scanned list that matches |operator_id|. |
| An empty |operator_id| means that registration should be |
| "automatic". In this case the implementation would typically |
| register with the home network. If a home network is not |
| available than any network that is returned by a network scan |
| can be registered with. |
| |
| Note: CDMA doesn't support a network scan. In this case, the |
| only possible option is to register with the home network and |
| ignore the value of |operator_id|. |
| @param return_cb: Async success callback. |
| @param raise_cb: Async failure callback. |
| |
| """ |
| raise NotImplementedError() |
| |
| |
| def UnregisterWithNetwork(self): |
| """ |
| Unregisters with the currently registered network. This should |
| transition the modem to the ENABLED state. |
| |
| Must be implemented by a subclass. |
| |
| """ |
| raise NotImplementedError() |
| |
| |
| def ValidateBearerProperties(self, properties): |
| """ |
| The default implementation makes sure that all keys in properties are |
| one of the allowed bearer properties. Subclasses can override this |
| method to provide CDMA/3GPP specific checks. |
| |
| @param properties: The dictionary of properties and values to validate. |
| @raises: MMCoreError, if one or more properties are invalid. |
| |
| """ |
| for key in properties.iterkeys(): |
| if key not in ALLOWED_BEARER_PROPERTIES: |
| raise pm_errors.MMCoreError( |
| pm_errors.MMCoreError.INVALID_ARGS, |
| 'Invalid property "%s", not creating bearer.' % key) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, out_signature='ao') |
| def ListBearers(self): |
| """ |
| Lists configured packet data bearers (EPS Bearers, PDP Contexts, or |
| CDMA2000 Packet Data Sessions). |
| |
| @returns: A list of bearer object paths. |
| |
| """ |
| return self.Get(mm1_constants.I_MODEM, 'Bearers') |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='a{sv}', |
| out_signature='o') |
| def CreateBearer(self, properties): |
| """ |
| Creates a new packet data bearer using the given characteristics. |
| |
| This request may fail if the modem does not support additional bearers, |
| if too many bearers are already defined, or if properties are invalid. |
| |
| @param properties: A dictionary containing the properties to assign to |
| the bearer after creating it. The allowed property values are |
| contained in modem.ALLOWED_PROPERTIES. |
| @returns: On success, the object path of the newly created bearer. |
| |
| """ |
| logging.info('CreateBearer') |
| maxbearers = self.Get(mm1_constants.I_MODEM, 'MaxBearers') |
| if len(self.bearers) == maxbearers: |
| raise pm_errors.MMCoreError( |
| pm_errors.MMCoreError.TOO_MANY, |
| ('Maximum number of bearers reached. Cannot create new ' |
| 'bearer.')) |
| else: |
| self.ValidateBearerProperties(properties) |
| bearer_obj = bearer.Bearer(self.bus, properties) |
| logging.info('Created bearer with path "%s".', bearer_obj.path) |
| self.bearers[bearer_obj.path] = bearer_obj |
| self._UpdateBearersProperty() |
| return bearer_obj.path |
| |
| |
| def ActivateBearer(self, bearer_path): |
| """ |
| Activates a data bearer by setting its 'Connected' property to True. |
| |
| This request may fail if the modem does not support additional active |
| bearers, if too many bearers are already active, if the requested |
| bearer doesn't exist, or if the requested bearer is already active. |
| |
| @param bearer_path: DBus path of the bearer to activate. |
| |
| """ |
| logging.info('ActivateBearer: %s', bearer_path) |
| bearer = self.bearers.get(bearer_path, None) |
| if bearer is None: |
| message = 'Could not find bearer with path "%s"' % bearer_path |
| logging.info(message) |
| raise pm_errors.MMCoreError(pm_errors.MMCoreError.NOT_FOUND, |
| message) |
| |
| max_active_bearers = self.Get(mm1_constants.I_MODEM, 'MaxActiveBearers') |
| if len(self.active_bearers) >= max_active_bearers: |
| message = ('Cannot activate bearer: maximum active bearer count ' |
| 'reached.') |
| logging.info(message) |
| raise pm_errors.MMCoreError(pm_errors.MMCoreError.TOO_MANY, message) |
| if bearer.IsActive(): |
| message = 'Bearer with path "%s" already active.', bearer_path |
| logging.info(message) |
| raise pm_errors.MMCoreError(pm_errors.MMCoreError.CONNECTED, |
| message) |
| |
| self.active_bearers[bearer_path] = bearer |
| bearer.Connect() |
| |
| |
| def DeactivateBearer(self, bearer_path): |
| """ |
| Deactivates data bearer by setting its 'Connected' property to False. |
| |
| This request may fail if the modem with the requested path doesn't |
| exist, or if the bearer is not active. |
| |
| @param bearer_path: DBus path of the bearer to activate. |
| |
| """ |
| logging.info('DeactivateBearer: %s', bearer_path) |
| bearer = self.bearers.get(bearer_path, None) |
| if bearer is None: |
| raise pm_errors.MMCoreError( |
| pm_errors.MMCoreError.NOT_FOUND, |
| 'Could not find bearer with path "%s".' % bearer_path) |
| if not bearer.IsActive(): |
| assert bearer_path not in self.active_bearers |
| raise pm_errors.MMCoreError( |
| pm_errors.MMCoreError.WRONG_STATE, |
| 'Bearer with path "%s" is not active.' % bearer_path) |
| assert bearer_path in self.active_bearers |
| bearer.Disconnect() |
| self.active_bearers.pop(bearer_path) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='o') |
| def DeleteBearer(self, bearer): |
| """ |
| Deletes an existing packet data bearer. |
| |
| If the bearer is currently active, it will be deactivated. |
| |
| @param bearer: Object path of the bearer to delete. |
| |
| """ |
| logging.info('Modem.DeleteBearer: ' + str(bearer)) |
| if not bearer in self.bearers: |
| logging.info('Unknown bearer. Nothing to do.') |
| return |
| bearer_object = self.bearers[bearer] |
| bearer_object.remove_from_connection() |
| self.bearers.pop(bearer) |
| self._UpdateBearersProperty() |
| if bearer in self.active_bearers: |
| self.active_bearers.pop(bearer) |
| |
| |
| def ClearBearers(self): |
| """ Deletes all bearers that are managed by this modem. """ |
| for b in self.bearers.keys(): |
| self.DeleteBearer(b) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM) |
| def Reset(self): |
| """ |
| Clears non-persistent configuration and state, and returns the device to |
| a newly-powered-on state. |
| |
| As a result of this operation, the modem will be removed from its |
| current path and will be exposed on an incremented path. It will be |
| enabled afterwards. |
| |
| """ |
| logging.info('Resetting modem.') |
| |
| if self.resetting: |
| raise pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS, |
| 'Reset already in progress.') |
| |
| self.resetting = True |
| |
| self.CancelAllStateMachines() |
| |
| def _ResetFunc(): |
| # Disappear. |
| manager = self.manager |
| if manager: |
| manager.Remove(self) |
| if self.sim: |
| manager.Remove(self.sim) |
| |
| self.ClearBearers() |
| |
| # Reappear. |
| def _DelayedReappear(): |
| self.IncrementPath() |
| |
| # Reset to defaults. |
| if self.sim: |
| self.sim.Reset() |
| self._properties = self._InitializeProperties() |
| if self.sim: |
| self.Set(mm1_constants.I_MODEM, |
| 'Sim', |
| dbus.types.ObjectPath(self.sim.path)) |
| self.UpdateLockStatus() |
| |
| if manager: |
| manager.Add(self) |
| |
| self.resetting = False |
| |
| def _DelayedEnable(): |
| state = self.Get(mm1_constants.I_MODEM, 'State') |
| if not self.IsPendingEnable() and \ |
| state == mm1_constants.MM_MODEM_STATE_DISABLED: |
| self.Enable(True) |
| return False |
| |
| gobject.timeout_add(1000, _DelayedEnable) |
| return False |
| |
| gobject.timeout_add(2000, _DelayedReappear) |
| |
| def _ErrorCallback(error): |
| raise error |
| |
| if (self.Get(mm1_constants.I_MODEM, 'State') == |
| mm1_constants.MM_MODEM_STATE_CONNECTED): |
| self.Disconnect('/', _ResetFunc, _ErrorCallback) |
| else: |
| gobject.idle_add(_ResetFunc) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='s') |
| def FactoryReset(self, code): |
| """ |
| Clears the modem's configuration (including persistent configuration and |
| state), and returns the device to a factory-default state. |
| |
| If not required by the modem, code may be ignored. |
| |
| This command may or may not power-cycle the device. |
| |
| @param code: Carrier specific activation code. |
| |
| """ |
| raise NotImplementedError() |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='(uu)') |
| def SetCurrentModes(self, modes): |
| """ |
| Sets the access technologies (eg 2G/3G/4G preference) the device is |
| currently allowed to use when connecting to a network. |
| |
| @param modes: Specifies all the modes allowed in the modem as a bitmask |
| of MMModemModem values. |
| @param preferred: Specific MMModemMode preferred among the ones allowed, |
| if any. |
| |
| """ |
| allowed = self.Get(mm1_constants.I_MODEM, 'SupportedModes') |
| if not modes in allowed: |
| raise pm_errors.MMCoreError(pm_errors.MMCoreError.FAILED, |
| 'Mode not supported: ' + repr(modes)) |
| self.Set(mm1_constants.I_MODEM, 'CurrentModes', modes) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='au') |
| def SetCurrentBands(self, bands): |
| """ |
| Sets the radio frequency and technology bands the device is currently |
| allowed to use when connecting to a network. |
| |
| @param bands: Specifies the bands to be used as a list of MMModemBand |
| values. |
| |
| """ |
| band_list = [dbus.types.UInt32(band) for band in bands] |
| self.Set(mm1_constants.I_MODEM, 'CurrentBands', band_list) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='su', |
| out_signature='s') |
| def Command(self, cmd, timeout): |
| """ |
| Allows clients to send commands to the modem. By default, this method |
| does nothing, but responds by telling the client's fortune to brighten |
| the client's day. |
| |
| @param cmd: Command to send to the modem. |
| @param timeout: The timeout interval for the command. |
| @returns: A string containing the response from the modem. |
| |
| """ |
| messages = ['Bananas are tasty and fresh. Have one!', |
| 'A soft voice may be awfully persuasive.', |
| 'Be careful or you could fall for some tricks today.', |
| 'Believe in yourself and others will too.', |
| 'Carve your name on your heart and not on marble.'] |
| return random.choice(messages) |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='u') |
| def SetPowerState(self, power_state): |
| """ |
| Sets the power state of the modem. This action can only be run when the |
| modem is in the MM_MODEM_STATE_DISABLED state. |
| |
| @param power_state: Specifies the desired power state as a |
| MMModemPowerState value. |
| @raises: MMCoreError if state is not DISABLED. |
| |
| """ |
| if (self.Get(mm1_constants.I_MODEM, 'State') != |
| mm1_constants.MM_MODEM_STATE_DISABLED): |
| raise pm_errors.MMCoreError( |
| pm_errors.MMCoreError.WRONG_STATE, |
| 'Cannot set the power state if modem is not DISABLED.') |
| self.SetUInt32(mm1_constants.I_MODEM, 'PowerState', power_state); |
| |
| |
| @utils.log_dbus_method() |
| @dbus.service.method(mm1_constants.I_MODEM, in_signature='u') |
| def SetCurrentCapabilities(self, capabilities): |
| """ |
| Set the capabilities of the device. A restart of the modem may be |
| required. |
| |
| @param capabilities: Bitmask of MMModemCapability values, to specify the |
| capabilities to use. |
| |
| """ |
| supported = self.Get(mm1_constants.I_MODEM, 'SupportedCapabilities') |
| if not capabilities in supported: |
| raise pm_errors.MMCoreError( |
| pm_errors.MMCoreError.FAILED, |
| 'Given capabilities not supported: ' + capabilities) |
| self.SetUInt32(mm1_constants.I_MODEM, 'CurrentCapabilities', |
| capabilities) |
| |
| |
| @dbus.service.signal(mm1_constants.I_MODEM, signature='iiu') |
| def StateChanged(self, old, new, reason): |
| """ |
| Signals that the modem's 'State' property has changed. |
| |
| @param old: Specifies the old state, as a MMModemState value. |
| @param new: Specifies the new state, as a MMModemState value. |
| @param reason: Specifies the reason for this state change as a |
| MMModemStateChangeReason value. |
| |
| """ |
| logging.info('Modem state changed from %u to %u for reason %u', |
| old, new, reason) |
| |
| |
| # org.freedesktop.ModemManager1.Messaging |
| |
| def List(self): |
| """ |
| Overriden from messaging.Messaging. |
| |
| """ |
| return self._sms_handler.list_messages() |
| |
| |
| def Delete(self, path): |
| """ |
| Overriden from messaging.Messaging. |
| |
| @param path |
| |
| """ |
| self._sms_handler.delete_message(path) |
| |
| |
| @dbus.service.signal(mm1_constants.I_MODEM_MESSAGING, signature='ob') |
| def Added(self, path, received): |
| """ |
| Overriden from messaging.Messaging. |
| |
| @param path |
| @param received |
| |
| """ |
| logging.info('New SMS added: path: ' + path + ' received: ' + |
| str(received)) |
| |
| |
| def _UpdateBearersProperty(self): |
| """ |
| Update the 'Bearers' property on |I_MODEM| interface to match the |
| internal list. |
| |
| """ |
| bearers = dbus.Array( |
| [dbus.types.ObjectPath(key) for key in self.bearers.iterkeys()], |
| signature='o') |
| self.Set(mm1_constants.I_MODEM, 'Bearers', bearers) |