blob: a10784f246c6ef4dba4bf9472a1393c8757ab232 [file] [log] [blame]
Neels Hofmeyr3531a192017-03-28 14:30:28 +02001# osmo_gsm_tester: DBUS client to talk to ofono
2#
3# Copyright (C) 2016-2017 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Neels Hofmeyr <neels@hofmeyr.de>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +020020from . import log, test
Neels Hofmeyr3531a192017-03-28 14:30:28 +020021
22from pydbus import SystemBus, Variant
23import time
24import pprint
25
26from gi.repository import GLib
27glib_main_loop = GLib.MainLoop()
28glib_main_ctx = glib_main_loop.get_context()
29bus = SystemBus()
30
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +020031I_NETREG = 'org.ofono.NetworkRegistration'
32I_SMS = 'org.ofono.MessageManager'
33
Neels Hofmeyr3531a192017-03-28 14:30:28 +020034def poll():
35 global glib_main_ctx
36 while glib_main_ctx.pending():
37 glib_main_ctx.iteration()
38
39def get(path):
40 global bus
41 return bus.get('org.ofono', path)
42
43def list_modems():
44 root = get('/')
45 return sorted(root.GetModems())
46
47
48class Modem(log.Origin):
49 'convenience for ofono Modem interaction'
50 msisdn = None
51
52 def __init__(self, conf):
53 self.conf = conf
54 self.path = conf.get('path')
55 self.set_name(self.path)
56 self.set_log_category(log.C_BUS)
57 self._dbus_obj = None
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +020058 self._interfaces = set()
59 test.poll()
Neels Hofmeyr3531a192017-03-28 14:30:28 +020060
61 def set_msisdn(self, msisdn):
62 self.msisdn = msisdn
63
64 def imsi(self):
Neels Hofmeyrb02c2112017-04-09 18:46:48 +020065 imsi = self.conf.get('imsi')
66 if not imsi:
67 with self:
68 raise RuntimeError('No IMSI')
69 return imsi
Neels Hofmeyr3531a192017-03-28 14:30:28 +020070
71 def ki(self):
72 return self.conf.get('ki')
73
74 def set_powered(self, on=True):
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +020075 test.poll()
Neels Hofmeyrb02c2112017-04-09 18:46:48 +020076 self.dbus_obj().SetProperty('Powered', Variant('b', on))
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +020077 test.poll()
Neels Hofmeyr3531a192017-03-28 14:30:28 +020078
79 def dbus_obj(self):
80 if self._dbus_obj is not None:
81 return self._dbus_obj
82 self._dbus_obj = get(self.path)
83 self._dbus_obj.PropertyChanged.connect(self._on_property_change)
84 self._on_interfaces_change(self.properties().get('Interfaces'))
Neels Hofmeyrb02c2112017-04-09 18:46:48 +020085 return self._dbus_obj
Neels Hofmeyr3531a192017-03-28 14:30:28 +020086
87 def properties(self):
88 return self.dbus_obj().GetProperties()
89
90 def _on_property_change(self, name, value):
91 if name == 'Interfaces':
92 self._on_interfaces_change(value)
93
94 def _on_interfaces_change(self, interfaces_now):
95 now = set(interfaces_now)
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +020096 additions = now - self._interfaces
97 removals = self._interfaces - now
98 self._interfaces = now
Neels Hofmeyr3531a192017-03-28 14:30:28 +020099 for iface in removals:
100 with log.Origin('modem.disable(%s)' % iface):
101 try:
102 self._on_interface_disabled(iface)
103 except:
104 self.log_exn()
105 for iface in additions:
106 with log.Origin('modem.enable(%s)' % iface):
107 try:
108 self._on_interface_enabled(iface)
109 except:
110 self.log_exn()
111
112 def _on_interface_enabled(self, interface_name):
113 self.dbg('Interface enabled:', interface_name)
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +0200114 if interface_name == I_SMS:
Neels Hofmeyrb02c2112017-04-09 18:46:48 +0200115 self.dbus_obj()[I_SMS].IncomingMessage.connect(self._on_incoming_message)
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200116
117 def _on_interface_disabled(self, interface_name):
118 self.dbg('Interface disabled:', interface_name)
119
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +0200120 def has_interface(self, name):
121 return name in self._interfaces
122
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200123 def connect(self, nitb):
124 'set the modem up to connect to MCC+MNC from NITB config'
125 self.log('connect to', nitb)
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +0200126 self.set_powered()
127 if not self.has_interface(I_NETREG):
128 self.log('No %r interface, hoping that the modem connects by itself' % I_NETREG)
129 else:
130 self.log('Use of %r interface not implemented yet, hoping that the modem connects by itself' % I_NETREG)
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200131
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +0200132 def sms_send(self, to_msisdn):
133 if hasattr(to_msisdn, 'msisdn'):
134 to_msisdn = to_msisdn.msisdn
135 self.log('sending sms to MSISDN', to_msisdn)
136 if not self.has_interface(I_SMS):
137 raise RuntimeError('Modem cannot send SMS, interface not active: %r' % I_SMS)
138 sms = Sms(self.msisdn(), to_msisdn)
Neels Hofmeyrb02c2112017-04-09 18:46:48 +0200139 mm = self.dbus_obj()[I_SMS]
Neels Hofmeyrb3daaea2017-04-09 14:18:34 +0200140 mm.SendMessage(to_msisdn, str(sms))
141 return sms
142
143 def _on_incoming_message(self, message, info):
144 self.log('Incoming SMS:', repr(message), **info)
145
146 def sms_received(self, sms):
147 pass
148
149class Sms:
150 _last_sms_idx = 0
151 msg = None
152
153 def __init__(self, from_msisdn=None, to_msisdn=None):
154 Sms._last_sms_idx += 1
155 msgs = ['message nr. %d' % Sms._last_sms_idx]
156 if from_msisdn or to_msisdn:
157 msgs.append(' sent')
158 if from_msisdn:
159 msgs.append(' from %s' % from_msisdn)
160 if to_msisdn:
161 msgs.append(' to %s' % to_msisdn)
162 self.msg = ''.join(msgs)
163
164 def __str__(self):
165 return self.msg
166
167 def __eq__(self, other):
168 if isinstance(other, Sms):
169 return self.msg == other.msg
170 return inself.msg == other
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200171
172# vim: expandtab tabstop=4 shiftwidth=4