From d7cb2da6db78f4c280781212ad887f0491b01608 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 20 Sep 2019 13:44:08 +0200 Subject: WIP Change-Id: Id6f85587dbfee05673262fd2eb4c8208288e2275 --- example/defaults.conf | 6 + example/resources.conf.rnd | 10 ++ src/osmo_gsm_tester/hnb_nano3g.py | 164 ++++++++++++++++++++++ src/osmo_gsm_tester/osmo_hnbgw.py | 136 ++++++++++++++++++ src/osmo_gsm_tester/resource.py | 15 +- src/osmo_gsm_tester/schema.py | 2 +- src/osmo_gsm_tester/suite.py | 25 +++- src/osmo_gsm_tester/templates/osmo-hnbgw.cfg.tmpl | 32 +++++ suites/3g_debug/interactive.py | 153 ++++++++++++++++++++ suites/3g_debug/suite.conf | 7 + 10 files changed, 546 insertions(+), 4 deletions(-) create mode 100644 src/osmo_gsm_tester/hnb_nano3g.py create mode 100644 src/osmo_gsm_tester/osmo_hnbgw.py create mode 100644 src/osmo_gsm_tester/templates/osmo-hnbgw.cfg.tmpl create mode 100755 suites/3g_debug/interactive.py create mode 100644 suites/3g_debug/suite.conf diff --git a/example/defaults.conf b/example/defaults.conf index 353cf9b..5a6baf1 100644 --- a/example/defaults.conf +++ b/example/defaults.conf @@ -92,3 +92,9 @@ osmo_bts_oc2g: max_trx: 1 trx_list: - nominal_power: 25 + +hnb: + net: + mcc: 901 + mnc: 70 + uarfcn: 9800 diff --git a/example/resources.conf.rnd b/example/resources.conf.rnd index 0fad50f..88d0613 100644 --- a/example/resources.conf.rnd +++ b/example/resources.conf.rnd @@ -46,6 +46,16 @@ bts: device: '01:01:55:2e:b6' port: '1' +hnb: +- label: nano3GS8 + type: nano3g + addr: 10.42.42.121 + band: PCS-1900 + power_supply: + type: 'sispm' + device: '01:01:55:2e:b6' + port: '3' + arfcn: - arfcn: 512 band: GSM-1800 diff --git a/src/osmo_gsm_tester/hnb_nano3g.py b/src/osmo_gsm_tester/hnb_nano3g.py new file mode 100644 index 0000000..63abf10 --- /dev/null +++ b/src/osmo_gsm_tester/hnb_nano3g.py @@ -0,0 +1,164 @@ +# osmo_gsm_tester: specifics for running an ip.access nanoBTS +# +# Copyright (C) 2018 by sysmocom - s.f.m.c. GmbH +# +# Author: Pau Espin Pedrol +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import pprint +import re +from . import log, config, util, process, pcap_recorder, abisipfind +from . import powersupply +from .event_loop import MainLoop + +class HnbNano3g(log.Origin): + + SSH_USER='root' + IPA_DMI_PATH='/opt/ipaccess/DMI/ipa-dmi' +############## +# PROTECTED +############## + def __init__(self, suite_run, conf): + super().__init__(log.C_RUN, 'nano3g_%s' % conf.get('label', 'nolabel'), 'nanobts') + self.suite_run = suite_run + self.conf = conf + self.pwsup = None + self.hnbgw = None + self.lac = None + self.rac = None + self.cellid = None + + def _configure(self): + if self.hnbgw is None: + raise log.Error('HNodeB needs to be added to a HNBGW before it can be configured') + + values = dict(hnb=config.get_defaults('hnb')) + config.overlay(values, self.suite_run.config()) + config.overlay(values, { 'hnb': self.conf }) + self.gen_conf = values + self.dbg('OSMO-BTS-TRX CONFIG:\n' + pprint.pformat(values)) + + pwsup_opt = self.conf.get('power_supply', {}) + if not pwsup_opt: + raise log.Error('No power_supply attribute provided in conf!') + pwsup_type = pwsup_opt.get('type') + if not pwsup_type: + raise log.Error('No type attribute provided in power_supply conf!' % trx_i) + self.pwsup = powersupply.get_instance_by_type(pwsup_type, pwsup_opt) + + def wait_ready(self, local_bind_ip, hnb_ip): + self.log('Finding nano3g %s, binding on %s...' % (hnb_ip, local_bind_ip)) + ipfind = abisipfind.AbisIpFind(self.suite_run, self.run_dir, local_bind_ip, 'preconf') + ipfind.start() + ipfind.wait_bts_ready(hnb_ip) + running_unitid, running_trx = ipfind.get_unitid_by_ip(hnb_ip) + self.log('Found nano3g %s with unit_id %d trx %d' % (hnb_ip, running_unitid, running_trx)) + ipfind.stop() + + def run_ssh_cmd(self, name, popen_args): + # On OpenSSH >= 7.0, only-supported algos by nano3g are disabled by default, they need to be enabled manually: + # https://projects.osmocom.org/projects/cellular-infrastructure/wiki/Configuring_the_ipaccess_nano3G#SSH-Access + ssh_args=['-o', 'KexAlgorithms=+diffie-hellman-group1-sha1', '-c', 'aes128-cbc'] + process.run_remote_sync(self.run_dir, HnbNano3g.SSH_USER, self.addr(), name, popen_args, remote_cwd=None, ssh_args=ssh_args) + + def run_dmi_cmd(self, name, cmd_str): + self.run_ssh_cmd('dmi-' + name, (HnbNano3g.IPA_DMI_PATH, '-c', '\"%s\"' % cmd_str)) + + def run_reboot(self): + self.run_ssh_cmd('reboot', reboot) + + def set_permanent_settings(self): + # These settings are set permantently and require a reboot after set: + self.run_dmi_cmd('set_mcc', 'set mcc=%s' % self.gen_conf['hnb']['net']['mcc']) + self.run_dmi_cmd('set_mnc', 'set mnc=%s' % self.gen_conf['hnb']['net']['mnc']) + # [uarfcnDownlink, 1900 MHz band], [scramblingCode], [dummyCellId] + self.run_dmi_cmd('set_rfparams', 'set rfParamsCandidateList=({%s, 401, %d})' % (self.gen_conf['hnb']['net']['uarfcn'], self.cellid)) + # [lac], [rac] + self.run_dmi_cmd('set_lac', 'set lacRacCandidateList=({%d, (%d)})' % (self.lac, self.rac)) + self.run_dmi_cmd('set_hnbcid', 'set hnbCId=%d', self.cellid) + self.run_dmi_cmd('set_rncid', 'set rncIdentity=0') + + def set_volatile_settings(self): + self.run_dmi_cmd('set_hnbgwaddr', 'set hnbGwAddress=%s' % self.addr()) + self.run_dmi_cmd('action_2061', 'action 2061') + self.run_dmi_cmd('action_1216', 'action 1216') + self.run_dmi_cmd('action_establish_conn', 'action establishPermanentHnbGwConnection') + self.run_dmi_cmd('set_csgaccessmode', 'set csgAccessMode=CSG_ACCESS_MODE_OPEN_ACCESS') + +######################## +# PUBLIC - INTERNAL API +####################### + + def set_lac(self, lac): + self.lac = lac + + def set_rac(self, rac): + self.rac = rac + + def set_cellid(self, cellid): + self.cellid = cellid + + def cleanup(self): + if self.pwsup: + self.dbg('Powering off') + self.pwsup.power_set(False) + self.pwsup = None + +################### +# PUBLIC (test API included) +################### + + def start(self): + self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name())) + self._configure() + + hnb_ip = self.addr() + + # Make sure nano3g is powered and in a clean state: + self.dbg('Powering cycling nano3g') + self.pwsup.power_cycle(1.0) + + pcap_recorder.PcapRecorder(self.suite_run, self.run_dir.new_dir('pcap'), None, + 'host %s and port not 22' % hnb_ip) + + # This fine for now, however concurrent tests using nano3g may run into "address already in use" since dst is broadcast. + # Once concurrency is needed, a new config attr should be added to have an extra static IP assigned on the main-unit to each Nano3g resource. + local_bind_ip = util.dst_ip_get_local_bind(hnb_ip) + + # Wait until nano3g is ready (announcing through abisip-find) and then set permanent settings + self.wait_ready(local_bind_ip, hnb_ip) + self.set_permanent_settings() + + # Configs applied above require a reboot of the nano3g to be applied: + self.run_reboot() + #sleep a few seconds (to avoid getting abisipind results previous to reboot): + MainLoop.sleep(self, 5.0) + + # Wait until nano3g is ready again and apply volatile settings: + self.wait_ready(local_bind_ip, hnb_ip) + self.set_volatile_settings() + + # After applying volatile settings, nano3g should end up connected to our HNBGW: + MainLoop.wait(self, self.hnbgw.hnb_is_connected, self, timeout=600) + self.log('nano3g connected to HNBGW') + + def addr(self): + return self.conf.get('addr') + + def set_hnbgw(self, hnbgw): + self.hnbgw = hnbgw + +# vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/osmo_hnbgw.py b/src/osmo_gsm_tester/osmo_hnbgw.py new file mode 100644 index 0000000..24e6373 --- /dev/null +++ b/src/osmo_gsm_tester/osmo_hnbgw.py @@ -0,0 +1,136 @@ +# osmo_gsm_tester: specifics for running an osmo-hnbgw +# +# Copyright (C) 2019 by sysmocom - s.f.m.c. GmbH +# +# Author: Pau Espin Pedrol +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import re +import pprint + +from . import log, util, config, template, process, osmo_ctrl, pcap_recorder + +class OsmoHnbgw(log.Origin): + + def __init__(self, suite_run, stp, ip_address): + super().__init__(log.C_RUN, 'osmo-hnbgw_%s' % ip_address.get('addr')) + self.run_dir = None + self.config_file = None + self.process = None + self.suite_run = suite_run + self.ip_address = ip_address + self.hnb_li = [] + self.stp = stp + + def start(self): + self.log('Starting osmo-hnbgw') + self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name())) + self.configure() + + inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('osmo-iuh'))) + + binary = inst.child('bin', 'osmo-hnbgw') + if not os.path.isfile(binary): + raise RuntimeError('Binary missing: %r' % binary) + lib = inst.child('lib') + if not os.path.isdir(lib): + raise RuntimeError('No lib/ in %r' % inst) + + + filter = 'host %s and port not 22' % self.addr() + pcap_recorder.PcapRecorder(self.suite_run, self.run_dir.new_dir('pcap'), None, filter) + + env = { 'LD_LIBRARY_PATH': util.prepend_library_path(lib) } + + self.dbg(run_dir=self.run_dir, binary=binary, env=env) + self.process = process.Process(self.name(), self.run_dir, + (binary, '-c', + os.path.abspath(self.config_file)), + env=env) + self.suite_run.remember_to_stop(self.process) + self.process.launch() + + def configure(self): + self.config_file = self.run_dir.new_file('osmo-hnbgw.cfg') + self.dbg(config_file=self.config_file) + + values = dict(hnbgw=config.get_defaults('hnbgw')) + config.overlay(values, self.suite_run.config()) + config.overlay(values, dict(hnbgw=dict(ip_address=self.ip_address))) + config.overlay(values, self.stp.conf_for_client()) + + #hnb_list = [] + #for hnb in self.hnb_li: + # hnb_list.append(hnb.conf_for_hnbgw()) + #config.overlay(values, dict(hnbgw=dict(hnb_list=hnb_list))) + + self.dbg('HNBGW CONFIG:\n' + pprint.pformat(values)) + + with open(self.config_file, 'w') as f: + r = template.render('osmo-hnbgw.cfg', values) + self.dbg(r) + f.write(r) + + def addr(self): + return self.ip_address.get('addr') + + def hnb_add(self, hnb): + self.hnb_li.append(hnb) + hnb.set_hnbgw(self) + + def hnb_num(self, hnb): + 'Provide number id used by OsmoHNBGW to identify configured HNB' + # We take advantage from the fact that VTY code assigns VTY in ascending + # order through the HNB nodes found. As we populate the config iterating + # over this list, we have a 1:1 match in indexes. + return self.hnb_li.index(hnb) + + def hnb_is_connected(self, hnb): + return OsmoHnbgwCtrl(self).hnb_is_connected(self.hnb_num(hnb)) + + def running(self): + return not self.process.terminated() + + +class OsmoHnbgwCtrl(log.Origin): + PORT = 4261 + HNB_INFO_VAR = "hnb.%d.info" + HNB_INFO_RE = re.compile("GET_REPLY (\d+) hnb.\d+.info (?P\w+)") + + def __init__(self, hnbgw): + self.hnbgw = hnbgw + super().__init__(log.C_BUS, 'CTRL(%s:%d)' % (self.hnbgw.addr(), OsmoHnbgwCtrl.PORT)) + + def ctrl(self): + return osmo_ctrl.OsmoCtrl(self.hnbgw.addr(), OsmoHnbgwCtrl.PORT) + + def hnb_is_connected(self, hnb_num): + with self.ctrl() as ctrl: + ctrl.do_get(OsmoHnbgwCtrl.HNB_INFO_VAR % hnb_num) + data = ctrl.receive() + while (len(data) > 0): + (answer, data) = ctrl.remove_ipa_ctrl_header(data) + answer_str = answer.decode('utf-8') + answer_str = answer_str.replace('\n', ' ') + res = OsmoHnbgwCtrl.HNB_INFO_RE.match(answer_str) + if res: + info = str(res.group('info')) + self.log('got info: "%s"' % info) + if info == 'connected': + return True + return False + +# vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/resource.py b/src/osmo_gsm_tester/resource.py index 1b18076..55ad648 100644 --- a/src/osmo_gsm_tester/resource.py +++ b/src/osmo_gsm_tester/resource.py @@ -27,6 +27,7 @@ from . import config from . import util from . import schema from . import bts_sysmo, bts_osmotrx, bts_osmovirtual, bts_octphy, bts_nanobts, bts_oc2g +from . import hnb_nano3g from . import modem from . import ms_osmo_mobile @@ -41,10 +42,11 @@ RESERVED_RESOURCES_FILE = 'reserved_resources.state' R_IP_ADDRESS = 'ip_address' R_BTS = 'bts' +R_HNB = 'hnb' R_ARFCN = 'arfcn' R_MODEM = 'modem' R_OSMOCON = 'osmocon_phone' -R_ALL = (R_IP_ADDRESS, R_BTS, R_ARFCN, R_MODEM, R_OSMOCON) +R_ALL = (R_IP_ADDRESS, R_BTS, R_HNB, R_ARFCN, R_MODEM, R_OSMOCON) RESOURCES_SCHEMA = { 'ip_address[].addr': schema.IPV4, @@ -76,6 +78,13 @@ RESOURCES_SCHEMA = { 'bts[].osmo_trx.dev_args': schema.STR, 'bts[].osmo_trx.multi_arfcn': schema.BOOL_STR, 'bts[].osmo_trx.max_trxd_version': schema.UINT, + 'hnb[].label': schema.STR, + 'hnb[].type': schema.STR, + 'hnb[].addr': schema.IPV4, + 'hnb[].band': schema.BAND, + 'hnb[].power_supply.type': schema.STR, + 'hnb[].power_supply.device': schema.STR, + 'hnb[].power_supply.port': schema.STR, 'arfcn[].arfcn': schema.INT, 'arfcn[].band': schema.BAND, 'modem[].type': schema.STR, @@ -108,6 +117,10 @@ KNOWN_BTS_TYPES = { 'nanobts': bts_nanobts.NanoBts, } +KNOWN_HNB_TYPES = { + 'nano3g': hnb_nano3g.HnbNano3g, + } + KNOWN_MS_TYPES = { # Map None to ofono for forward compability diff --git a/src/osmo_gsm_tester/schema.py b/src/osmo_gsm_tester/schema.py index 14fe640..91d45cc 100644 --- a/src/osmo_gsm_tester/schema.py +++ b/src/osmo_gsm_tester/schema.py @@ -39,7 +39,7 @@ def match_re(name, regex, val): raise ValueError('Invalid %s: %r' % (name, val)) def band(val): - if val in ('GSM-900', 'GSM-1800', 'GSM-1900'): + if val in ('GSM-900', 'GSM-1800', 'GSM-1900', 'PCS-1900'): return raise ValueError('Unknown GSM band: %r' % val) diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py index 0738e96..3b2d87d 100644 --- a/src/osmo_gsm_tester/suite.py +++ b/src/osmo_gsm_tester/suite.py @@ -21,9 +21,9 @@ import os import sys import time import pprint -from . import config, log, util, resource, test +from . import config, log, util, resource, test, process from .event_loop import MainLoop -from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, esme, osmocon, ms_driver, iperf3, process +from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, esme, osmocon, ms_driver, iperf3, osmo_hnbgw class Timeout(Exception): pass @@ -327,6 +327,19 @@ class SuiteRun(log.Origin): self.register_for_cleanup(bts) return bts + def hnbgw(self, stp, ip_address=None): + if ip_address is None: + ip_address = self.ip_address() + return osmo_hnbgw.OsmoHnbgw(self, stp, ip_address) + + def hnb(self, specifics=None): + hnb = hnb_obj(self, self.reserved_resources.get(resource.R_HNB, specifics=specifics)) + hnb.set_lac(self.lac()) + hnb.set_rac(self.rac()) + hnb.set_cellid(self.cellid()) + self.register_for_cleanup(hnb) + return hnb + def modem(self, specifics=None): conf = self.reserved_resources.get(resource.R_MODEM, specifics=specifics) ms_type = conf.get('type') @@ -477,4 +490,12 @@ def bts_obj(suite_run, conf): raise RuntimeError('No such BTS type is defined: %r' % bts_type) return bts_class(suite_run, conf) +def hnb_obj(suite_run, conf): + hnb_type = conf.get('type') + log.dbg('create HNB object', type=hnb_type) + hnb_class = resource.KNOWN_HNB_TYPES.get(hnb_type) + if hnb_class is None: + raise RuntimeError('No such HNB type is defined: %r' % hnb_type) + return hnb_class(suite_run, conf) + # vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/templates/osmo-hnbgw.cfg.tmpl b/src/osmo_gsm_tester/templates/osmo-hnbgw.cfg.tmpl new file mode 100644 index 0000000..244873e --- /dev/null +++ b/src/osmo_gsm_tester/templates/osmo-hnbgw.cfg.tmpl @@ -0,0 +1,32 @@ +! +! OsmoHNBGW (0) configuration saved from vty +!! +! +log stderr + logging filter all 1 + logging color 1 + logging print category 1 + logging timestamp 1 + logging print extended-timestamp 1 + logging level all debug + logging level lglobal notice + logging level llapd notice + logging level linp notice + logging level lmux notice + logging level lmi notice + logging level lmib notice + logging level lsms notice + logging level lctrl notice + logging level lgtp notice + logging level lstats notice + logging level set-all debug +line vty + no login + bind ${hnbgw.ip_address.addr} +ctrl + bind ${hnbgw.ip_address.addr} + +hnbgw + iuh + local-ip ${hnbgw.ip_address.addr} + hnbap-allow-tmsi 1 diff --git a/suites/3g_debug/interactive.py b/suites/3g_debug/interactive.py new file mode 100755 index 0000000..0de7c9f --- /dev/null +++ b/suites/3g_debug/interactive.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * +hlr = suite.hlr() +hnb = suite.hnb() +mgw_msc = suite.mgw() +stp = suite.stp() +ggsn = suite.ggsn() +sgsn = suite.sgsn(hlr, ggsn) +msc = suite.msc(hlr, mgw_msc, stp) +hnbgw = suite.hnbgw(stp) + +modems = suite.modems(int(prompt('How many modems?'))) + +hnbgw.hnb_add(hnb) + +hlr.start() +stp.start() +ggsn.start() +sgsn.start() +msc.start() +mgw_msc.start() +hnbgw.start() + +hnb.start() +print('Waiting for hnb to connect to hnbgw...') +wait(hnbgw.hnb_is_connected, hnb) + +for m in modems: + hlr.subscriber_add(m) + m.connect(msc.mcc_mnc()) + +while True: + cmd = prompt('Enter command: (q)uit (s)ms (g)et-registered (w)ait-registered, call-list [], call-dial , call-wait-incoming , call-answer , call-hangup , ussd , data-attach, data-wait, data-detach, data-activate') + cmd = cmd.strip().lower() + + if not cmd: + continue + + params = cmd.split() + + if 'quit'.startswith(cmd): + 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.') + + elif 'get-registered'.startswith(cmd): + print(msc.imsi_list_attached()) + print('RESULT: %s' % + ('All modems are registered.' if msc.subscriber_attached(*modems) + else 'Some modem(s) not registered yet.')) + + elif 'sms'.startswith(cmd): + for mo in modems: + for mt in modems: + mo.sms_send(mt.msisdn, 'to ' + mt.name()) + + elif cmd.startswith('call-list'): + if len(params) != 1 and len(params) != 2: + print('wrong format') + continue + for ms in modems: + if len(params) == 1 or str(ms.msisdn) == params[1]: + print('call-list: %r %r' % (ms.name(), ms.call_id_list())) + + elif cmd.startswith('call-dial'): + if len(params) != 3: + print('wrong format') + continue + src_msisdn, dst_msisdn = params[1:] + for mo in modems: + if str(mo.msisdn) == src_msisdn: + print('dialing %s->%s' % (src_msisdn, dst_msisdn)) + call_id = mo.call_dial(dst_msisdn) + print('dial success: call_id=%r' % call_id) + + elif cmd.startswith('call-wait-incoming'): + if len(params) != 3: + print('wrong format') + continue + src_msisdn, dst_msisdn = params[1:] + for mt in modems: + if str(mt.msisdn) == dst_msisdn: + print('waiting for incoming %s->%s' % (src_msisdn, dst_msisdn)) + call_id = mt.call_wait_incoming(src_msisdn) + print('incoming call success: call_id=%r' % call_id) + + elif cmd.startswith('call-answer'): + if len(params) != 3: + print('wrong format') + continue + mt_msisdn, call_id = params[1:] + for mt in modems: + if str(mt.msisdn) == mt_msisdn: + print('answering %s %r' % (mt.name(), call_id)) + mt.call_answer(call_id) + + elif cmd.startswith('call-hangup'): + if len(params) != 3: + print('wrong format') + continue + ms_msisdn, call_id = params[1:] + for ms in modems: + if str(ms.msisdn) == ms_msisdn: + print('hanging up %s %r' % (ms.name(), call_id)) + ms.call_hangup(call_id) + + elif cmd.startswith('ussd'): + if len(params) != 2: + print('wrong format') + continue + ussd_cmd = params[1] + for ms in modems: + print('modem %s: ussd %s' % (ms.name(), ussd_cmd)) + response = ms.ussd_send(ussd_cmd) + print('modem %s: response=%r' % (ms.name(), response)) + + elif cmd.startswith('data-attach'): + if len(params) != 1: + print('wrong format') + continue + for ms in modems: + print('modem %s: attach' % ms.name()) + ms.attach() + wait(ms.is_attached) + print('modem %s: attached' % ms.name()) + + elif cmd.startswith('data-detach'): + if len(params) != 1: + print('wrong format') + continue + for ms in modems: + print('modem %s: detach' % ms.name()) + ms.attach() + wait(lambda: not ms.is_attached()) + print('modem %s: detached' % ms.name()) + + elif cmd.startswith('data-activate'): + if len(params) != 1: + print('wrong format') + continue + for ms in modems: + print('modem %s: activate' % ms.name()) + response = ms.activate_context() + print('modem %s: response=%r' % (ms.name(), response)) + + else: + print('Unknown command: %s' % cmd) diff --git a/suites/3g_debug/suite.conf b/suites/3g_debug/suite.conf new file mode 100644 index 0000000..400fa28 --- /dev/null +++ b/suites/3g_debug/suite.conf @@ -0,0 +1,7 @@ +resources: + ip_address: + - times: 8 + hnb: + - times: 1 + modem: + - times: 2 -- cgit v1.2.3