19d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
29d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le# Use of this source code is governed by a BSD-style license that can be
39d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le# found in the LICENSE file.
49d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
59d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le"""
69d632a90777f69bb476c06be35a61d5fc338c8b3Thieu LeThis module provides bindings for ModemManager1.
79d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
89d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le"""
99d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
109d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Leimport dbus
119d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Leimport dbus.mainloop.glib
129d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
139d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Lefrom autotest_lib.client.bin import utils
149d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Lefrom autotest_lib.client.cros.cellular import mm1_constants
159d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
169d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
17c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhudef _is_unknown_dbus_binding_exception(e):
18c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    return (isinstance(e, dbus.exceptions.DBusException) and
19c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            e.get_dbus_name() in [mm1_constants.DBUS_SERVICE_UNKNOWN,
20c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                                  mm1_constants.DBUS_UNKNOWN_METHOD,
21c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                                  mm1_constants.DBUS_UNKNOWN_OBJECT,
22c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                                  mm1_constants.DBUS_UNKNOWN_INTERFACE])
23c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
24c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
259d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Leclass ModemManager1ProxyError(Exception):
269d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    """Exceptions raised by ModemManager1ProxyError and it's children."""
279d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    pass
289d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
299d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
309d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Leclass ModemManager1Proxy(object):
319d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    """A wrapper around a DBus proxy for ModemManager1."""
329d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
339d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    # Amount of time to wait between attempts to connect to ModemManager1.
349d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    CONNECT_WAIT_INTERVAL_SECONDS = 0.2
359d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
369d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @classmethod
3716f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le    def get_proxy(cls, bus=None, timeout_seconds=10):
389d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """Connect to ModemManager1 over DBus, retrying if necessary.
399d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
409d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        After connecting to ModemManager1, this method will verify that
419d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        ModemManager1 is answering RPCs.
429d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
4316f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le        @param bus: D-Bus bus to use, or specify None and this object will
4416f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le            create a mainloop and bus.
459d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @param timeout_seconds: float number of seconds to try connecting
469d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            A value <= 0 will cause the method to return immediately,
479d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            without trying to connect.
489d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @return a ModemManager1Proxy instance if we connected, or None
499d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            otherwise.
509d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @raise ModemManager1ProxyError if it fails to connect to
519d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            ModemManager1.
529d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
539d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """
5416f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le        def _connect_to_mm1(bus):
559d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            try:
569d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                # We create instance of class on which this classmethod was
579d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                # called. This way, calling
589d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                # SubclassOfModemManager1Proxy.get_proxy() will get a proxy of
599d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                # the right type.
6016f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le                return cls(bus=bus)
619d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            except dbus.exceptions.DBusException as e:
62c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                if _is_unknown_dbus_binding_exception(e):
63c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                    return None
64c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                raise ModemManager1ProxyError(
65c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                        'Error connecting to ModemManager1. DBus error: |%s|',
66c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                        repr(e))
679d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
689d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        utils.poll_for_condition(
6916f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le            lambda: _connect_to_mm1(bus) is not None,
709d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            exception=ModemManager1ProxyError(
719d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                    'Timed out connecting to ModemManager1'),
729d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            timeout=timeout_seconds,
739d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            sleep_interval=ModemManager1Proxy.CONNECT_WAIT_INTERVAL_SECONDS)
7416f7eebb7d05cdfb4f7dd96316085805291b16b0Thieu Le        connection = _connect_to_mm1(bus)
759d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
769d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        # Check to make sure ModemManager1 is responding to DBus requests by
779d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        # setting the logging to debug.
789d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        connection.manager.SetLogging('DEBUG', timeout=timeout_seconds)
799d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
809d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return connection
819d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
829d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
839d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def __init__(self, bus=None):
849d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        if bus is None:
859d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
869d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            bus = dbus.SystemBus()
879d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        self._bus = bus
889d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        self._manager = dbus.Interface(
899d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                self._bus.get_object(mm1_constants.I_MODEM_MANAGER,
909d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                                     mm1_constants.MM1),
919d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                mm1_constants.I_MODEM_MANAGER)
929d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
939d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
949d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
959d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def manager(self):
969d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return the DBus ModemManager1 Manager object."""
979d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return self._manager
989d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
999d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1009d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def get_modem(self):
1019d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """
1029d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        Return the one and only modem object.
1039d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1049d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        This method distinguishes between no modem and more than one modem.
1059d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        In the former, this could happen if the modem has not yet surfaced and
1069d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        is not really considered an error. The caller can wait for the modem
1079d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        by repeatedly calling this method. In the latter, it is a clear error
1089d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        condition and an exception will be raised.
1099d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1109d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        Every call to |get_modem| obtains a fresh DBus proxy for the modem. So,
1119d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        if the modem DBus object has changed between two calls to this method,
1129d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        the proxy returned will be for the currently exported modem.
1139d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1149d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @return a ModemProxy object.  Return None if no modem is found.
1159d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @raise ModemManager1ProxyError unless exactly one modem is found.
1169d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1179d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """
1189d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        try:
1199d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            object_manager = dbus.Interface(
1209d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                self._bus.get_object(mm1_constants.I_MODEM_MANAGER,
1219d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                                     mm1_constants.MM1),
1229d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                mm1_constants.I_OBJECT_MANAGER)
1239d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            modems = object_manager.GetManagedObjects()
1249d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        except dbus.exceptions.DBusException as e:
1259d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            raise ModemManager1ProxyError(
1269d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                    'Failed to list the available modems. DBus error: |%s|',
1279d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                    repr(e))
1289d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1299d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        if not modems:
1309d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            return None
1319d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        elif len(modems) > 1:
1329d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            raise ModemManager1ProxyError(
1339d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                    'Expected one modem object, found %d', len(modems))
1349d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1359d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        modem_proxy = ModemProxy(self._bus, modems.keys()[0])
1369d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        # Check that this object is valid
1379d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        try:
1389d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            modem_proxy.modem.GetAll(mm1_constants.I_MODEM,
1399d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                                     dbus_interface=mm1_constants.I_PROPERTIES)
1409d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            return modem_proxy
1419d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        except dbus.exceptions.DBusException as e:
142c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            if _is_unknown_dbus_binding_exception(e):
143c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                return None
1449d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            raise ModemManager1ProxyError(
1459d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                    'Failed to obtain dbus object for the modem. DBus error: '
1469d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                    '|%s|', repr(e))
1479d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1489d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1498f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le    def wait_for_modem(self, timeout_seconds):
1508f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        """
1518f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        Wait for the modem to appear.
1528f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le
1538f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        @param timeout_seconds: Number of seconds to wait for modem to appear.
1548f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        @return a ModemProxy object.
1558f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        @raise ModemManager1ProxyError if no modem is found within the timeout
1568f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le                or if more than one modem is found. NOTE: This method does not
1578f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le                wait for a second modem. The exception is raised if there is
1588f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le                more than one modem at the time of polling.
1598f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le
1608f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        """
1618f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le        return utils.poll_for_condition(
1628f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le                self.get_modem,
1638f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le                exception=ModemManager1ProxyError('No modem found'),
1648f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le                timeout=timeout_seconds)
1658f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le
1668f87650ea068c2b1a7ed5e8d5818f236dd13c8fcThieu Le
1679d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Leclass ModemProxy(object):
1689d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    """A wrapper around a DBus proxy for ModemManager1 modem object."""
1699d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1709d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    # Amount of time to wait for a state transition.
1719d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    STATE_TRANSITION_WAIT_SECONDS = 10
1729d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1739d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def __init__(self, bus, path):
1749d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        self._bus = bus
1759d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        self._modem = self._bus.get_object(mm1_constants.I_MODEM_MANAGER, path)
1769d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1779d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1789d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
1799d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def modem(self):
1809d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return the DBus modem object."""
1819d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return self._modem
1829d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1839d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1849d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
1859d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def iface_modem(self):
1869d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return org.freedesktop.ModemManager1.Modem DBus interface."""
1879d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return dbus.Interface(self._modem, mm1_constants.I_MODEM)
1889d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1899d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1909d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
1919d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def iface_simple_modem(self):
1929d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return org.freedesktop.ModemManager1.Simple DBus interface."""
1939d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return dbus.Interface(self._modem, mm1_constants.I_MODEM_SIMPLE)
1949d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1959d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
1969d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
1979d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def iface_gsm_modem(self):
1989d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return org.freedesktop.ModemManager1.Modem3gpp DBus interface."""
1999d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return dbus.Interface(self._modem, mm1_constants.I_MODEM_3GPP)
2009d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2019d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2029d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
2039d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def iface_cdma_modem(self):
2049d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return org.freedesktop.ModemManager1.ModemCdma DBus interface."""
2059d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return dbus.Interface(self._modem, mm1_constants.I_MODEM_CDMA)
2069d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2079d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2089d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    @property
2099d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def iface_properties(self):
2109d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """@return org.freedesktop.DBus.Properties DBus interface."""
2119d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return dbus.Interface(self._modem, dbus.PROPERTIES_IFACE)
2129d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2139d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2149d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def properties(self, iface):
2159d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """Return the properties associated with the specified interface.
2169d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2179d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @param iface: Name of interface to retrieve the properties from.
2189d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @return array of properties.
2199d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2209d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """
2219d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        return self.iface_properties.GetAll(iface)
2229d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2239d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
224c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    def get_sim(self):
225c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """
226c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        Return the SIM proxy object associated with this modem.
227c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
228c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        @return SimProxy object or None if no SIM exists.
229c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
230c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """
231c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        sim_path = self.properties(mm1_constants.I_MODEM).get('Sim')
232c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        if not sim_path:
233c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            return None
234c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        sim_proxy = SimProxy(self._bus, sim_path)
235c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        # Check that this object is valid
236c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        try:
237c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            sim_proxy.properties(mm1_constants.I_SIM)
238c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            return sim_proxy
239c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        except dbus.exceptions.DBusException as e:
240c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            if _is_unknown_dbus_binding_exception(e):
241c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                return None
242c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu            raise ModemManager1ProxyError(
243c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                    'Failed to obtain dbus object for the SIM. DBus error: '
244c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu                    '|%s|', repr(e))
245c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
246c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
2479d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le    def wait_for_states(self, states,
2489d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        timeout_seconds=STATE_TRANSITION_WAIT_SECONDS):
2499d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """
2509d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        Wait for the modem to transition to a state in |states|.
2519d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2529d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        This method does not support transitory states (eg. enabling,
2539d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        disabling, connecting, disconnecting, etc).
2549d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2559d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @param states: List of states the modem can transition to.
2569d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @param timeout_seconds: Max number of seconds to wait.
2579d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        @raise ModemManager1ProxyError if the modem does not transition to
2589d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            one of the accepted states.
2599d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2609d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        """
2619d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        for state in states:
2629d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le            if state in [mm1_constants.MM_MODEM_STATE_INITIALIZING,
2639d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                         mm1_constants.MM_MODEM_STATE_DISABLING,
2649d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                         mm1_constants.MM_MODEM_STATE_ENABLING,
2659d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                         mm1_constants.MM_MODEM_STATE_SEARCHING,
2669d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                         mm1_constants.MM_MODEM_STATE_DISCONNECTING,
2679d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                         mm1_constants.MM_MODEM_STATE_CONNECTING]:
2689d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                raise ModemManager1ProxyError(
2699d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        'wait_for_states() does not support transitory states.')
2709d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2719d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le        utils.poll_for_condition(
2729d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                lambda: self.properties(mm1_constants.I_MODEM)[
2739d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        mm1_constants.MM_MODEM_PROPERTY_NAME_STATE] in states,
2749d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                exception=ModemManager1ProxyError(
2759d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        'Timed out waiting for modem to enter one of these '
2769d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        'states: %s, current state=%s',
2779d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        states,
2789d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                        self.properties(mm1_constants.I_MODEM)[
2799d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                                mm1_constants.MM_MODEM_PROPERTY_NAME_STATE]),
2809d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le                timeout=timeout_seconds)
2819d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
2829d632a90777f69bb476c06be35a61d5fc338c8b3Thieu Le
283c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhuclass SimProxy(object):
284c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    """A wrapper around a DBus proxy for ModemManager1 SIM object."""
285c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
286c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    def __init__(self, bus, path):
287c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        self._bus = bus
288c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        self._sim = self._bus.get_object(mm1_constants.I_MODEM_MANAGER, path)
289c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
290c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
291c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    @property
292c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    def sim(self):
293c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """@return the DBus SIM object."""
294c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        return self._sim
295c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
296c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
297c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    @property
298c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    def iface_properties(self):
299c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """@return org.freedesktop.DBus.Properties DBus interface."""
300c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        return dbus.Interface(self._sim, dbus.PROPERTIES_IFACE)
301c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
302c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
303c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    @property
304c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    def iface_sim(self):
305c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """@return org.freedesktop.ModemManager1.Sim DBus interface."""
306c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        return dbus.Interface(self._sim, mm1_constants.I_SIM)
307c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
308c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
309c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu    def properties(self, iface=mm1_constants.I_SIM):
310c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """Return the properties associated with the specified interface.
311c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
312c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        @param iface: Name of interface to retrieve the properties from.
313c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        @return array of properties.
314c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu
315c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        """
316c62e556725820b3c37c175b7bac8496e42020d4cPrathmesh Prabhu        return self.iface_properties.GetAll(iface)
317