2017-03-28 12:30:28 +00:00
|
|
|
# osmo_gsm_tester: DBUS client to talk to ofono
|
|
|
|
#
|
|
|
|
# Copyright (C) 2016-2017 by sysmocom - s.f.m.c. GmbH
|
|
|
|
#
|
|
|
|
# Author: Neels Hofmeyr <neels@hofmeyr.de>
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
2017-06-03 07:51:45 +00:00
|
|
|
# it under the terms of the GNU General Public License as
|
2017-03-28 12:30:28 +00:00
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2017-06-03 07:51:45 +00:00
|
|
|
# GNU General Public License for more details.
|
2017-03-28 12:30:28 +00:00
|
|
|
#
|
2017-06-03 07:51:45 +00:00
|
|
|
# You should have received a copy of the GNU General Public License
|
2017-03-28 12:30:28 +00:00
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2017-05-30 13:13:29 +00:00
|
|
|
from . import log, test, util, event_loop, sms
|
2017-03-28 12:30:28 +00:00
|
|
|
|
|
|
|
from pydbus import SystemBus, Variant
|
|
|
|
import time
|
|
|
|
import pprint
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
import sys
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-06-14 10:14:53 +00:00
|
|
|
# Required for Gio.Cancellable.
|
|
|
|
# See https://lazka.github.io/pgi-docs/Gio-2.0/classes/Cancellable.html#Gio.Cancellable
|
|
|
|
from gi.module import get_introspection_module
|
|
|
|
Gio = get_introspection_module('Gio')
|
|
|
|
|
2017-03-28 12:30:28 +00:00
|
|
|
from gi.repository import GLib
|
|
|
|
glib_main_loop = GLib.MainLoop()
|
|
|
|
glib_main_ctx = glib_main_loop.get_context()
|
|
|
|
bus = SystemBus()
|
|
|
|
|
2017-05-04 09:38:23 +00:00
|
|
|
I_MODEM = 'org.ofono.Modem'
|
2017-04-09 12:18:34 +00:00
|
|
|
I_NETREG = 'org.ofono.NetworkRegistration'
|
|
|
|
I_SMS = 'org.ofono.MessageManager'
|
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
# See https://github.com/intgr/ofono/blob/master/doc/network-api.txt#L78
|
|
|
|
NETREG_ST_REGISTERED = 'registered'
|
|
|
|
NETREG_ST_ROAMING = 'roaming'
|
|
|
|
|
|
|
|
NETREG_MAX_REGISTER_ATTEMPTS = 3
|
|
|
|
|
2017-05-05 15:52:45 +00:00
|
|
|
class DeferredHandling:
|
|
|
|
defer_queue = []
|
|
|
|
|
|
|
|
def __init__(self, dbus_iface, handler):
|
|
|
|
self.handler = handler
|
2017-05-10 11:24:05 +00:00
|
|
|
self.subscription_id = dbus_iface.connect(self.receive_signal)
|
2017-05-05 15:52:45 +00:00
|
|
|
|
|
|
|
def receive_signal(self, *args, **kwargs):
|
|
|
|
DeferredHandling.defer_queue.append((self.handler, args, kwargs))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def handle_queue():
|
|
|
|
while DeferredHandling.defer_queue:
|
|
|
|
handler, args, kwargs = DeferredHandling.defer_queue.pop(0)
|
|
|
|
handler(*args, **kwargs)
|
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
def defer(handler, *args, **kwargs):
|
|
|
|
DeferredHandling.defer_queue.append((handler, args, kwargs))
|
|
|
|
|
2017-05-05 15:52:45 +00:00
|
|
|
def dbus_connect(dbus_iface, handler):
|
|
|
|
'''This function shall be used instead of directly connecting DBus signals.
|
|
|
|
It ensures that we don't nest a glib main loop within another, and also
|
|
|
|
that we receive exceptions raised within the signal handlers. This makes it
|
|
|
|
so that a signal handler is invoked only after the DBus polling is through
|
|
|
|
by enlisting signals that should be handled in the
|
|
|
|
DeferredHandling.defer_queue.'''
|
2017-05-10 11:24:05 +00:00
|
|
|
return DeferredHandling(dbus_iface, handler).subscription_id
|
2017-05-05 15:52:45 +00:00
|
|
|
|
2017-05-22 14:38:49 +00:00
|
|
|
def poll_glib():
|
2017-03-28 12:30:28 +00:00
|
|
|
global glib_main_ctx
|
|
|
|
while glib_main_ctx.pending():
|
|
|
|
glib_main_ctx.iteration()
|
2017-05-05 15:52:45 +00:00
|
|
|
DeferredHandling.handle_queue()
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-22 14:38:49 +00:00
|
|
|
event_loop.register_poll_func(poll_glib)
|
|
|
|
|
2017-05-03 14:32:16 +00:00
|
|
|
def systembus_get(path):
|
2017-03-28 12:30:28 +00:00
|
|
|
global bus
|
|
|
|
return bus.get('org.ofono', path)
|
|
|
|
|
|
|
|
def list_modems():
|
2017-05-03 14:32:16 +00:00
|
|
|
root = systembus_get('/')
|
2017-03-28 12:30:28 +00:00
|
|
|
return sorted(root.GetModems())
|
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
def _async_result_handler(obj, result, user_data):
|
|
|
|
'''Generic callback dispatcher called from glib loop when an async method
|
|
|
|
call has returned. This callback is set up by method dbus_async_call.'''
|
|
|
|
(result_callback, error_callback, real_user_data) = user_data
|
|
|
|
try:
|
|
|
|
ret = obj.call_finish(result)
|
|
|
|
except Exception as e:
|
2017-06-14 10:14:53 +00:00
|
|
|
if isinstance(e, GLib.Error) and e.code == Gio.IOErrorEnum.CANCELLED:
|
|
|
|
log.dbg('DBus method cancelled')
|
|
|
|
return
|
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
if error_callback:
|
|
|
|
error_callback(obj, e, real_user_data)
|
|
|
|
else:
|
|
|
|
result_callback(obj, e, real_user_data)
|
|
|
|
return
|
|
|
|
|
|
|
|
ret = ret.unpack()
|
|
|
|
# to be compatible with standard Python behaviour, unbox
|
|
|
|
# single-element tuples and return None for empty result tuples
|
|
|
|
if len(ret) == 1:
|
|
|
|
ret = ret[0]
|
|
|
|
elif len(ret) == 0:
|
|
|
|
ret = None
|
|
|
|
result_callback(obj, ret, real_user_data)
|
|
|
|
|
|
|
|
def dbus_async_call(instance, proxymethod, *proxymethod_args,
|
|
|
|
result_handler=None, error_handler=None,
|
2017-06-14 10:14:53 +00:00
|
|
|
user_data=None, timeout=30, cancellable=None,
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
**proxymethod_kwargs):
|
|
|
|
'''pydbus doesn't support asynchronous methods. This method adds support for
|
|
|
|
it until pydbus implements it'''
|
|
|
|
|
|
|
|
argdiff = len(proxymethod_args) - len(proxymethod._inargs)
|
|
|
|
if argdiff < 0:
|
|
|
|
raise TypeError(proxymethod.__qualname__ + " missing {} required positional argument(s)".format(-argdiff))
|
|
|
|
elif argdiff > 0:
|
|
|
|
raise TypeError(proxymethod.__qualname__ + " takes {} positional argument(s) but {} was/were given".format(len(proxymethod._inargs), len(proxymethod_args)))
|
|
|
|
|
|
|
|
timeout = timeout * 1000
|
|
|
|
user_data = (result_handler, error_handler, user_data)
|
|
|
|
|
2017-06-14 10:14:53 +00:00
|
|
|
# See https://lazka.github.io/pgi-docs/Gio-2.0/classes/DBusProxy.html#Gio.DBusProxy.call
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
ret = instance._bus.con.call(
|
|
|
|
instance._bus_name, instance._path,
|
|
|
|
proxymethod._iface_name, proxymethod.__name__,
|
|
|
|
GLib.Variant(proxymethod._sinargs, proxymethod_args),
|
|
|
|
GLib.VariantType.new(proxymethod._soutargs),
|
2017-06-14 10:14:53 +00:00
|
|
|
0, timeout, cancellable,
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
_async_result_handler, user_data)
|
|
|
|
|
2017-08-25 10:58:25 +00:00
|
|
|
def dbus_call_dismiss_error(log_obj, err_str, method):
|
|
|
|
try:
|
|
|
|
method()
|
|
|
|
except Exception as e:
|
|
|
|
if isinstance(e, GLib.Error) and err_str in e.domain:
|
|
|
|
log_obj.log('Dismissed Dbus method error: %r' % e)
|
|
|
|
return
|
|
|
|
raise log.Error('dbus_call_dismiss_error raised error %r' % e)
|
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
class ModemDbusInteraction(log.Origin):
|
|
|
|
'''Work around inconveniences specific to pydbus and ofono.
|
|
|
|
ofono adds and removes DBus interfaces and notifies about them.
|
|
|
|
Upon changes we need a fresh pydbus object to benefit from that.
|
|
|
|
Watching the interfaces change is optional; be sure to call
|
|
|
|
watch_interfaces() if you'd like to have signals subscribed.
|
|
|
|
Related: https://github.com/LEW21/pydbus/issues/56
|
|
|
|
'''
|
|
|
|
|
fix and refactor logging: drop 'with', simplify
With the recent fix of the junit report related issues, another issue arose:
the 'with log.Origin' was changed to disallow __enter__ing an object twice to
fix problems, now still code would fail because it tries to do 'with' on the
same object twice. The only reason is to ensure that logging is associated with
a given object. Instead of complicating even more, implement differently.
Refactor logging to simplify use: drop the 'with Origin' style completely, and
instead use the python stack to determine which objects are created by which,
and which object to associate a log statement with.
The new way: we rely on the convention that each class instance has a local
'self' referencing the object instance. If we need to find an origin as a new
object's parent, or to associate a log message with, we traverse each stack
frame, fetching the first local 'self' object that is a log.Origin class
instance.
How to use:
Simply call log.log() anywhere, and it finds an Origin object to log for, from
the stack. Alternatively call self.log() for any Origin() object to skip the
lookup.
Create classes as child class of log.Origin and make sure to call
super().__init__(category, name). This constructor will magically find a parent
Origin on the stack.
When an exception happens, we first escalate the exception up through call
scopes to where ever it is handled by log.log_exn(). This then finds an Origin
object in the traceback's stack frames, no need to nest in 'with' scopes.
Hence the 'with log.Origin' now "happens implicitly", we can write pure natural
python code, no more hassles with scope ordering.
Furthermore, any frame can place additional logging information in a frame by
calling log.ctx(). This is automatically inserted in the ancestry associated
with a log statement / exception.
Change-Id: I5f9b53150f2bb6fa9d63ce27f0806f0ca6a45e90
2017-06-09 23:18:27 +00:00
|
|
|
modem_path = None
|
|
|
|
watch_props_subscription = None
|
|
|
|
_dbus_obj = None
|
|
|
|
interfaces = None
|
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def __init__(self, modem_path):
|
|
|
|
self.modem_path = modem_path
|
fix and refactor logging: drop 'with', simplify
With the recent fix of the junit report related issues, another issue arose:
the 'with log.Origin' was changed to disallow __enter__ing an object twice to
fix problems, now still code would fail because it tries to do 'with' on the
same object twice. The only reason is to ensure that logging is associated with
a given object. Instead of complicating even more, implement differently.
Refactor logging to simplify use: drop the 'with Origin' style completely, and
instead use the python stack to determine which objects are created by which,
and which object to associate a log statement with.
The new way: we rely on the convention that each class instance has a local
'self' referencing the object instance. If we need to find an origin as a new
object's parent, or to associate a log message with, we traverse each stack
frame, fetching the first local 'self' object that is a log.Origin class
instance.
How to use:
Simply call log.log() anywhere, and it finds an Origin object to log for, from
the stack. Alternatively call self.log() for any Origin() object to skip the
lookup.
Create classes as child class of log.Origin and make sure to call
super().__init__(category, name). This constructor will magically find a parent
Origin on the stack.
When an exception happens, we first escalate the exception up through call
scopes to where ever it is handled by log.log_exn(). This then finds an Origin
object in the traceback's stack frames, no need to nest in 'with' scopes.
Hence the 'with log.Origin' now "happens implicitly", we can write pure natural
python code, no more hassles with scope ordering.
Furthermore, any frame can place additional logging information in a frame by
calling log.ctx(). This is automatically inserted in the ancestry associated
with a log statement / exception.
Change-Id: I5f9b53150f2bb6fa9d63ce27f0806f0ca6a45e90
2017-06-09 23:18:27 +00:00
|
|
|
super().__init__(log.C_BUS, self.modem_path)
|
2017-05-24 18:17:26 +00:00
|
|
|
self.interfaces = set()
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
# A dict listing signal handlers to connect, e.g.
|
|
|
|
# { I_SMS: ( ('IncomingMessage', self._on_incoming_message), ), }
|
|
|
|
self.required_signals = {}
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
# A dict collecting subscription tokens for connected signal handlers.
|
|
|
|
# { I_SMS: ( token1, token2, ... ), }
|
|
|
|
self.connected_signals = util.listdict()
|
|
|
|
|
2017-05-29 02:13:58 +00:00
|
|
|
def cleanup(self):
|
2017-06-23 11:10:38 +00:00
|
|
|
self.set_powered(False)
|
2017-05-24 18:17:26 +00:00
|
|
|
self.unwatch_interfaces()
|
|
|
|
for interface_name in list(self.connected_signals.keys()):
|
|
|
|
self.remove_signals(interface_name)
|
|
|
|
|
2017-05-29 02:13:58 +00:00
|
|
|
def __del__(self):
|
|
|
|
self.cleanup()
|
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def get_new_dbus_obj(self):
|
|
|
|
return systembus_get(self.modem_path)
|
|
|
|
|
|
|
|
def dbus_obj(self):
|
|
|
|
if self._dbus_obj is None:
|
|
|
|
self._dbus_obj = self.get_new_dbus_obj()
|
|
|
|
return self._dbus_obj
|
|
|
|
|
|
|
|
def interface(self, interface_name):
|
|
|
|
try:
|
|
|
|
return self.dbus_obj()[interface_name]
|
|
|
|
except KeyError:
|
fix and refactor logging: drop 'with', simplify
With the recent fix of the junit report related issues, another issue arose:
the 'with log.Origin' was changed to disallow __enter__ing an object twice to
fix problems, now still code would fail because it tries to do 'with' on the
same object twice. The only reason is to ensure that logging is associated with
a given object. Instead of complicating even more, implement differently.
Refactor logging to simplify use: drop the 'with Origin' style completely, and
instead use the python stack to determine which objects are created by which,
and which object to associate a log statement with.
The new way: we rely on the convention that each class instance has a local
'self' referencing the object instance. If we need to find an origin as a new
object's parent, or to associate a log message with, we traverse each stack
frame, fetching the first local 'self' object that is a log.Origin class
instance.
How to use:
Simply call log.log() anywhere, and it finds an Origin object to log for, from
the stack. Alternatively call self.log() for any Origin() object to skip the
lookup.
Create classes as child class of log.Origin and make sure to call
super().__init__(category, name). This constructor will magically find a parent
Origin on the stack.
When an exception happens, we first escalate the exception up through call
scopes to where ever it is handled by log.log_exn(). This then finds an Origin
object in the traceback's stack frames, no need to nest in 'with' scopes.
Hence the 'with log.Origin' now "happens implicitly", we can write pure natural
python code, no more hassles with scope ordering.
Furthermore, any frame can place additional logging information in a frame by
calling log.ctx(). This is automatically inserted in the ancestry associated
with a log statement / exception.
Change-Id: I5f9b53150f2bb6fa9d63ce27f0806f0ca6a45e90
2017-06-09 23:18:27 +00:00
|
|
|
raise log.Error('Modem interface is not available:', interface_name)
|
2017-05-24 18:17:26 +00:00
|
|
|
|
|
|
|
def signal(self, interface_name, signal):
|
|
|
|
return getattr(self.interface(interface_name), signal)
|
|
|
|
|
|
|
|
def watch_interfaces(self):
|
|
|
|
self.unwatch_interfaces()
|
|
|
|
# Note: we are watching the properties on a get_new_dbus_obj() that is
|
|
|
|
# separate from the one used to interact with interfaces. We need to
|
|
|
|
# refresh the pydbus object to interact with Interfaces that have newly
|
|
|
|
# appeared, but exchanging the DBus object to watch Interfaces being
|
|
|
|
# enabled and disabled is racy: we may skip some removals and
|
|
|
|
# additions. Hence do not exchange this DBus object. We don't even
|
|
|
|
# need to store the dbus object used for this, we will not touch it
|
|
|
|
# again. We only store the signal subscription.
|
|
|
|
self.watch_props_subscription = dbus_connect(self.get_new_dbus_obj().PropertyChanged,
|
|
|
|
self.on_property_change)
|
|
|
|
self.on_interfaces_change(self.properties().get('Interfaces'))
|
|
|
|
|
|
|
|
def unwatch_interfaces(self):
|
|
|
|
if self.watch_props_subscription is None:
|
|
|
|
return
|
|
|
|
self.watch_props_subscription.disconnect()
|
|
|
|
self.watch_props_subscription = None
|
|
|
|
|
|
|
|
def on_property_change(self, name, value):
|
|
|
|
if name == 'Interfaces':
|
|
|
|
self.on_interfaces_change(value)
|
2017-09-05 17:04:06 +00:00
|
|
|
else:
|
|
|
|
self.dbg('%r.PropertyChanged() -> %s=%s' % (I_MODEM, name, value))
|
2017-05-24 18:17:26 +00:00
|
|
|
|
|
|
|
def on_interfaces_change(self, interfaces_now):
|
|
|
|
# First some logging.
|
|
|
|
now = set(interfaces_now)
|
|
|
|
additions = now - self.interfaces
|
|
|
|
removals = self.interfaces - now
|
|
|
|
self.interfaces = now
|
|
|
|
if not (additions or removals):
|
|
|
|
# nothing changed.
|
|
|
|
return
|
|
|
|
|
|
|
|
if additions:
|
|
|
|
self.dbg('interface enabled:', ', '.join(sorted(additions)))
|
|
|
|
|
|
|
|
if removals:
|
|
|
|
self.dbg('interface disabled:', ', '.join(sorted(removals)))
|
|
|
|
|
|
|
|
# The dbus object is now stale and needs refreshing before we
|
|
|
|
# access the next interface function.
|
2017-03-28 12:30:28 +00:00
|
|
|
self._dbus_obj = None
|
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
# If an interface disappeared, disconnect the signal handlers for it.
|
|
|
|
# Even though we're going to use a fresh dbus object for new
|
|
|
|
# subscriptions, we will still keep active subscriptions alive on the
|
|
|
|
# old dbus object which will linger, associated with the respective
|
|
|
|
# signal subscription.
|
|
|
|
for removed in removals:
|
|
|
|
self.remove_signals(removed)
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
# Connect signals for added interfaces.
|
|
|
|
for interface_name in additions:
|
|
|
|
self.connect_signals(interface_name)
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def remove_signals(self, interface_name):
|
|
|
|
got = self.connected_signals.pop(interface_name, [])
|
|
|
|
|
|
|
|
if not got:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.dbg('Disconnecting', len(got), 'signals for', interface_name)
|
|
|
|
for subscription in got:
|
|
|
|
subscription.disconnect()
|
|
|
|
|
|
|
|
def connect_signals(self, interface_name):
|
|
|
|
# If an interface was added, it must not have existed before. For
|
|
|
|
# paranoia, make sure we have no handlers for those.
|
|
|
|
self.remove_signals(interface_name)
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
want = self.required_signals.get(interface_name, [])
|
|
|
|
if not want:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.dbg('Connecting', len(want), 'signals for', interface_name)
|
|
|
|
for signal, cb in self.required_signals.get(interface_name, []):
|
|
|
|
subscription = dbus_connect(self.signal(interface_name, signal), cb)
|
|
|
|
self.connected_signals.add(interface_name, subscription)
|
|
|
|
|
|
|
|
def has_interface(self, *interface_names):
|
|
|
|
try:
|
|
|
|
for interface_name in interface_names:
|
|
|
|
self.dbus_obj()[interface_name]
|
|
|
|
result = True
|
|
|
|
except KeyError:
|
|
|
|
result = False
|
|
|
|
self.dbg('has_interface(%s) ==' % (', '.join(interface_names)), result)
|
|
|
|
return result
|
|
|
|
|
|
|
|
def properties(self, iface=I_MODEM):
|
|
|
|
return self.dbus_obj()[iface].GetProperties()
|
|
|
|
|
|
|
|
def property_is(self, name, val, iface=I_MODEM):
|
|
|
|
is_val = self.properties(iface).get(name)
|
|
|
|
self.dbg(name, '==', is_val)
|
|
|
|
return is_val is not None and is_val == val
|
|
|
|
|
|
|
|
def set_bool(self, name, bool_val, iface=I_MODEM):
|
2017-05-02 12:57:57 +00:00
|
|
|
# to make sure any pending signals are received before we send out more DBus requests
|
2017-05-22 14:38:49 +00:00
|
|
|
event_loop.poll()
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-02 12:57:57 +00:00
|
|
|
val = bool(bool_val)
|
|
|
|
self.log('Setting', name, val)
|
2017-05-24 18:17:26 +00:00
|
|
|
self.interface(iface).SetProperty(name, Variant('b', val))
|
2017-05-02 12:57:57 +00:00
|
|
|
|
2017-05-22 14:38:49 +00:00
|
|
|
event_loop.wait(self, self.property_is, name, bool_val)
|
2017-05-02 14:30:18 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def set_powered(self, powered=True):
|
|
|
|
self.set_bool('Powered', powered)
|
2017-05-02 12:57:57 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def set_online(self, online=True):
|
|
|
|
self.set_bool('Online', online)
|
2017-05-02 12:57:57 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def is_powered(self):
|
|
|
|
return self.property_is('Powered', True)
|
2017-05-02 07:39:27 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def is_online(self):
|
|
|
|
return self.property_is('Online', True)
|
2017-03-28 12:30:28 +00:00
|
|
|
|
|
|
|
|
2017-05-10 11:24:05 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
class Modem(log.Origin):
|
|
|
|
'convenience for ofono Modem interaction'
|
|
|
|
msisdn = None
|
|
|
|
sms_received_list = None
|
2017-08-22 17:10:20 +00:00
|
|
|
_ki = None
|
2017-05-10 11:24:05 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def __init__(self, conf):
|
|
|
|
self.conf = conf
|
|
|
|
self.path = conf.get('path')
|
fix and refactor logging: drop 'with', simplify
With the recent fix of the junit report related issues, another issue arose:
the 'with log.Origin' was changed to disallow __enter__ing an object twice to
fix problems, now still code would fail because it tries to do 'with' on the
same object twice. The only reason is to ensure that logging is associated with
a given object. Instead of complicating even more, implement differently.
Refactor logging to simplify use: drop the 'with Origin' style completely, and
instead use the python stack to determine which objects are created by which,
and which object to associate a log statement with.
The new way: we rely on the convention that each class instance has a local
'self' referencing the object instance. If we need to find an origin as a new
object's parent, or to associate a log message with, we traverse each stack
frame, fetching the first local 'self' object that is a log.Origin class
instance.
How to use:
Simply call log.log() anywhere, and it finds an Origin object to log for, from
the stack. Alternatively call self.log() for any Origin() object to skip the
lookup.
Create classes as child class of log.Origin and make sure to call
super().__init__(category, name). This constructor will magically find a parent
Origin on the stack.
When an exception happens, we first escalate the exception up through call
scopes to where ever it is handled by log.log_exn(). This then finds an Origin
object in the traceback's stack frames, no need to nest in 'with' scopes.
Hence the 'with log.Origin' now "happens implicitly", we can write pure natural
python code, no more hassles with scope ordering.
Furthermore, any frame can place additional logging information in a frame by
calling log.ctx(). This is automatically inserted in the ancestry associated
with a log statement / exception.
Change-Id: I5f9b53150f2bb6fa9d63ce27f0806f0ca6a45e90
2017-06-09 23:18:27 +00:00
|
|
|
super().__init__(log.C_TST, self.path)
|
2017-05-24 18:17:26 +00:00
|
|
|
self.sms_received_list = []
|
|
|
|
self.dbus = ModemDbusInteraction(self.path)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
self.register_attempts = 0
|
2017-06-14 10:14:53 +00:00
|
|
|
# one Cancellable can handle several concurrent methods.
|
|
|
|
self.cancellable = Gio.Cancellable.new()
|
2017-05-24 18:17:26 +00:00
|
|
|
self.dbus.required_signals = {
|
2017-05-10 11:24:05 +00:00
|
|
|
I_SMS: ( ('IncomingMessage', self._on_incoming_message), ),
|
2017-05-31 10:05:20 +00:00
|
|
|
I_NETREG: ( ('PropertyChanged', self._on_netreg_property_changed), ),
|
2017-05-10 11:24:05 +00:00
|
|
|
}
|
2017-05-24 18:17:26 +00:00
|
|
|
self.dbus.watch_interfaces()
|
|
|
|
|
2017-05-29 02:13:58 +00:00
|
|
|
def cleanup(self):
|
2017-06-14 10:14:53 +00:00
|
|
|
self.dbg('cleanup')
|
|
|
|
if self.cancellable:
|
|
|
|
self.cancellable.cancel()
|
|
|
|
# Cancel op is applied as a signal coming from glib mainloop, so we
|
|
|
|
# need to run it and wait for the callbacks to handle cancellations.
|
|
|
|
poll_glib()
|
|
|
|
self.cancellable = None
|
2017-05-29 02:13:58 +00:00
|
|
|
self.dbus.cleanup()
|
|
|
|
self.dbus = None
|
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def properties(self, *args, **kwargs):
|
|
|
|
'''Return a dict of properties on this modem. For the actual arguments,
|
|
|
|
see ModemDbusInteraction.properties(), which this function calls. The
|
|
|
|
returned dict is defined by ofono. An example is:
|
|
|
|
{'Lockdown': False,
|
|
|
|
'Powered': True,
|
|
|
|
'Model': 'MC7304',
|
|
|
|
'Revision': 'SWI9X15C_05.05.66.00 r29972 CARMD-EV-FRMWR1 2015/10/08 08:36:28',
|
|
|
|
'Manufacturer': 'Sierra Wireless, Incorporated',
|
|
|
|
'Emergency': False,
|
|
|
|
'Interfaces': ['org.ofono.SmartMessaging',
|
|
|
|
'org.ofono.PushNotification',
|
|
|
|
'org.ofono.MessageManager',
|
|
|
|
'org.ofono.NetworkRegistration',
|
|
|
|
'org.ofono.ConnectionManager',
|
|
|
|
'org.ofono.SupplementaryServices',
|
|
|
|
'org.ofono.RadioSettings',
|
|
|
|
'org.ofono.AllowedAccessPoints',
|
|
|
|
'org.ofono.SimManager',
|
|
|
|
'org.ofono.LocationReporting',
|
|
|
|
'org.ofono.VoiceCallManager'],
|
|
|
|
'Serial': '356853054230919',
|
|
|
|
'Features': ['sms', 'net', 'gprs', 'ussd', 'rat', 'sim', 'gps'],
|
|
|
|
'Type': 'hardware',
|
|
|
|
'Online': True}
|
|
|
|
'''
|
|
|
|
return self.dbus.properties(*args, **kwargs)
|
|
|
|
|
|
|
|
def set_powered(self, powered=True):
|
|
|
|
return self.dbus.set_powered(powered=powered)
|
|
|
|
|
|
|
|
def set_online(self, online=True):
|
|
|
|
return self.dbus.set_online(online=online)
|
|
|
|
|
|
|
|
def is_powered(self):
|
|
|
|
return self.dbus.is_powered()
|
|
|
|
|
|
|
|
def is_online(self):
|
|
|
|
return self.dbus.is_online()
|
2017-05-10 11:24:05 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def set_msisdn(self, msisdn):
|
|
|
|
self.msisdn = msisdn
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def imsi(self):
|
|
|
|
imsi = self.conf.get('imsi')
|
|
|
|
if not imsi:
|
fix and refactor logging: drop 'with', simplify
With the recent fix of the junit report related issues, another issue arose:
the 'with log.Origin' was changed to disallow __enter__ing an object twice to
fix problems, now still code would fail because it tries to do 'with' on the
same object twice. The only reason is to ensure that logging is associated with
a given object. Instead of complicating even more, implement differently.
Refactor logging to simplify use: drop the 'with Origin' style completely, and
instead use the python stack to determine which objects are created by which,
and which object to associate a log statement with.
The new way: we rely on the convention that each class instance has a local
'self' referencing the object instance. If we need to find an origin as a new
object's parent, or to associate a log message with, we traverse each stack
frame, fetching the first local 'self' object that is a log.Origin class
instance.
How to use:
Simply call log.log() anywhere, and it finds an Origin object to log for, from
the stack. Alternatively call self.log() for any Origin() object to skip the
lookup.
Create classes as child class of log.Origin and make sure to call
super().__init__(category, name). This constructor will magically find a parent
Origin on the stack.
When an exception happens, we first escalate the exception up through call
scopes to where ever it is handled by log.log_exn(). This then finds an Origin
object in the traceback's stack frames, no need to nest in 'with' scopes.
Hence the 'with log.Origin' now "happens implicitly", we can write pure natural
python code, no more hassles with scope ordering.
Furthermore, any frame can place additional logging information in a frame by
calling log.ctx(). This is automatically inserted in the ancestry associated
with a log statement / exception.
Change-Id: I5f9b53150f2bb6fa9d63ce27f0806f0ca6a45e90
2017-06-09 23:18:27 +00:00
|
|
|
raise log.Error('No IMSI')
|
2017-05-24 18:17:26 +00:00
|
|
|
return imsi
|
2017-03-28 12:30:28 +00:00
|
|
|
|
2017-08-22 17:10:20 +00:00
|
|
|
def set_ki(self, ki):
|
|
|
|
self._ki = ki
|
|
|
|
|
2017-05-24 18:17:26 +00:00
|
|
|
def ki(self):
|
2017-08-22 17:10:20 +00:00
|
|
|
if self._ki is not None:
|
|
|
|
return self._ki
|
2017-05-24 18:17:26 +00:00
|
|
|
return self.conf.get('ki')
|
2017-04-09 12:18:34 +00:00
|
|
|
|
2017-08-24 14:57:17 +00:00
|
|
|
def auth_algo(self):
|
|
|
|
return self.conf.get('auth_algo', None)
|
|
|
|
|
2017-05-31 10:05:20 +00:00
|
|
|
def _on_netreg_property_changed(self, name, value):
|
|
|
|
self.dbg('%r.PropertyChanged() -> %s=%s' % (I_NETREG, name, value))
|
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
def is_connected(self, mcc_mnc=None):
|
|
|
|
netreg = self.dbus.interface(I_NETREG)
|
|
|
|
prop = netreg.GetProperties()
|
|
|
|
status = prop.get('Status')
|
2017-06-13 14:23:23 +00:00
|
|
|
self.dbg('status:', status)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
if not (status == NETREG_ST_REGISTERED or status == NETREG_ST_ROAMING):
|
|
|
|
return False
|
|
|
|
if mcc_mnc is None: # Any network is fine and we are registered.
|
|
|
|
return True
|
|
|
|
mcc = prop.get('MobileCountryCode')
|
|
|
|
mnc = prop.get('MobileNetworkCode')
|
|
|
|
if (mcc, mnc) == mcc_mnc:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def schedule_scan_register(self, mcc_mnc):
|
|
|
|
if self.register_attempts > NETREG_MAX_REGISTER_ATTEMPTS:
|
2017-06-13 14:55:31 +00:00
|
|
|
raise log.Error('Failed to find Network Operator', mcc_mnc=mcc_mnc, attempts=self.register_attempts)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
self.register_attempts += 1
|
|
|
|
netreg = self.dbus.interface(I_NETREG)
|
|
|
|
self.dbg('Scanning for operators...')
|
|
|
|
# Scan method can take several seconds, and we don't want to block
|
|
|
|
# waiting for that. Make it async and try to register when the scan is
|
|
|
|
# finished.
|
|
|
|
register_func = self.scan_cb_register_automatic if mcc_mnc is None else self.scan_cb_register
|
|
|
|
result_handler = lambda obj, result, user_data: defer(register_func, result, user_data)
|
2017-06-13 14:23:23 +00:00
|
|
|
error_handler = lambda obj, e, user_data: defer(self.scan_cb_error_handler, e, mcc_mnc)
|
2017-06-14 10:14:53 +00:00
|
|
|
dbus_async_call(netreg, netreg.Scan, timeout=30, cancellable=self.cancellable,
|
|
|
|
result_handler=result_handler, error_handler=error_handler,
|
|
|
|
user_data=mcc_mnc)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
|
2017-06-13 14:23:23 +00:00
|
|
|
def scan_cb_error_handler(self, e, mcc_mnc):
|
|
|
|
# It was detected that Scan() method can fail for some modems on some
|
|
|
|
# specific circumstances. For instance it fails with org.ofono.Error.Failed
|
|
|
|
# if the modem starts to register internally after we started Scan() and
|
|
|
|
# the registering succeeds while we are still waiting for Scan() to finsih.
|
|
|
|
# So far the easiest seems to check if we are now registered and
|
|
|
|
# otherwise schedule a scan again.
|
2017-06-13 14:59:19 +00:00
|
|
|
self.err('Scan() failed, retrying if needed:', e)
|
2017-06-13 14:23:23 +00:00
|
|
|
if not self.is_connected(mcc_mnc):
|
|
|
|
self.schedule_scan_register(mcc_mnc)
|
2017-06-13 14:59:19 +00:00
|
|
|
else:
|
|
|
|
self.log('Already registered with network', mcc_mnc)
|
2017-06-13 14:23:23 +00:00
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
def scan_cb_register_automatic(self, scanned_operators, mcc_mnc):
|
|
|
|
self.dbg('scanned operators: ', scanned_operators);
|
|
|
|
for op_path, op_prop in scanned_operators:
|
|
|
|
if op_prop.get('Status') == 'current':
|
|
|
|
mcc = op_prop.get('MobileCountryCode')
|
|
|
|
mnc = op_prop.get('MobileNetworkCode')
|
|
|
|
self.log('Already registered with network', (mcc, mnc))
|
|
|
|
return
|
|
|
|
self.log('Registering with the default network')
|
|
|
|
netreg = self.dbus.interface(I_NETREG)
|
2017-08-25 10:58:25 +00:00
|
|
|
dbus_call_dismiss_error(self, 'org.ofono.Error.InProgress', netreg.Register)
|
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
|
|
|
|
def scan_cb_register(self, scanned_operators, mcc_mnc):
|
|
|
|
self.dbg('scanned operators: ', scanned_operators);
|
|
|
|
matching_op_path = None
|
|
|
|
for op_path, op_prop in scanned_operators:
|
|
|
|
mcc = op_prop.get('MobileCountryCode')
|
|
|
|
mnc = op_prop.get('MobileNetworkCode')
|
|
|
|
if (mcc, mnc) == mcc_mnc:
|
|
|
|
if op_prop.get('Status') == 'current':
|
|
|
|
self.log('Already registered with network', mcc_mnc)
|
|
|
|
# We discovered the network and we are already registered
|
|
|
|
# with it. Avoid calling op.Register() in this case (it
|
|
|
|
# won't act as a NO-OP, it actually returns an error).
|
|
|
|
return
|
|
|
|
matching_op_path = op_path
|
|
|
|
break
|
|
|
|
if matching_op_path is None:
|
|
|
|
self.dbg('Failed to find Network Operator', mcc_mnc=mcc_mnc, attempts=self.register_attempts)
|
|
|
|
self.schedule_scan_register(mcc_mnc)
|
|
|
|
return
|
|
|
|
dbus_op = systembus_get(matching_op_path)
|
|
|
|
self.log('Registering with operator', matching_op_path, mcc_mnc)
|
2017-08-25 10:58:25 +00:00
|
|
|
dbus_call_dismiss_error(self, 'org.ofono.Error.InProgress', dbus_op.Register)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
|
|
|
|
def power_cycle(self):
|
|
|
|
'Power the modem and put it online, power cycle it if it was already on'
|
2017-05-24 18:17:26 +00:00
|
|
|
if self.is_powered():
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
self.dbg('Power cycling')
|
2017-05-04 09:37:16 +00:00
|
|
|
self.set_online(False)
|
|
|
|
self.set_powered(False)
|
2017-05-24 18:17:26 +00:00
|
|
|
event_loop.wait(self, lambda: not self.dbus.has_interface(I_NETREG, I_SMS), timeout=10)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
else:
|
|
|
|
self.dbg('Powering on')
|
2017-04-09 12:18:34 +00:00
|
|
|
self.set_powered()
|
2017-05-02 07:39:27 +00:00
|
|
|
self.set_online()
|
2017-05-24 18:17:26 +00:00
|
|
|
event_loop.wait(self, self.dbus.has_interface, I_NETREG, I_SMS, timeout=10)
|
2017-04-09 12:18:34 +00:00
|
|
|
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
def connect(self, mcc_mnc=None):
|
|
|
|
'Connect to MCC+MNC'
|
|
|
|
if (mcc_mnc is not None) and (len(mcc_mnc) != 2 or None in mcc_mnc):
|
2017-06-13 14:55:31 +00:00
|
|
|
raise log.Error('mcc_mnc value is invalid. It should be None or contain both valid mcc and mnc values:', mcc_mnc=mcc_mnc)
|
ofono_client: Implement network registration during connect()
A new mcc_mnc parameter is now optionally passed to connect() in order
to manually register to a specific network with a given MCC+MNC pair.
If no parameter is passed (or None), then the modem will be instructed
to attempt an automatic registration with any available network which
permits it.
We get the MCC+MNC parameter from the MSC/NITB and we pass it to the
modem object at connect time as shown in the modified tests. Two new
simple tests to check network registration is working are added in this
commit.
Ofono modems seem to be automatically registering at some point after
they are set Online=true, and we were actually using that 'feature'
before this patch. Thus, it is possible that a modem quickly becomes
registered, and we then check so before starting the scan+registration
process, which can take a few seconds.
The scanning method can take a few seconds to complete. To avoid
blocking in the dbus ofono Scan() method, this commit adds some code to
make use of glib/gdbus async methods, which are not yet supported
directly by pydbus. This way, we can continue polling while waiting for
the scan process to complete and we can register several modems in
parallel. When scan completes, a callback is run which attempts to
register. If no MCC+MNC was passed, as we just finished scanning the
modem should have enough fresh operator information to take good and
quick decisions on where to connect. If we have an MCC+MNC, then we check
the operator list received by Scan() method. If operator with desired
MCC+MNC is there, we register with it. If it's not there, we start
scanning() again asynchronously hoping the operator will show up in next
scan.
As scanning() and registration is done in the background, tests are
expected to call connect(), and then later on wait for the modem to
register by waiting/polling the method "modem.is_connected()". Tests
first check for the modem being connected and after with MSC
subscriber_attached(). The order is intentional because the later has to
poll through network and adds unneeded garbage to the pcap files bein
recorded.
Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
2017-05-29 12:25:22 +00:00
|
|
|
self.power_cycle()
|
|
|
|
self.register_attempts = 0
|
|
|
|
if self.is_connected(mcc_mnc):
|
|
|
|
self.log('Already registered with', mcc_mnc if mcc_mnc else 'default network')
|
|
|
|
else:
|
|
|
|
self.log('Connect to', mcc_mnc if mcc_mnc else 'default network')
|
|
|
|
self.schedule_scan_register(mcc_mnc)
|
|
|
|
|
2017-05-25 02:33:53 +00:00
|
|
|
def sms_send(self, to_msisdn_or_modem, *tokens):
|
|
|
|
if isinstance(to_msisdn_or_modem, Modem):
|
|
|
|
to_msisdn = to_msisdn_or_modem.msisdn
|
|
|
|
tokens = list(tokens)
|
|
|
|
tokens.append('to ' + to_msisdn_or_modem.name())
|
|
|
|
else:
|
|
|
|
to_msisdn = str(to_msisdn_or_modem)
|
2017-05-30 13:13:29 +00:00
|
|
|
msg = sms.Sms(self.msisdn, to_msisdn, 'from ' + self.name(), *tokens)
|
|
|
|
self.log('sending sms to MSISDN', to_msisdn, sms=msg)
|
2017-05-24 18:17:26 +00:00
|
|
|
mm = self.dbus.interface(I_SMS)
|
2017-05-30 13:13:29 +00:00
|
|
|
mm.SendMessage(to_msisdn, str(msg))
|
|
|
|
return msg
|
2017-04-09 12:18:34 +00:00
|
|
|
|
|
|
|
def _on_incoming_message(self, message, info):
|
2017-05-06 20:42:57 +00:00
|
|
|
self.log('Incoming SMS:', repr(message))
|
2017-05-06 20:43:32 +00:00
|
|
|
self.dbg(info=info)
|
2017-05-02 14:29:09 +00:00
|
|
|
self.sms_received_list.append((message, info))
|
2017-04-09 12:18:34 +00:00
|
|
|
|
2017-05-30 13:13:29 +00:00
|
|
|
def sms_was_received(self, sms_obj):
|
2017-05-02 14:29:09 +00:00
|
|
|
for msg, info in self.sms_received_list:
|
2017-05-30 13:13:29 +00:00
|
|
|
if sms_obj.matches(msg):
|
2017-05-06 20:42:57 +00:00
|
|
|
self.log('SMS received as expected:', repr(msg))
|
2017-05-06 20:43:32 +00:00
|
|
|
self.dbg(info=info)
|
2017-05-02 14:29:09 +00:00
|
|
|
return True
|
|
|
|
return False
|
2017-04-09 12:18:34 +00:00
|
|
|
|
2017-09-05 16:46:34 +00:00
|
|
|
def info(self, keys=('Manufacturer', 'Model', 'Revision', 'Serial')):
|
2017-05-29 01:45:24 +00:00
|
|
|
props = self.properties()
|
|
|
|
return ', '.join(['%s: %r'%(k,props.get(k)) for k in keys])
|
|
|
|
|
|
|
|
def log_info(self, *args, **kwargs):
|
|
|
|
self.log(self.info(*args, **kwargs))
|
|
|
|
|
2017-03-28 12:30:28 +00:00
|
|
|
# vim: expandtab tabstop=4 shiftwidth=4
|