dbus: implement StartPairing/StopPairing on the manager

Triggers a StartDiscovery()/StopDiscovery() on the bluetooth adapters, but
with a fixed timeout of 30s.
pull/8/head
Peter Hutterer 2018-01-17 15:20:46 +01:00
parent 3871fc1d58
commit 43b1c4057c
3 changed files with 137 additions and 3 deletions

27
tuhi.py
View File

@ -138,14 +138,31 @@ class Tuhi(GObject.Object):
GObject.Object.__init__(self)
self.server = TuhiDBusServer()
self.server.connect('bus-name-acquired', self._on_tuhi_bus_name_acquired)
self.server.connect('pairing-start-requested', self._on_start_pairing_requested)
self.server.connect('pairing-stop-requested', self._on_stop_pairing_requested)
self.bluez = BlueZDeviceManager()
self.bluez.connect('device-added', self._on_bluez_device_added)
self.bluez.connect('discovery-started', self._on_bluez_discovery_started)
self.bluez.connect('discovery-stopped', self._on_bluez_discovery_stopped)
self.devices = {}
self._pairing_stop_handler = None
def _on_tuhi_bus_name_acquired(self, dbus_server):
self.bluez.connect_to_bluez()
def _on_start_pairing_requested(self, dbus_server, stop_handler):
self._pairing_stop_handler = stop_handler
self.bluez.start_discovery(timeout=30)
def _on_stop_pairing_requested(self, dbus_server):
# If you request to stop, you get a successful stop and we ignore
# anything the server does underneath
self._pairing_stop_handler(0)
self._pairing_stop_handler = None
self.bluez.stop_discovery()
def _on_bluez_device_added(self, manager, bluez_device):
if bluez_device.vendor_id != WACOM_COMPANY_ID:
return
@ -154,6 +171,16 @@ class Tuhi(GObject.Object):
d = TuhiDevice(bluez_device, tuhi_dbus_device)
self.devices[bluez_device.address] = d
def _on_bluez_discovery_started(self, manager):
# Something else may turn discovery mode on, we don't care about
# it then
if not self._pairing_stop_handler:
return
def _on_bluez_discovery_stopped(self, manager):
if self._pairing_stop_handler is not None:
self._pairing_stop_handler(0)
def main(args):
desc = "Daemon to extract the pen stroke data from Wacom SmartPad devices"

View File

@ -11,7 +11,7 @@
# GNU General Public License for more details.
import logging
from gi.repository import GObject, Gio
from gi.repository import GObject, Gio, GLib
logger = logging.getLogger('tuhi.ble')
@ -256,6 +256,10 @@ class BlueZDeviceManager(GObject.Object):
__gsignals__ = {
"device-added":
(GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
"discovery-started":
(GObject.SIGNAL_RUN_FIRST, None, ()),
"discovery-stopped":
(GObject.SIGNAL_RUN_FIRST, None, ()),
}
def __init__(self, **kwargs):
@ -285,6 +289,54 @@ class BlueZDeviceManager(GObject.Object):
for obj in self._om.get_objects():
self._process_object(obj)
def _discovery_timeout_expired(self):
self.stop_discovery()
return False
def start_discovery(self, timeout=0):
"""
Start discovery mode, terminating after the specified timeout (in
seconds). If timeout is 0, no timeout is imposed and the discovery
mode stays on.
This emits the discovery-started signal
"""
self.emit("discovery-started")
for obj in self._om.get_objects():
i = obj.get_interface(ORG_BLUEZ_ADAPTER1)
if i is None:
continue
objpath = obj.get_object_path()
i.StartDiscovery()
logger.debug('{}: Discovery started (timeout {})'.format(objpath, timeout))
if timeout > 0:
GObject.timeout_add_seconds(timeout, self._discovery_timeout_expired)
# FIXME: Any errors up to here should trigger discovery-stopped
# signal with the status code
def stop_discovery(self):
"""
Stop an ongoing discovery mode. Any errors are logged but ignored.
This emits the discovery-stopped signal
"""
for obj in self._om.get_objects():
i = obj.get_interface(ORG_BLUEZ_ADAPTER1)
if i is None:
continue
objpath = obj.get_object_path()
try:
i.StopDiscovery()
logger.debug('{}: Discovery stopped'.format(objpath))
except GLib.Error as e:
logger.debug('{}: Failed to stop discovery ({})'.format(objpath, e))
self.emit("discovery-stopped")
def _on_om_object_added(self, om, obj):
"""Callback for ObjectManager's object-added"""
objpath = obj.get_object_path()

View File

@ -23,6 +23,19 @@ INTROSPECTION_XML = """
<property type='ao' name='Devices' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property>
<method name='StartPairing'>
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
</method>
<method name='StopPairing'>
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
</method>
<signal name='PairingStopped'>
<arg name='status' type='i' />
</signal>
</interface>
<interface name='org.freedesktop.tuhi1.Device'>
@ -131,6 +144,15 @@ class TuhiDBusServer(GObject.Object):
__gsignals__ = {
"bus-name-acquired":
(GObject.SIGNAL_RUN_FIRST, None, ()),
# Signal arguments:
# pairing_stop_handler(status)
# to be called when the pairing process has terminated, with
# an integer status code (0 == success, negative errno)
"pairing-start-requested":
(GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
"pairing-stop-requested":
(GObject.SIGNAL_RUN_FIRST, None, ()),
}
def __init__(self):
@ -142,6 +164,7 @@ class TuhiDBusServer(GObject.Object):
self._bus_aquired,
self._bus_name_aquired,
self._bus_name_lost)
self._is_pairing = False
def _bus_aquired(self, connection, name):
introspection = Gio.DBusNodeInfo.new_for_xml(INTROSPECTION_XML)
@ -161,8 +184,16 @@ class TuhiDBusServer(GObject.Object):
def _bus_name_lost(self, connection, name):
pass
def _method_cb(self):
pass
def _method_cb(self, connection, sender, objpath, interface, methodname, args, invocation):
if interface != INTF_MANAGER:
return None
if methodname == 'StartPairing':
self._start_pairing()
invocation.return_value()
elif methodname == 'StopPairing':
self._stop_pairing()
invocation.return_value()
def _property_read_cb(self, connection, sender, objpath, interface, propname):
if interface != INTF_MANAGER:
@ -176,6 +207,30 @@ class TuhiDBusServer(GObject.Object):
def _property_write_cb(self):
pass
def _start_pairing(self):
if self._is_pairing:
return
self._is_pairing = True
self.emit("pairing-start-requested", self._on_pairing_stop)
def _stop_pairing(self):
if not self._is_pairing:
return
self._is_pairing = False
self.emit("pairing-stop-requested")
def _on_pairing_stop(self, status):
"""
Called by whoever handles the pairing-start-requested signal
"""
logger.debug("Pairing has stopped")
status = GLib.Variant.new_int32(status)
status = GLib.Variant.new_tuple(status)
self._connection.emit_signal(None, BASE_PATH, INTF_MANAGER,
"PairingStopped", status)
def cleanup(self):
Gio.bus_unown_name(self._dbus)