xref: /aosp_15_r20/external/autotest/client/cros/cellular/pseudomodem/modem.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Lifrom __future__ import absolute_import
7*9c5db199SXin Lifrom __future__ import division
8*9c5db199SXin Lifrom __future__ import print_function
9*9c5db199SXin Li
10*9c5db199SXin Liimport dbus
11*9c5db199SXin Liimport dbus.service
12*9c5db199SXin Liimport dbus.types
13*9c5db199SXin Li# AU tests use ToT client code, but ToT -3 client version.
14*9c5db199SXin Litry:
15*9c5db199SXin Li    from gi.repository import GObject
16*9c5db199SXin Liexcept ImportError:
17*9c5db199SXin Li    import gobject as GObject
18*9c5db199SXin Liimport logging
19*9c5db199SXin Liimport random
20*9c5db199SXin Li
21*9c5db199SXin Liimport six
22*9c5db199SXin Li
23*9c5db199SXin Liimport common
24*9c5db199SXin Li
25*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import bearer
26*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import dbus_std_ifaces
27*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import messaging
28*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import modem_simple
29*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import pm_constants
30*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import pm_errors
31*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import sms_handler
32*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import state_machine_factory as smf
33*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import utils
34*9c5db199SXin Li
35*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import mm1_constants
36*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import net_interface
37*9c5db199SXin Li
38*9c5db199SXin LiALLOWED_BEARER_PROPERTIES = [
39*9c5db199SXin Li    'apn',
40*9c5db199SXin Li    'operator-id',
41*9c5db199SXin Li    'allowed-modes',
42*9c5db199SXin Li    'preferred-mode',
43*9c5db199SXin Li    'bands',
44*9c5db199SXin Li    'ip-type',
45*9c5db199SXin Li    'user',
46*9c5db199SXin Li    'password',
47*9c5db199SXin Li    'allow-roaming',
48*9c5db199SXin Li    'rm-protocol',
49*9c5db199SXin Li    'number'
50*9c5db199SXin Li]
51*9c5db199SXin Li
52*9c5db199SXin Liclass Modem(dbus_std_ifaces.DBusProperties,
53*9c5db199SXin Li            modem_simple.ModemSimple,
54*9c5db199SXin Li            messaging.Messaging):
55*9c5db199SXin Li    """
56*9c5db199SXin Li    Pseudomodem implementation of the org.freedesktop.ModemManager1.Modem
57*9c5db199SXin Li    interface. This class serves as the abstract base class of all fake modem
58*9c5db199SXin Li    implementations.
59*9c5db199SXin Li
60*9c5db199SXin Li    """
61*9c5db199SXin Li
62*9c5db199SXin Li    SUPPORTS_MULTIPLE_OBJECT_PATHS = True
63*9c5db199SXin Li
64*9c5db199SXin Li    def __init__(self,
65*9c5db199SXin Li                 state_machine_factory=None,
66*9c5db199SXin Li                 bus=None,
67*9c5db199SXin Li                 device='pseudomodem0',
68*9c5db199SXin Li                 device_port_type=mm1_constants.MM_MODEM_PORT_TYPE_AT,
69*9c5db199SXin Li                 index=0,
70*9c5db199SXin Li                 roaming_networks=None,
71*9c5db199SXin Li                 config=None):
72*9c5db199SXin Li        """
73*9c5db199SXin Li        Initializes the fake modem object. kwargs can contain the optional
74*9c5db199SXin Li        argument |config|, which is a dictionary of property-value mappings.
75*9c5db199SXin Li        These properties will be added to the underlying property dictionary,
76*9c5db199SXin Li        and must be one of the properties listed in the ModemManager Reference
77*9c5db199SXin Li        Manual. See _InitializeProperties for all of the properties that belong
78*9c5db199SXin Li        to this interface. Possible values for each are enumerated in
79*9c5db199SXin Li        mm1_constants.py.
80*9c5db199SXin Li
81*9c5db199SXin Li        """
82*9c5db199SXin Li        if state_machine_factory:
83*9c5db199SXin Li            self._state_machine_factory = state_machine_factory
84*9c5db199SXin Li        else:
85*9c5db199SXin Li            self._state_machine_factory = smf.StateMachineFactory()
86*9c5db199SXin Li        self.device = device
87*9c5db199SXin Li        self.device_port_type = device_port_type
88*9c5db199SXin Li        self.index = index
89*9c5db199SXin Li        self.sim = None
90*9c5db199SXin Li
91*9c5db199SXin Li        # The superclass construct will call _InitializeProperties
92*9c5db199SXin Li        dbus_std_ifaces.DBusProperties.__init__(self,
93*9c5db199SXin Li            mm1_constants.MM1 + '/Modem/' + str(index), bus, config)
94*9c5db199SXin Li
95*9c5db199SXin Li        if roaming_networks is None:
96*9c5db199SXin Li            roaming_networks = []
97*9c5db199SXin Li        self.roaming_networks = roaming_networks
98*9c5db199SXin Li
99*9c5db199SXin Li        self.bearers = {}
100*9c5db199SXin Li        self.active_bearers = {}
101*9c5db199SXin Li        self.enable_step = None
102*9c5db199SXin Li        self.disable_step = None
103*9c5db199SXin Li        self.connect_step = None
104*9c5db199SXin Li        self.disconnect_step = None
105*9c5db199SXin Li        self.register_step = None
106*9c5db199SXin Li
107*9c5db199SXin Li        self._modemmanager = None
108*9c5db199SXin Li        self.resetting = False
109*9c5db199SXin Li
110*9c5db199SXin Li        self._sms_handler = sms_handler.SmsHandler(self, bus)
111*9c5db199SXin Li
112*9c5db199SXin Li
113*9c5db199SXin Li    def _InitializeProperties(self):
114*9c5db199SXin Li        """ Sets up the default values for the properties. """
115*9c5db199SXin Li        props = {
116*9c5db199SXin Li            'Manufacturer' : 'Banana Technologies', # be creative here
117*9c5db199SXin Li            'Model' : 'Banana Peel 3000', # yep
118*9c5db199SXin Li            'Revision' : '1.0',
119*9c5db199SXin Li            'DeviceIdentifier' : 'Banana1234567890',
120*9c5db199SXin Li            'Device' : self.device,
121*9c5db199SXin Li            'Ports': [dbus.types.Struct(
122*9c5db199SXin Li                              [self.device,
123*9c5db199SXin Li                               dbus.types.UInt32(self.device_port_type)],
124*9c5db199SXin Li                              signature='su'),
125*9c5db199SXin Li                      dbus.types.Struct(
126*9c5db199SXin Li                              [net_interface.PseudoNetInterface.IFACE_NAME,
127*9c5db199SXin Li                               dbus.types.UInt32(
128*9c5db199SXin Li                                       mm1_constants.MM_MODEM_PORT_TYPE_NET)],
129*9c5db199SXin Li                              signature='su')],
130*9c5db199SXin Li            'Drivers' : ['FakeDriver'],
131*9c5db199SXin Li            'Plugin' : 'Banana Plugin',
132*9c5db199SXin Li            'UnlockRequired' :
133*9c5db199SXin Li                    dbus.types.UInt32(mm1_constants.MM_MODEM_LOCK_NONE),
134*9c5db199SXin Li            'UnlockRetries' : dbus.Dictionary(signature='uu'),
135*9c5db199SXin Li            'State' : dbus.types.Int32(mm1_constants.MM_MODEM_STATE_DISABLED),
136*9c5db199SXin Li            'SignalQuality' : dbus.types.Struct(
137*9c5db199SXin Li                                      [dbus.types.UInt32(100), True],
138*9c5db199SXin Li                                      signature='ub'),
139*9c5db199SXin Li            'OwnNumbers' : ['5555555555'],
140*9c5db199SXin Li            'PowerState' :
141*9c5db199SXin Li                    dbus.types.UInt32(mm1_constants.MM_MODEM_POWER_STATE_ON),
142*9c5db199SXin Li            'SupportedIpFamilies' :
143*9c5db199SXin Li                dbus.types.UInt32(mm1_constants.MM_BEARER_IP_FAMILY_ANY),
144*9c5db199SXin Li            'Bearers' : dbus.Array([], signature='o'),
145*9c5db199SXin Li
146*9c5db199SXin Li            # specified by subclass:
147*9c5db199SXin Li            'SupportedCapabilities' :
148*9c5db199SXin Li                    [dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_NONE)],
149*9c5db199SXin Li            'CurrentCapabilities' :
150*9c5db199SXin Li                    dbus.types.UInt32(mm1_constants.MM_MODEM_CAPABILITY_NONE),
151*9c5db199SXin Li            'MaxBearers' : dbus.types.UInt32(0),
152*9c5db199SXin Li            'MaxActiveBearers' : dbus.types.UInt32(0),
153*9c5db199SXin Li            'EquipmentIdentifier' : '',
154*9c5db199SXin Li            'AccessTechnologies' :
155*9c5db199SXin Li                    dbus.types.UInt32(
156*9c5db199SXin Li                            mm1_constants.MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
157*9c5db199SXin Li            'SupportedModes' : [
158*9c5db199SXin Li                    dbus.types.Struct(
159*9c5db199SXin Li                            [dbus.types.UInt32(
160*9c5db199SXin Li                                    mm1_constants.MM_MODEM_MODE_NONE),
161*9c5db199SXin Li                             dbus.types.UInt32(
162*9c5db199SXin Li                                    mm1_constants.MM_MODEM_MODE_NONE)],
163*9c5db199SXin Li                            signature='uu')
164*9c5db199SXin Li            ],
165*9c5db199SXin Li            'CurrentModes' :
166*9c5db199SXin Li                    dbus.types.Struct(
167*9c5db199SXin Li                            [dbus.types.UInt32(
168*9c5db199SXin Li                                    mm1_constants.MM_MODEM_MODE_NONE),
169*9c5db199SXin Li                             dbus.types.UInt32(
170*9c5db199SXin Li                                    mm1_constants.MM_MODEM_MODE_NONE)],
171*9c5db199SXin Li                            signature='uu'),
172*9c5db199SXin Li            'SupportedBands' :
173*9c5db199SXin Li                    [dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_UNKNOWN)],
174*9c5db199SXin Li            'CurrentBands' :
175*9c5db199SXin Li                    [dbus.types.UInt32(mm1_constants.MM_MODEM_BAND_UNKNOWN)],
176*9c5db199SXin Li            'Sim' : dbus.types.ObjectPath(mm1_constants.ROOT_PATH)
177*9c5db199SXin Li        }
178*9c5db199SXin Li        return {
179*9c5db199SXin Li            mm1_constants.I_MODEM : props,
180*9c5db199SXin Li            mm1_constants.I_MODEM_SIMPLE : {}
181*9c5db199SXin Li        }
182*9c5db199SXin Li
183*9c5db199SXin Li
184*9c5db199SXin Li    def IncrementPath(self):
185*9c5db199SXin Li        """
186*9c5db199SXin Li        Increments the current index at which this modem is exposed on DBus.
187*9c5db199SXin Li        E.g. if the current path is org/freedesktop/ModemManager/Modem/0, the
188*9c5db199SXin Li        path will change to org/freedesktop/ModemManager/Modem/1.
189*9c5db199SXin Li
190*9c5db199SXin Li        Calling this method does not remove the object from its current path,
191*9c5db199SXin Li        which means that it will be available via both the old and the new
192*9c5db199SXin Li        paths. This is currently only used by Reset, in conjunction with
193*9c5db199SXin Li        dbus_std_ifaces.DBusObjectManager.[Add|Remove].
194*9c5db199SXin Li
195*9c5db199SXin Li        """
196*9c5db199SXin Li        self.index += 1
197*9c5db199SXin Li        path = mm1_constants.MM1 + '/Modem/' + str(self.index)
198*9c5db199SXin Li        logging.info('Modem coming back as: ' + path)
199*9c5db199SXin Li        self.SetPath(path)
200*9c5db199SXin Li
201*9c5db199SXin Li
202*9c5db199SXin Li    @property
203*9c5db199SXin Li    def manager(self):
204*9c5db199SXin Li        """
205*9c5db199SXin Li        The current modemmanager.ModemManager instance that is managing this
206*9c5db199SXin Li        modem.
207*9c5db199SXin Li
208*9c5db199SXin Li        @returns: A modemmanager.ModemManager object.
209*9c5db199SXin Li
210*9c5db199SXin Li        """
211*9c5db199SXin Li        return self._modemmanager
212*9c5db199SXin Li
213*9c5db199SXin Li
214*9c5db199SXin Li    @manager.setter
215*9c5db199SXin Li    def manager(self, manager):
216*9c5db199SXin Li        """
217*9c5db199SXin Li        Sets the current modemmanager.ModemManager instance that is managing
218*9c5db199SXin Li        this modem.
219*9c5db199SXin Li
220*9c5db199SXin Li        @param manager: A modemmanager.ModemManager object.
221*9c5db199SXin Li
222*9c5db199SXin Li        """
223*9c5db199SXin Li        self._modemmanager = manager
224*9c5db199SXin Li
225*9c5db199SXin Li
226*9c5db199SXin Li    @property
227*9c5db199SXin Li    def sms_handler(self):
228*9c5db199SXin Li        """
229*9c5db199SXin Li        @returns: sms_handler.SmsHandler responsible for handling SMS.
230*9c5db199SXin Li
231*9c5db199SXin Li        """
232*9c5db199SXin Li        return self._sms_handler
233*9c5db199SXin Li
234*9c5db199SXin Li
235*9c5db199SXin Li    def IsPendingEnable(self):
236*9c5db199SXin Li        """
237*9c5db199SXin Li        @returns: True, if a current enable state machine is active and hasn't
238*9c5db199SXin Li                been cancelled.
239*9c5db199SXin Li
240*9c5db199SXin Li        """
241*9c5db199SXin Li        return self.enable_step and not self.enable_step.cancelled
242*9c5db199SXin Li
243*9c5db199SXin Li
244*9c5db199SXin Li    def IsPendingDisable(self):
245*9c5db199SXin Li        """
246*9c5db199SXin Li        @returns: True, if a current disable state machine is active and hasn't
247*9c5db199SXin Li                been cancelled.
248*9c5db199SXin Li
249*9c5db199SXin Li        """
250*9c5db199SXin Li        return self.disable_step and not self.disable_step.cancelled
251*9c5db199SXin Li
252*9c5db199SXin Li
253*9c5db199SXin Li    def IsPendingConnect(self):
254*9c5db199SXin Li        """
255*9c5db199SXin Li        @returns: True, if a current connect state machine is active and hasn't
256*9c5db199SXin Li                been cancelled.
257*9c5db199SXin Li
258*9c5db199SXin Li        """
259*9c5db199SXin Li        return self.connect_step and not self.connect_step.cancelled
260*9c5db199SXin Li
261*9c5db199SXin Li
262*9c5db199SXin Li    def IsPendingDisconnect(self):
263*9c5db199SXin Li        """
264*9c5db199SXin Li        @returns: True, if a current disconnect state machine is active and
265*9c5db199SXin Li                hasn't been cancelled.
266*9c5db199SXin Li
267*9c5db199SXin Li        """
268*9c5db199SXin Li        return self.disconnect_step and not self.disconnect_step.cancelled
269*9c5db199SXin Li
270*9c5db199SXin Li
271*9c5db199SXin Li    def IsPendingRegister(self):
272*9c5db199SXin Li        """
273*9c5db199SXin Li        @returns: True, if a current register state machine is active and hasn't
274*9c5db199SXin Li                been cancelled.
275*9c5db199SXin Li
276*9c5db199SXin Li        """
277*9c5db199SXin Li        return self.register_step and not self.register_step.cancelled
278*9c5db199SXin Li
279*9c5db199SXin Li
280*9c5db199SXin Li    def CancelAllStateMachines(self):
281*9c5db199SXin Li        """ Cancels all state machines that are active. """
282*9c5db199SXin Li        if self.IsPendingEnable():
283*9c5db199SXin Li            self.enable_step.Cancel()
284*9c5db199SXin Li        if self.IsPendingDisable():
285*9c5db199SXin Li            self.disable_step.Cancel()
286*9c5db199SXin Li        if self.IsPendingConnect():
287*9c5db199SXin Li            self.connect_step.Cancel()
288*9c5db199SXin Li        if self.IsPendingDisconnect():
289*9c5db199SXin Li            self.disconnect_step.Cancel()
290*9c5db199SXin Li        if self.IsPendingRegister():
291*9c5db199SXin Li            self.register_step.Cancel()
292*9c5db199SXin Li
293*9c5db199SXin Li
294*9c5db199SXin Li    def SetSignalQuality(self, quality):
295*9c5db199SXin Li        """
296*9c5db199SXin Li        Sets the 'SignalQuality' property to the given value.
297*9c5db199SXin Li
298*9c5db199SXin Li        @param quality: An integer value in the range 0-100.
299*9c5db199SXin Li        Emits:
300*9c5db199SXin Li            PropertiesChanged
301*9c5db199SXin Li
302*9c5db199SXin Li        """
303*9c5db199SXin Li        self.Set(mm1_constants.I_MODEM, 'SignalQuality', (dbus.types.Struct(
304*9c5db199SXin Li            [dbus.types.UInt32(quality), True], signature='ub')))
305*9c5db199SXin Li
306*9c5db199SXin Li
307*9c5db199SXin Li    def ChangeState(self, state, reason):
308*9c5db199SXin Li        """
309*9c5db199SXin Li        Changes the modem state and emits the StateChanged signal.
310*9c5db199SXin Li
311*9c5db199SXin Li        @param state: A MMModemState value.
312*9c5db199SXin Li        @param reason: A MMModemStateChangeReason value.
313*9c5db199SXin Li        Emits:
314*9c5db199SXin Li            PropertiesChanged
315*9c5db199SXin Li            StateChanged
316*9c5db199SXin Li
317*9c5db199SXin Li        """
318*9c5db199SXin Li        old_state = self.Get(mm1_constants.I_MODEM, 'State')
319*9c5db199SXin Li        self.SetInt32(mm1_constants.I_MODEM, 'State', state)
320*9c5db199SXin Li        self.StateChanged(old_state, state, dbus.types.UInt32(reason))
321*9c5db199SXin Li
322*9c5db199SXin Li
323*9c5db199SXin Li    def SetSIM(self, sim):
324*9c5db199SXin Li        """
325*9c5db199SXin Li        Assigns a SIM object to this Modem. It exposes the SIM object via DBus
326*9c5db199SXin Li        and sets 'Sim' property of this Modem to the path of the SIM.
327*9c5db199SXin Li
328*9c5db199SXin Li        @param sim: An instance of sim.SIM.
329*9c5db199SXin Li        Emits:
330*9c5db199SXin Li            PropertiesChanged
331*9c5db199SXin Li
332*9c5db199SXin Li        """
333*9c5db199SXin Li        self.sim = sim
334*9c5db199SXin Li        if not sim:
335*9c5db199SXin Li            val = mm1_constants.ROOT_PATH
336*9c5db199SXin Li        else:
337*9c5db199SXin Li            val = sim.path
338*9c5db199SXin Li            self.sim.SetBus(self.bus)
339*9c5db199SXin Li            self.sim.modem = self
340*9c5db199SXin Li            self.UpdateLockStatus()
341*9c5db199SXin Li        self.Set(mm1_constants.I_MODEM, 'Sim', dbus.types.ObjectPath(val))
342*9c5db199SXin Li
343*9c5db199SXin Li
344*9c5db199SXin Li    def SetBus(self, bus):
345*9c5db199SXin Li        """
346*9c5db199SXin Li        Overridden from dbus_std_ifaces.DBusProperties.
347*9c5db199SXin Li
348*9c5db199SXin Li        @param bus
349*9c5db199SXin Li
350*9c5db199SXin Li        """
351*9c5db199SXin Li        dbus_std_ifaces.DBusProperties.SetBus(self, bus)
352*9c5db199SXin Li        self._state_machine_factory.SetBus(bus)
353*9c5db199SXin Li        self._sms_handler.bus = bus
354*9c5db199SXin Li
355*9c5db199SXin Li
356*9c5db199SXin Li    def UpdateLockStatus(self):
357*9c5db199SXin Li        """
358*9c5db199SXin Li        Tells the modem to update the current lock status. This method will
359*9c5db199SXin Li        update the modem state and the relevant modem properties.
360*9c5db199SXin Li
361*9c5db199SXin Li        """
362*9c5db199SXin Li        if not self.sim:
363*9c5db199SXin Li            logging.info('SIM lock is the only kind of lock that is currently '
364*9c5db199SXin Li                         'supported. No SIM present, nothing to do.')
365*9c5db199SXin Li            return
366*9c5db199SXin Li        self.SetUInt32(mm1_constants.I_MODEM, 'UnlockRequired',
367*9c5db199SXin Li                       self.sim.lock_type)
368*9c5db199SXin Li        self.Set(mm1_constants.I_MODEM, 'UnlockRetries',
369*9c5db199SXin Li                 self.sim.unlock_retries)
370*9c5db199SXin Li        if self.sim.locked:
371*9c5db199SXin Li            def _SetLocked():
372*9c5db199SXin Li                logging.info('There is a SIM lock in place. Setting state to '
373*9c5db199SXin Li                             'LOCKED')
374*9c5db199SXin Li                self.ChangeState(
375*9c5db199SXin Li                        mm1_constants.MM_MODEM_STATE_LOCKED,
376*9c5db199SXin Li                        mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN)
377*9c5db199SXin Li
378*9c5db199SXin Li            # If the modem is currently in an enabled state, disable it before
379*9c5db199SXin Li            # setting the modem state to LOCKED.
380*9c5db199SXin Li            if (self.Get(mm1_constants.I_MODEM, 'State') >=
381*9c5db199SXin Li                    mm1_constants.MM_MODEM_STATE_ENABLED):
382*9c5db199SXin Li                logging.info('SIM got locked. Disabling modem.')
383*9c5db199SXin Li                self.Enable(False, return_cb=_SetLocked)
384*9c5db199SXin Li            else:
385*9c5db199SXin Li                _SetLocked()
386*9c5db199SXin Li        elif (self.Get(mm1_constants.I_MODEM, 'State') ==
387*9c5db199SXin Li                mm1_constants.MM_MODEM_STATE_LOCKED):
388*9c5db199SXin Li            # Change the state to DISABLED. Shill will see the property change
389*9c5db199SXin Li            # and automatically attempt to enable the modem.
390*9c5db199SXin Li            logging.info('SIM became unlocked! Setting state to INITIALIZING.')
391*9c5db199SXin Li            self.ChangeState(mm1_constants.MM_MODEM_STATE_INITIALIZING,
392*9c5db199SXin Li                             mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN)
393*9c5db199SXin Li            logging.info('SIM became unlocked! Setting state to DISABLED.')
394*9c5db199SXin Li            self.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLED,
395*9c5db199SXin Li                             mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN)
396*9c5db199SXin Li
397*9c5db199SXin Li
398*9c5db199SXin Li    @utils.log_dbus_method(return_cb_arg='return_cb', raise_cb_arg='raise_cb')
399*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM,
400*9c5db199SXin Li                         in_signature='b', async_callbacks=('return_cb',
401*9c5db199SXin Li                                                            'raise_cb'))
402*9c5db199SXin Li    def Enable(self, enable, return_cb=None, raise_cb=None):
403*9c5db199SXin Li        """
404*9c5db199SXin Li        Enables or disables the modem.
405*9c5db199SXin Li
406*9c5db199SXin Li        When enabled, the modem's radio is powered on and data sessions, voice
407*9c5db199SXin Li        calls, location services, and Short Message Service may be available.
408*9c5db199SXin Li
409*9c5db199SXin Li        When disabled, the modem enters low-power state and no network-related
410*9c5db199SXin Li        operations are available.
411*9c5db199SXin Li
412*9c5db199SXin Li        @param enable: True to enable the modem and False to disable it.
413*9c5db199SXin Li        @param return_cb: The asynchronous callback to invoke on success.
414*9c5db199SXin Li        @param raise_cb: The asynchronous callback to invoke on failure. Has to
415*9c5db199SXin Li                take a python Exception or Error as its single argument.
416*9c5db199SXin Li
417*9c5db199SXin Li        """
418*9c5db199SXin Li        if enable:
419*9c5db199SXin Li            logging.info('Modem enable')
420*9c5db199SXin Li            machine = self._state_machine_factory.CreateMachine(
421*9c5db199SXin Li                    pm_constants.STATE_MACHINE_ENABLE,
422*9c5db199SXin Li                    self,
423*9c5db199SXin Li                    return_cb,
424*9c5db199SXin Li                    raise_cb)
425*9c5db199SXin Li        else:
426*9c5db199SXin Li            logging.info('Modem disable')
427*9c5db199SXin Li            machine = self._state_machine_factory.CreateMachine(
428*9c5db199SXin Li                    pm_constants.STATE_MACHINE_DISABLE,
429*9c5db199SXin Li                    self,
430*9c5db199SXin Li                    return_cb,
431*9c5db199SXin Li                    raise_cb)
432*9c5db199SXin Li        machine.Start()
433*9c5db199SXin Li
434*9c5db199SXin Li
435*9c5db199SXin Li    def RegisterWithNetwork(
436*9c5db199SXin Li            self, operator_id="", return_cb=None, raise_cb=None):
437*9c5db199SXin Li        """
438*9c5db199SXin Li        Register with the network specified by the given |operator_id|.
439*9c5db199SXin Li        |operator_id| should be an MCCMNC value (for 3GPP) or an empty string.
440*9c5db199SXin Li        An implementation of this method must set the state to SEARCHING first,
441*9c5db199SXin Li        and eventually to REGISTERED, also setting technology specific
442*9c5db199SXin Li        registration state properties. Technology specific error cases need to
443*9c5db199SXin Li        be handled here (such as activation, the presence of a valid SIM card,
444*9c5db199SXin Li        etc).
445*9c5db199SXin Li
446*9c5db199SXin Li        Must be implemented by a subclass.
447*9c5db199SXin Li
448*9c5db199SXin Li        @param operator_id: String containing the operator code. This method
449*9c5db199SXin Li                will typically initiate a network scan, yielding a list of
450*9c5db199SXin Li                networks. If |operator_id| is non-empty, the modem will register
451*9c5db199SXin Li                with the network in the scanned list that matches |operator_id|.
452*9c5db199SXin Li                An empty |operator_id| means that registration should be
453*9c5db199SXin Li                "automatic". In this case the implementation would typically
454*9c5db199SXin Li                register with the home network. If a home network is not
455*9c5db199SXin Li                available than any network that is returned by a network scan
456*9c5db199SXin Li                can be registered with.
457*9c5db199SXin Li
458*9c5db199SXin Li                Note: CDMA doesn't support a network scan. In this case, the
459*9c5db199SXin Li                only possible option is to register with the home network and
460*9c5db199SXin Li                ignore the value of |operator_id|.
461*9c5db199SXin Li        @param return_cb: Async success callback.
462*9c5db199SXin Li        @param raise_cb: Async failure callback.
463*9c5db199SXin Li
464*9c5db199SXin Li        """
465*9c5db199SXin Li        raise NotImplementedError()
466*9c5db199SXin Li
467*9c5db199SXin Li
468*9c5db199SXin Li    def UnregisterWithNetwork(self):
469*9c5db199SXin Li        """
470*9c5db199SXin Li        Unregisters with the currently registered network. This should
471*9c5db199SXin Li        transition the modem to the ENABLED state.
472*9c5db199SXin Li
473*9c5db199SXin Li        Must be implemented by a subclass.
474*9c5db199SXin Li
475*9c5db199SXin Li        """
476*9c5db199SXin Li        raise NotImplementedError()
477*9c5db199SXin Li
478*9c5db199SXin Li
479*9c5db199SXin Li    def ValidateBearerProperties(self, properties):
480*9c5db199SXin Li        """
481*9c5db199SXin Li        The default implementation makes sure that all keys in properties are
482*9c5db199SXin Li        one of the allowed bearer properties. Subclasses can override this
483*9c5db199SXin Li        method to provide CDMA/3GPP specific checks.
484*9c5db199SXin Li
485*9c5db199SXin Li        @param properties: The dictionary of properties and values to validate.
486*9c5db199SXin Li        @raises: MMCoreError, if one or more properties are invalid.
487*9c5db199SXin Li
488*9c5db199SXin Li        """
489*9c5db199SXin Li        for key in six.iterkeys(properties):
490*9c5db199SXin Li            if key not in ALLOWED_BEARER_PROPERTIES:
491*9c5db199SXin Li                raise pm_errors.MMCoreError(
492*9c5db199SXin Li                        pm_errors.MMCoreError.INVALID_ARGS,
493*9c5db199SXin Li                        'Invalid property "%s", not creating bearer.' % key)
494*9c5db199SXin Li
495*9c5db199SXin Li
496*9c5db199SXin Li    @utils.log_dbus_method()
497*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, out_signature='ao')
498*9c5db199SXin Li    def ListBearers(self):
499*9c5db199SXin Li        """
500*9c5db199SXin Li        Lists configured packet data bearers (EPS Bearers, PDP Contexts, or
501*9c5db199SXin Li        CDMA2000 Packet Data Sessions).
502*9c5db199SXin Li
503*9c5db199SXin Li        @returns: A list of bearer object paths.
504*9c5db199SXin Li
505*9c5db199SXin Li        """
506*9c5db199SXin Li        return self.Get(mm1_constants.I_MODEM, 'Bearers')
507*9c5db199SXin Li
508*9c5db199SXin Li
509*9c5db199SXin Li    @utils.log_dbus_method()
510*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='a{sv}',
511*9c5db199SXin Li                         out_signature='o')
512*9c5db199SXin Li    def CreateBearer(self, properties):
513*9c5db199SXin Li        """
514*9c5db199SXin Li        Creates a new packet data bearer using the given characteristics.
515*9c5db199SXin Li
516*9c5db199SXin Li        This request may fail if the modem does not support additional bearers,
517*9c5db199SXin Li        if too many bearers are already defined, or if properties are invalid.
518*9c5db199SXin Li
519*9c5db199SXin Li        @param properties: A dictionary containing the properties to assign to
520*9c5db199SXin Li                the bearer after creating it. The allowed property values are
521*9c5db199SXin Li                contained in modem.ALLOWED_PROPERTIES.
522*9c5db199SXin Li        @returns: On success, the object path of the newly created bearer.
523*9c5db199SXin Li
524*9c5db199SXin Li        """
525*9c5db199SXin Li        logging.info('CreateBearer')
526*9c5db199SXin Li        maxbearers = self.Get(mm1_constants.I_MODEM, 'MaxBearers')
527*9c5db199SXin Li        if len(self.bearers) == maxbearers:
528*9c5db199SXin Li            raise pm_errors.MMCoreError(
529*9c5db199SXin Li                    pm_errors.MMCoreError.TOO_MANY,
530*9c5db199SXin Li                    ('Maximum number of bearers reached. Cannot create new '
531*9c5db199SXin Li                     'bearer.'))
532*9c5db199SXin Li        else:
533*9c5db199SXin Li            self.ValidateBearerProperties(properties)
534*9c5db199SXin Li            bearer_obj = bearer.Bearer(self.bus, properties)
535*9c5db199SXin Li            logging.info('Created bearer with path "%s".', bearer_obj.path)
536*9c5db199SXin Li            self.bearers[bearer_obj.path] = bearer_obj
537*9c5db199SXin Li            self._UpdateBearersProperty()
538*9c5db199SXin Li            return bearer_obj.path
539*9c5db199SXin Li
540*9c5db199SXin Li
541*9c5db199SXin Li    def ActivateBearer(self, bearer_path):
542*9c5db199SXin Li        """
543*9c5db199SXin Li        Activates a data bearer by setting its 'Connected' property to True.
544*9c5db199SXin Li
545*9c5db199SXin Li        This request may fail if the modem does not support additional active
546*9c5db199SXin Li        bearers, if too many bearers are already active, if the requested
547*9c5db199SXin Li        bearer doesn't exist, or if the requested bearer is already active.
548*9c5db199SXin Li
549*9c5db199SXin Li        @param bearer_path: DBus path of the bearer to activate.
550*9c5db199SXin Li
551*9c5db199SXin Li        """
552*9c5db199SXin Li        logging.info('ActivateBearer: %s', bearer_path)
553*9c5db199SXin Li        bearer = self.bearers.get(bearer_path, None)
554*9c5db199SXin Li        if bearer is None:
555*9c5db199SXin Li            message = 'Could not find bearer with path "%s"' % bearer_path
556*9c5db199SXin Li            logging.info(message)
557*9c5db199SXin Li            raise pm_errors.MMCoreError(pm_errors.MMCoreError.NOT_FOUND,
558*9c5db199SXin Li                                        message)
559*9c5db199SXin Li
560*9c5db199SXin Li        max_active_bearers = self.Get(mm1_constants.I_MODEM, 'MaxActiveBearers')
561*9c5db199SXin Li        if len(self.active_bearers) >= max_active_bearers:
562*9c5db199SXin Li            message = ('Cannot activate bearer: maximum active bearer count '
563*9c5db199SXin Li                       'reached.')
564*9c5db199SXin Li            logging.info(message)
565*9c5db199SXin Li            raise pm_errors.MMCoreError(pm_errors.MMCoreError.TOO_MANY, message)
566*9c5db199SXin Li        if bearer.IsActive():
567*9c5db199SXin Li            message = 'Bearer with path "%s" already active.', bearer_path
568*9c5db199SXin Li            logging.info(message)
569*9c5db199SXin Li            raise pm_errors.MMCoreError(pm_errors.MMCoreError.CONNECTED,
570*9c5db199SXin Li                                        message)
571*9c5db199SXin Li
572*9c5db199SXin Li        self.active_bearers[bearer_path] = bearer
573*9c5db199SXin Li        bearer.Connect()
574*9c5db199SXin Li
575*9c5db199SXin Li
576*9c5db199SXin Li    def DeactivateBearer(self, bearer_path):
577*9c5db199SXin Li        """
578*9c5db199SXin Li        Deactivates data bearer by setting its 'Connected' property to False.
579*9c5db199SXin Li
580*9c5db199SXin Li        This request may fail if the modem with the requested path doesn't
581*9c5db199SXin Li        exist, or if the bearer is not active.
582*9c5db199SXin Li
583*9c5db199SXin Li        @param bearer_path: DBus path of the bearer to activate.
584*9c5db199SXin Li
585*9c5db199SXin Li        """
586*9c5db199SXin Li        logging.info('DeactivateBearer: %s', bearer_path)
587*9c5db199SXin Li        bearer = self.bearers.get(bearer_path, None)
588*9c5db199SXin Li        if bearer is None:
589*9c5db199SXin Li            raise pm_errors.MMCoreError(
590*9c5db199SXin Li                    pm_errors.MMCoreError.NOT_FOUND,
591*9c5db199SXin Li                    'Could not find bearer with path "%s".' % bearer_path)
592*9c5db199SXin Li        if not bearer.IsActive():
593*9c5db199SXin Li            assert bearer_path not in self.active_bearers
594*9c5db199SXin Li            raise pm_errors.MMCoreError(
595*9c5db199SXin Li                    pm_errors.MMCoreError.WRONG_STATE,
596*9c5db199SXin Li                    'Bearer with path "%s" is not active.' % bearer_path)
597*9c5db199SXin Li        assert bearer_path in self.active_bearers
598*9c5db199SXin Li        bearer.Disconnect()
599*9c5db199SXin Li        self.active_bearers.pop(bearer_path)
600*9c5db199SXin Li
601*9c5db199SXin Li
602*9c5db199SXin Li    @utils.log_dbus_method()
603*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='o')
604*9c5db199SXin Li    def DeleteBearer(self, bearer):
605*9c5db199SXin Li        """
606*9c5db199SXin Li        Deletes an existing packet data bearer.
607*9c5db199SXin Li
608*9c5db199SXin Li        If the bearer is currently active, it will be deactivated.
609*9c5db199SXin Li
610*9c5db199SXin Li        @param bearer: Object path of the bearer to delete.
611*9c5db199SXin Li
612*9c5db199SXin Li        """
613*9c5db199SXin Li        logging.info('Modem.DeleteBearer: ' + str(bearer))
614*9c5db199SXin Li        if not bearer in self.bearers:
615*9c5db199SXin Li            logging.info('Unknown bearer. Nothing to do.')
616*9c5db199SXin Li            return
617*9c5db199SXin Li        bearer_object = self.bearers[bearer]
618*9c5db199SXin Li        bearer_object.remove_from_connection()
619*9c5db199SXin Li        self.bearers.pop(bearer)
620*9c5db199SXin Li        self._UpdateBearersProperty()
621*9c5db199SXin Li        if bearer in self.active_bearers:
622*9c5db199SXin Li            self.active_bearers.pop(bearer)
623*9c5db199SXin Li
624*9c5db199SXin Li
625*9c5db199SXin Li    def ClearBearers(self):
626*9c5db199SXin Li        """ Deletes all bearers that are managed by this modem. """
627*9c5db199SXin Li        for b in self.bearers.keys():
628*9c5db199SXin Li            self.DeleteBearer(b)
629*9c5db199SXin Li
630*9c5db199SXin Li
631*9c5db199SXin Li    @utils.log_dbus_method()
632*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM)
633*9c5db199SXin Li    def Reset(self):
634*9c5db199SXin Li        """
635*9c5db199SXin Li        Clears non-persistent configuration and state, and returns the device to
636*9c5db199SXin Li        a newly-powered-on state.
637*9c5db199SXin Li
638*9c5db199SXin Li        As a result of this operation, the modem will be removed from its
639*9c5db199SXin Li        current path and will be exposed on an incremented path. It will be
640*9c5db199SXin Li        enabled afterwards.
641*9c5db199SXin Li
642*9c5db199SXin Li        """
643*9c5db199SXin Li        logging.info('Resetting modem.')
644*9c5db199SXin Li
645*9c5db199SXin Li        if self.resetting:
646*9c5db199SXin Li            raise pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS,
647*9c5db199SXin Li                                        'Reset already in progress.')
648*9c5db199SXin Li
649*9c5db199SXin Li        self.resetting = True
650*9c5db199SXin Li
651*9c5db199SXin Li        self.CancelAllStateMachines()
652*9c5db199SXin Li
653*9c5db199SXin Li        def _ResetFunc():
654*9c5db199SXin Li            # Disappear.
655*9c5db199SXin Li            manager = self.manager
656*9c5db199SXin Li            if manager:
657*9c5db199SXin Li                manager.Remove(self)
658*9c5db199SXin Li                if self.sim:
659*9c5db199SXin Li                    manager.Remove(self.sim)
660*9c5db199SXin Li
661*9c5db199SXin Li            self.ClearBearers()
662*9c5db199SXin Li
663*9c5db199SXin Li            # Reappear.
664*9c5db199SXin Li            def _DelayedReappear():
665*9c5db199SXin Li                self.IncrementPath()
666*9c5db199SXin Li
667*9c5db199SXin Li                # Reset to defaults.
668*9c5db199SXin Li                if self.sim:
669*9c5db199SXin Li                    self.sim.Reset()
670*9c5db199SXin Li                self._properties = self._InitializeProperties()
671*9c5db199SXin Li                if self.sim:
672*9c5db199SXin Li                    self.Set(mm1_constants.I_MODEM,
673*9c5db199SXin Li                             'Sim',
674*9c5db199SXin Li                             dbus.types.ObjectPath(self.sim.path))
675*9c5db199SXin Li                    self.UpdateLockStatus()
676*9c5db199SXin Li
677*9c5db199SXin Li                if manager:
678*9c5db199SXin Li                    manager.Add(self)
679*9c5db199SXin Li
680*9c5db199SXin Li                self.resetting = False
681*9c5db199SXin Li
682*9c5db199SXin Li                def _DelayedEnable():
683*9c5db199SXin Li                    state = self.Get(mm1_constants.I_MODEM, 'State')
684*9c5db199SXin Li                    if not self.IsPendingEnable() and \
685*9c5db199SXin Li                            state == mm1_constants.MM_MODEM_STATE_DISABLED:
686*9c5db199SXin Li                        self.Enable(True)
687*9c5db199SXin Li                    return False
688*9c5db199SXin Li
689*9c5db199SXin Li                GObject.timeout_add(1000, _DelayedEnable)
690*9c5db199SXin Li                return False
691*9c5db199SXin Li
692*9c5db199SXin Li            GObject.timeout_add(2000, _DelayedReappear)
693*9c5db199SXin Li
694*9c5db199SXin Li        def _ErrorCallback(error):
695*9c5db199SXin Li            raise error
696*9c5db199SXin Li
697*9c5db199SXin Li        if (self.Get(mm1_constants.I_MODEM, 'State') ==
698*9c5db199SXin Li                mm1_constants.MM_MODEM_STATE_CONNECTED):
699*9c5db199SXin Li            self.Disconnect('/', _ResetFunc, _ErrorCallback)
700*9c5db199SXin Li        else:
701*9c5db199SXin Li            GObject.idle_add(_ResetFunc)
702*9c5db199SXin Li
703*9c5db199SXin Li
704*9c5db199SXin Li    @utils.log_dbus_method()
705*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='s')
706*9c5db199SXin Li    def FactoryReset(self, code):
707*9c5db199SXin Li        """
708*9c5db199SXin Li        Clears the modem's configuration (including persistent configuration and
709*9c5db199SXin Li        state), and returns the device to a factory-default state.
710*9c5db199SXin Li
711*9c5db199SXin Li        If not required by the modem, code may be ignored.
712*9c5db199SXin Li
713*9c5db199SXin Li        This command may or may not power-cycle the device.
714*9c5db199SXin Li
715*9c5db199SXin Li        @param code: Carrier specific activation code.
716*9c5db199SXin Li
717*9c5db199SXin Li        """
718*9c5db199SXin Li        raise NotImplementedError()
719*9c5db199SXin Li
720*9c5db199SXin Li
721*9c5db199SXin Li    @utils.log_dbus_method()
722*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='(uu)')
723*9c5db199SXin Li    def SetCurrentModes(self, modes):
724*9c5db199SXin Li        """
725*9c5db199SXin Li        Sets the access technologies (eg 2G/3G/4G preference) the device is
726*9c5db199SXin Li        currently allowed to use when connecting to a network.
727*9c5db199SXin Li
728*9c5db199SXin Li        @param modes: Specifies all the modes allowed in the modem as a bitmask
729*9c5db199SXin Li                of MMModemModem values.
730*9c5db199SXin Li        @param preferred: Specific MMModemMode preferred among the ones allowed,
731*9c5db199SXin Li                if any.
732*9c5db199SXin Li
733*9c5db199SXin Li        """
734*9c5db199SXin Li        allowed = self.Get(mm1_constants.I_MODEM, 'SupportedModes')
735*9c5db199SXin Li        if not modes in allowed:
736*9c5db199SXin Li            raise pm_errors.MMCoreError(pm_errors.MMCoreError.FAILED,
737*9c5db199SXin Li                                        'Mode not supported: ' + repr(modes))
738*9c5db199SXin Li        self.Set(mm1_constants.I_MODEM, 'CurrentModes', modes)
739*9c5db199SXin Li
740*9c5db199SXin Li
741*9c5db199SXin Li    @utils.log_dbus_method()
742*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='au')
743*9c5db199SXin Li    def SetCurrentBands(self, bands):
744*9c5db199SXin Li        """
745*9c5db199SXin Li        Sets the radio frequency and technology bands the device is currently
746*9c5db199SXin Li        allowed to use when connecting to a network.
747*9c5db199SXin Li
748*9c5db199SXin Li        @param bands: Specifies the bands to be used as a list of MMModemBand
749*9c5db199SXin Li                values.
750*9c5db199SXin Li
751*9c5db199SXin Li        """
752*9c5db199SXin Li        band_list = [dbus.types.UInt32(band) for band in bands]
753*9c5db199SXin Li        self.Set(mm1_constants.I_MODEM, 'CurrentBands', band_list)
754*9c5db199SXin Li
755*9c5db199SXin Li
756*9c5db199SXin Li    @utils.log_dbus_method()
757*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='su',
758*9c5db199SXin Li                         out_signature='s')
759*9c5db199SXin Li    def Command(self, cmd, timeout):
760*9c5db199SXin Li        """
761*9c5db199SXin Li        Allows clients to send commands to the modem. By default, this method
762*9c5db199SXin Li        does nothing, but responds by telling the client's fortune to brighten
763*9c5db199SXin Li        the client's day.
764*9c5db199SXin Li
765*9c5db199SXin Li        @param cmd: Command to send to the modem.
766*9c5db199SXin Li        @param timeout: The timeout interval for the command.
767*9c5db199SXin Li        @returns: A string containing the response from the modem.
768*9c5db199SXin Li
769*9c5db199SXin Li        """
770*9c5db199SXin Li        messages = ['Bananas are tasty and fresh. Have one!',
771*9c5db199SXin Li                    'A soft voice may be awfully persuasive.',
772*9c5db199SXin Li                    'Be careful or you could fall for some tricks today.',
773*9c5db199SXin Li                    'Believe in yourself and others will too.',
774*9c5db199SXin Li                    'Carve your name on your heart and not on marble.']
775*9c5db199SXin Li        return random.choice(messages)
776*9c5db199SXin Li
777*9c5db199SXin Li
778*9c5db199SXin Li    @utils.log_dbus_method()
779*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='u')
780*9c5db199SXin Li    def SetPowerState(self, power_state):
781*9c5db199SXin Li        """
782*9c5db199SXin Li        Sets the power state of the modem. This action can only be run when the
783*9c5db199SXin Li        modem is in the MM_MODEM_STATE_DISABLED state.
784*9c5db199SXin Li
785*9c5db199SXin Li        @param power_state: Specifies the desired power state as a
786*9c5db199SXin Li                MMModemPowerState value.
787*9c5db199SXin Li        @raises: MMCoreError if state is not DISABLED.
788*9c5db199SXin Li
789*9c5db199SXin Li        """
790*9c5db199SXin Li        if (self.Get(mm1_constants.I_MODEM, 'State') !=
791*9c5db199SXin Li                mm1_constants.MM_MODEM_STATE_DISABLED):
792*9c5db199SXin Li            raise pm_errors.MMCoreError(
793*9c5db199SXin Li                    pm_errors.MMCoreError.WRONG_STATE,
794*9c5db199SXin Li                    'Cannot set the power state if modem is not DISABLED.')
795*9c5db199SXin Li        self.SetUInt32(mm1_constants.I_MODEM, 'PowerState', power_state);
796*9c5db199SXin Li
797*9c5db199SXin Li
798*9c5db199SXin Li    @utils.log_dbus_method()
799*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_MODEM, in_signature='u')
800*9c5db199SXin Li    def SetCurrentCapabilities(self, capabilities):
801*9c5db199SXin Li        """
802*9c5db199SXin Li        Set the capabilities of the device. A restart of the modem may be
803*9c5db199SXin Li        required.
804*9c5db199SXin Li
805*9c5db199SXin Li        @param capabilities: Bitmask of MMModemCapability values, to specify the
806*9c5db199SXin Li                capabilities to use.
807*9c5db199SXin Li
808*9c5db199SXin Li        """
809*9c5db199SXin Li        supported = self.Get(mm1_constants.I_MODEM, 'SupportedCapabilities')
810*9c5db199SXin Li        if not capabilities in supported:
811*9c5db199SXin Li            raise pm_errors.MMCoreError(
812*9c5db199SXin Li                    pm_errors.MMCoreError.FAILED,
813*9c5db199SXin Li                    'Given capabilities not supported: ' + capabilities)
814*9c5db199SXin Li        self.SetUInt32(mm1_constants.I_MODEM, 'CurrentCapabilities',
815*9c5db199SXin Li                       capabilities)
816*9c5db199SXin Li
817*9c5db199SXin Li
818*9c5db199SXin Li    @dbus.service.signal(mm1_constants.I_MODEM, signature='iiu')
819*9c5db199SXin Li    def StateChanged(self, old, new, reason):
820*9c5db199SXin Li        """
821*9c5db199SXin Li        Signals that the modem's 'State' property has changed.
822*9c5db199SXin Li
823*9c5db199SXin Li        @param old: Specifies the old state, as a MMModemState value.
824*9c5db199SXin Li        @param new: Specifies the new state, as a MMModemState value.
825*9c5db199SXin Li        @param reason: Specifies the reason for this state change as a
826*9c5db199SXin Li                MMModemStateChangeReason value.
827*9c5db199SXin Li
828*9c5db199SXin Li        """
829*9c5db199SXin Li        logging.info('Modem state changed from %u to %u for reason %u',
830*9c5db199SXin Li                old, new, reason)
831*9c5db199SXin Li
832*9c5db199SXin Li
833*9c5db199SXin Li    # org.freedesktop.ModemManager1.Messaging
834*9c5db199SXin Li
835*9c5db199SXin Li    def List(self):
836*9c5db199SXin Li        """
837*9c5db199SXin Li        Overriden from messaging.Messaging.
838*9c5db199SXin Li
839*9c5db199SXin Li        """
840*9c5db199SXin Li        return self._sms_handler.list_messages()
841*9c5db199SXin Li
842*9c5db199SXin Li
843*9c5db199SXin Li    def Delete(self, path):
844*9c5db199SXin Li        """
845*9c5db199SXin Li        Overriden from messaging.Messaging.
846*9c5db199SXin Li
847*9c5db199SXin Li        @param path
848*9c5db199SXin Li
849*9c5db199SXin Li        """
850*9c5db199SXin Li        self._sms_handler.delete_message(path)
851*9c5db199SXin Li
852*9c5db199SXin Li
853*9c5db199SXin Li    @dbus.service.signal(mm1_constants.I_MODEM_MESSAGING, signature='ob')
854*9c5db199SXin Li    def Added(self, path, received):
855*9c5db199SXin Li        """
856*9c5db199SXin Li        Overriden from messaging.Messaging.
857*9c5db199SXin Li
858*9c5db199SXin Li        @param path
859*9c5db199SXin Li        @param received
860*9c5db199SXin Li
861*9c5db199SXin Li        """
862*9c5db199SXin Li        logging.info('New SMS added: path: ' + path + ' received: ' +
863*9c5db199SXin Li                     str(received))
864*9c5db199SXin Li
865*9c5db199SXin Li
866*9c5db199SXin Li    def _UpdateBearersProperty(self):
867*9c5db199SXin Li        """
868*9c5db199SXin Li        Update the 'Bearers' property on |I_MODEM| interface to match the
869*9c5db199SXin Li        internal list.
870*9c5db199SXin Li
871*9c5db199SXin Li        """
872*9c5db199SXin Li        bearers = dbus.Array(
873*9c5db199SXin Li                [dbus.types.ObjectPath(key) for key in six.iterkeys(self.bearers)],
874*9c5db199SXin Li                signature='o')
875*9c5db199SXin Li        self.Set(mm1_constants.I_MODEM, 'Bearers', bearers)
876