[PATCH] osmo-gsm-tester[master]: ofono_client: Implement network registration during connect()

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Pau Espin Pedrol gerrit-no-reply at lists.osmocom.org
Tue Jun 6 13:53:20 UTC 2017


Hello Neels Hofmeyr, Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/2779

to look at the new patch set (#7).

ofono_client: Implement network registration during connect()

Also add a new simple test to check network registration is working

Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
---
M src/osmo_gsm_tester/ofono_client.py
M src/osmo_gsm_tester/osmo_msc.py
M src/osmo_gsm_tester/osmo_nitb.py
M suites/aoip_debug/interactive.py
M suites/aoip_sms/mo_mt_sms.py
M suites/debug/interactive.py
A suites/netreg/register.py
A suites/netreg/register_default.py
A suites/netreg/suite.conf
M suites/sms/mo_mt_sms.py
10 files changed, 223 insertions(+), 9 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/79/2779/7

diff --git a/src/osmo_gsm_tester/ofono_client.py b/src/osmo_gsm_tester/ofono_client.py
index 46300ec..394220f 100644
--- a/src/osmo_gsm_tester/ofono_client.py
+++ b/src/osmo_gsm_tester/ofono_client.py
@@ -22,6 +22,7 @@
 from pydbus import SystemBus, Variant
 import time
 import pprint
+import sys
 
 from gi.repository import GLib
 glib_main_loop = GLib.MainLoop()
@@ -31,6 +32,12 @@
 I_MODEM = 'org.ofono.Modem'
 I_NETREG = 'org.ofono.NetworkRegistration'
 I_SMS = 'org.ofono.MessageManager'
+
+# 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
 
 class DeferredHandling:
     defer_queue = []
@@ -72,6 +79,55 @@
 def list_modems():
     root = systembus_get('/')
     return sorted(root.GetModems())
+
+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:
+        etype, e = sys.exc_info()[:2]
+        # return exception as value
+        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(proxymethod, instance,
+                  *proxymethod_args,
+                  result_handler=None, error_handler=None,
+                  user_data=None, timeout=30,
+                  **proxymethod_kwargs):
+
+#def dbus_async_call(proxymethod, instance, *args, **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)
+
+    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),
+        0, timeout, None,
+        _async_result_handler, user_data)
 
 class ModemDbusInteraction(log.Origin):
     '''Work around inconveniences specific to pydbus and ofono.
@@ -255,8 +311,10 @@
         self.path = conf.get('path')
         self.set_name(self.path)
         self.set_log_category(log.C_TST)
+        self.mcc_mnc = None
         self.sms_received_list = []
         self.dbus = ModemDbusInteraction(self.path)
+        self.register_attempts = 0
         self.dbus.required_signals = {
                 I_SMS: ( ('IncomingMessage', self._on_incoming_message), ),
                 I_NETREG: ( ('PropertyChanged', self._on_netreg_property_changed), ),
@@ -323,9 +381,71 @@
     def _on_netreg_property_changed(self, name, value):
         self.dbg('%r.PropertyChanged() -> %s=%s' % (I_NETREG, name, value))
 
-    def connect(self, nitb):
-        'set the modem up to connect to MCC+MNC from NITB config'
-        self.log('connect to', nitb)
+    def is_connected(self, mcc_mnc=None):
+        nr = self.dbus.interface(I_NETREG)
+        prop = nr.GetProperties()
+        status = prop.get('Status')
+        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):
+        if self.register_attempts > NETREG_MAX_REGISTER_ATTEMPTS:
+            self.raise_exn('Failed to find Network Operator', mcc_mnc=self.mcc_mnc, attempts=self.register_attempts)
+        self.register_attempts += 1
+        nr = 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.
+        dbus_async_call(nr.Scan, nr, timeout=30, result_handler=self.scan_result_cb,
+                        error_handler=self.scan_error_cb, user_data=None)
+
+    def scan_error_cb(self, obj, e, user_data):
+        self.raise_exn('Scan() failed:', e)
+
+    def scan_result_cb(self, obj, result, user_data):
+        self.register(result)
+
+    def register(self, scanned_operators):
+        if self.mcc_mnc is None:
+            if not self.is_connected():
+                self.log('Registering with the default network...')
+                nr = self.dbus.interface(I_NETREG)
+                nr.Register()
+            else:
+                self.log('Already registered with the network')
+            return
+        self.dbg('scanned operators: ', scanned_operators);
+        myop = None
+        for op in scanned_operators:
+            op_path, op_prop = op
+            mcc = op_prop.get('MobileCountryCode')
+            mnc = op_prop.get('MobileNetworkCode')
+            if (mcc, mnc) == self.mcc_mnc:
+                if op_prop.get('Status') == 'current':
+                    self.log('Already registered with the network')
+                    # return and not try to re-connect, otherwise dbus method returns a fail
+                    return
+                myop = op_path
+                break
+        if myop is None:
+            self.dbg('Failed to find Network Operator', mcc_mnc=self.mcc_mnc, attempts=self.register_attempts)
+            self.schedule_scan_register()
+            return
+        dbus_op = systembus_get(myop)
+        self.log('Registering with operator', myop)
+        dbus_op.Register()
+
+    def power_cycle(self):
+        'Power the modem and put it online'
+        self.dbg('Powering on')
         if self.is_powered():
             self.dbg('is powered')
             self.set_online(False)
@@ -335,6 +455,19 @@
         self.set_online()
         event_loop.wait(self, self.dbus.has_interface, I_NETREG, I_SMS, timeout=10)
 
+    def connect(self, mcc_mnc=None):
+        'Connect to MCC+MNC from NITB config'
+        if mcc_mnc is not None and (len(mcc_mnc) != 2 or None in mcc_mnc):
+            self.raise_exn('mcc_mnc value is invalid. It should be None or contain both valid mcc and mnc values:', mcc_mnc=mcc_mnc)
+        self.mcc_mnc = mcc_mnc
+        self.power_cycle()
+        self.log('connect to', self.mcc_mnc if self.mcc_mnc else 'default network')
+        self.register_attempts = 0
+        if self.is_connected(self.mcc_mnc):
+            self.log('Already registered with the network')
+        else:
+            self.schedule_scan_register()
+
     def sms_send(self, to_msisdn_or_modem, *tokens):
         if isinstance(to_msisdn_or_modem, Modem):
             to_msisdn = to_msisdn_or_modem.msisdn
diff --git a/src/osmo_gsm_tester/osmo_msc.py b/src/osmo_gsm_tester/osmo_msc.py
index ca0e246..b2507c8 100644
--- a/src/osmo_gsm_tester/osmo_msc.py
+++ b/src/osmo_gsm_tester/osmo_msc.py
@@ -37,6 +37,7 @@
         self.set_name('osmo-msc_%s' % ip_address.get('addr'))
         self.hlr = hlr
         self.mgcpgw = mgcpgw
+        self.config = None
 
     def start(self):
         self.log('Starting osmo-msc')
@@ -72,6 +73,7 @@
         config.overlay(values, self.suite_run.config())
         config.overlay(values, dict(msc=dict(ip_address=self.ip_address)))
         config.overlay(values, self.mgcpgw.conf_for_msc())
+        self.config = values
 
         self.dbg('MSC CONFIG:\n' + pprint.pformat(values))
 
@@ -83,6 +85,15 @@
     def addr(self):
         return self.ip_address.get('addr')
 
+    def mcc(self):
+        return self.config['msc']['net']['mcc']
+
+    def mnc(self):
+        return self.config['msc']['net']['mnc']
+
+    def mcc_mnc(self):
+        return (self.mcc(), self.mnc())
+
     def subscriber_attached(self, *modems):
         return self.imsi_attached(*[m.imsi() for m in modems])
 
diff --git a/src/osmo_gsm_tester/osmo_nitb.py b/src/osmo_gsm_tester/osmo_nitb.py
index b2ddfb7..b4bf247 100644
--- a/src/osmo_gsm_tester/osmo_nitb.py
+++ b/src/osmo_gsm_tester/osmo_nitb.py
@@ -76,6 +76,7 @@
         for bts in self.bts:
             bts_list.append(bts.conf_for_bsc())
         config.overlay(values, dict(nitb=dict(net=dict(bts_list=bts_list))))
+        self.config = values
 
         self.dbg('NITB CONFIG:\n' + pprint.pformat(values))
 
@@ -91,6 +92,15 @@
         self.bts.append(bts)
         bts.set_bsc(self)
 
+    def mcc(self):
+        return self.config['nitb']['net']['mcc']
+
+    def mnc(self):
+        return self.config['nitb']['net']['mnc']
+
+    def mcc_mnc(self):
+        return (self.mcc(), self.mnc())
+
     def subscriber_add(self, modem, msisdn=None):
         if msisdn is None:
             msisdn = self.suite_run.resources_pool.next_msisdn(modem)
diff --git a/suites/aoip_debug/interactive.py b/suites/aoip_debug/interactive.py
index 7cc1b76..cfedd3a 100755
--- a/suites/aoip_debug/interactive.py
+++ b/suites/aoip_debug/interactive.py
@@ -18,7 +18,7 @@
 
 for m in modems:
   hlr.subscriber_add(m)
-  m.connect(bsc)
+  m.connect(msc.mcc_mnc())
 
 while True:
   cmd = prompt('Enter command: (q)uit (s)ms (g)et-registered (w)ait-registered')
@@ -30,6 +30,8 @@
     break
   elif 'wait-registered'.startswith(cmd):
     try:
+      for m in modems:
+          wait(m.is_connected, msc.mcc_mnc())
       wait(msc.subscriber_attached, *modems)
     except Timeout:
       print('Timeout while waiting for registration.')
diff --git a/suites/aoip_sms/mo_mt_sms.py b/suites/aoip_sms/mo_mt_sms.py
index b9383ea..8eba842 100755
--- a/suites/aoip_sms/mo_mt_sms.py
+++ b/suites/aoip_sms/mo_mt_sms.py
@@ -21,13 +21,15 @@
 hlr.subscriber_add(ms_mo)
 hlr.subscriber_add(ms_mt)
 
-ms_mo.connect(bsc)
-ms_mt.connect(bsc)
+ms_mo.connect(msc.mcc_mnc())
+ms_mt.connect(msc.mcc_mnc())
 
 ms_mo.log_info()
 ms_mt.log_info()
 
 print('waiting for modems to attach...')
+wait(ms_mo.is_connected, msc.mcc_mnc())
+wait(ms_mt.is_connected, msc.mcc_mnc())
 wait(msc.subscriber_attached, ms_mo, ms_mt)
 
 sms = ms_mo.sms_send(ms_mt)
diff --git a/suites/debug/interactive.py b/suites/debug/interactive.py
index 603e395..37076dc 100755
--- a/suites/debug/interactive.py
+++ b/suites/debug/interactive.py
@@ -13,7 +13,7 @@
 
 for m in modems:
   nitb.subscriber_add(m)
-  m.connect(nitb)
+  m.connect(nitb.mcc_mnc())
 
 while True:
   cmd = prompt('Enter command: (q)uit (s)ms (g)et-registered (w)ait-registered')
@@ -25,6 +25,8 @@
     break
   elif 'wait-registered'.startswith(cmd):
     try:
+      for m in modems:
+         wait(m.is_connected, nitb.mcc_mnc())
       wait(nitb.subscriber_attached, *modems)
     except Timeout:
       print('Timeout while waiting for registration.')
diff --git a/suites/netreg/register.py b/suites/netreg/register.py
new file mode 100755
index 0000000..9141986
--- /dev/null
+++ b/suites/netreg/register.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.test import *
+
+print('use resources...')
+nitb = suite.nitb()
+bts = suite.bts()
+ms = suite.modem()
+
+print('start nitb and bts...')
+nitb.bts_add(bts)
+nitb.start()
+bts.start()
+
+nitb.subscriber_add(ms)
+
+ms.connect(nitb.mcc_mnc())
+
+print(ms.info())
+
+wait(ms.is_connected, nitb.mcc_mnc())
+wait(nitb.subscriber_attached, ms)
diff --git a/suites/netreg/register_default.py b/suites/netreg/register_default.py
new file mode 100755
index 0000000..d15b3f5
--- /dev/null
+++ b/suites/netreg/register_default.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.test import *
+
+print('use resources...')
+nitb = suite.nitb()
+bts = suite.bts()
+ms = suite.modem()
+
+print('start nitb and bts...')
+nitb.bts_add(bts)
+nitb.start()
+bts.start()
+
+nitb.subscriber_add(ms)
+
+ms.connect()
+
+print(ms.info())
+
+wait(ms.is_connected)
+wait(nitb.subscriber_attached, ms)
diff --git a/suites/netreg/suite.conf b/suites/netreg/suite.conf
new file mode 100644
index 0000000..1bb1dbb
--- /dev/null
+++ b/suites/netreg/suite.conf
@@ -0,0 +1,10 @@
+resources:
+  ip_address:
+  - times: 1
+  bts:
+  - times: 1
+  modem:
+  - times: 1
+
+defaults:
+  timeout: 40s
diff --git a/suites/sms/mo_mt_sms.py b/suites/sms/mo_mt_sms.py
index 860f5e7..4e0ba08 100755
--- a/suites/sms/mo_mt_sms.py
+++ b/suites/sms/mo_mt_sms.py
@@ -14,13 +14,15 @@
 nitb.subscriber_add(ms_mo)
 nitb.subscriber_add(ms_mt)
 
-ms_mo.connect(nitb)
-ms_mt.connect(nitb)
+ms_mo.connect(nitb.mcc_mnc())
+ms_mt.connect(nitb.mcc_mnc())
 
 ms_mo.log_info()
 ms_mt.log_info()
 
 print('waiting for modems to attach...')
+wait(ms_mo.is_connected, nitb.mcc_mnc())
+wait(ms_mt.is_connected, nitb.mcc_mnc())
 wait(nitb.subscriber_attached, ms_mo, ms_mt)
 
 sms = ms_mo.sms_send(ms_mt)

-- 
To view, visit https://gerrit.osmocom.org/2779
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I8d9eb47eac1044550d3885adb55105c304b0c15c
Gerrit-PatchSet: 7
Gerrit-Project: osmo-gsm-tester
Gerrit-Branch: master
Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Pau Espin Pedrol <pespin at sysmocom.de>



More information about the gerrit-log mailing list