Implement pairing of a new device

pull/4/head
Benjamin Tissoires 2018-01-17 17:01:12 +01:00
parent c30952c490
commit c2526d6e0e
3 changed files with 101 additions and 4 deletions

21
tuhi.py
View File

@ -82,13 +82,19 @@ class TuhiDevice(GObject.Object):
self._wacom_device.connect('drawing', self._on_drawing_received)
self._wacom_device.connect('done', self._on_fetching_finished, bluez_device)
self.drawings = []
self.pairing_mode = False
bluez_device.connect('connected', self._on_bluez_device_connected)
bluez_device.connect('disconnected', self._on_bluez_device_disconnected)
self._bluez_device = bluez_device
def connect_device(self):
self._bluez_device.connect_device()
def _on_bluez_device_connected(self, bluez_device):
logger.debug('{}: connected'.format(bluez_device.address))
self._wacom_device.start()
self._wacom_device.start(self.pairing_mode)
self.pairing_mode = False
def _on_bluez_device_disconnected(self, bluez_device):
logger.debug('{}: disconnected'.format(bluez_device.address))
@ -140,6 +146,7 @@ class Tuhi(GObject.Object):
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.server.connect('pair-device-requested', self._on_pair_device_requested)
self.bluez = BlueZDeviceManager()
self.bluez.connect('device-added', self._on_bluez_device_added)
self.bluez.connect('device-updated', self._on_bluez_device_updated)
@ -184,6 +191,18 @@ class Tuhi(GObject.Object):
self._pairable_device_handler is not None):
self._pairable_device_handler(bluez_device)
def _on_pair_device_requested(self, manager, address):
bluez_device = self.server.get_pairable_device(address)
if bluez_device is None:
# FIXME: we should return the dbus method an error
return
tuhi_dbus_device = self.server.create_device(bluez_device)
d = TuhiDevice(bluez_device, tuhi_dbus_device)
d.pairing_mode = True
self.devices[bluez_device.address] = d
d.connect_device()
def main(args):
desc = "Daemon to extract the pen stroke data from Wacom SmartPad devices"

View File

@ -32,6 +32,11 @@ INTROSPECTION_XML = """
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
</method>
<method name='Pair'>
<arg name='address' type='s' direction='in'/>
<arg name='result' type='i' direction='out'/>
</method>
<signal name='PairingStopped'>
<arg name='status' type='i' />
</signal>
@ -39,7 +44,6 @@ INTROSPECTION_XML = """
<signal name='PairableDevice'>
<arg name='info' type='a{sv}' />
</signal>
</interface>
<interface name='org.freedesktop.tuhi1.Device'>
@ -162,6 +166,8 @@ class TuhiDBusServer(GObject.Object):
(GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT,)),
"pairing-stop-requested":
(GObject.SIGNAL_RUN_FIRST, None, ()),
"pair-device-requested":
(GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_STRING,)),
}
def __init__(self):
@ -203,6 +209,10 @@ class TuhiDBusServer(GObject.Object):
elif methodname == 'StopPairing':
self._stop_pairing()
invocation.return_value()
elif methodname == 'Pair':
self.emit('pair-device-requested', args[0])
result = GLib.Variant.new_int32(0)
invocation.return_value(GLib.Variant.new_tuple(result))
def _property_read_cb(self, connection, sender, objpath, interface, propname):
if interface != INTF_MANAGER:
@ -271,3 +281,9 @@ class TuhiDBusServer(GObject.Object):
dev = TuhiDBusDevice(device, self._connection)
self._devices.append(dev)
return dev
def get_pairable_device(self, address):
if address not in self._pairable_devices:
return None
return self._pairable_devices[address]

View File

@ -97,6 +97,10 @@ class WacomEEAGAINException(WacomException):
pass
class WacomWrongModeException(WacomException):
pass
class WacomNotPairedException(WacomException):
pass
@ -241,6 +245,8 @@ class WacomDevice(GObject.Object):
raise WacomNotPairedException(f"wrong device, please redo pairing")
if data[0] == 0x02:
raise WacomEEAGAINException(f"unexpected answer: {data[0]:02x}")
if data[0] == 0x01:
raise WacomWrongModeException(f"wrong device mode")
def send_nordic_command_sync(self,
command,
@ -571,6 +577,57 @@ class WacomDevice(GObject.Object):
except WacomEEAGAINException:
logger.warning("no data, please make sure the LED is blue and the button is pressed to switch it back to green")
def register_device_slate(self):
self.register_connection()
logger.info("Press the button now to confirm")
data = self.wait_nordic_data([0xe4, 0xb3], 10)
if data.opcode == 0xb3:
# generic ACK
self.check_ack(data)
self.set_time()
self.read_time()
self.ec_command()
self.bb_command()
w = self.get_dimensions('width')
h = self.get_dimensions('height')
if self.width != w or self.height != h:
logger.error(f'Uncompatible dimensions: {w}x{h}')
fw_high = self.get_firmware_version(0)
fw_low = self.get_firmware_version(1)
logger.info(f'firmware is {fw_high}-{fw_low}')
logger.info("pairing completed")
def register_device_spark(self):
try:
self.check_connection()
except WacomWrongModeException:
# this is expected
pass
self.send_nordic_command(command=0xe3,
arguments=[0x01])
logger.info("Press the button now to confirm")
# Wait for the button confirmation event, or any error
data = self.wait_nordic_data([0xe4, 0xb3], 10)
if data.opcode == 0xb3:
# generic ACK
self.check_ack(data)
self.send_nordic_command_sync(command=0xe5,
arguments=None,
expected_opcode=0xb3)
self.set_time()
self.read_time()
self.bb_command()
fw_high = self.get_firmware_version(0)
fw_low = self.get_firmware_version(1)
logger.info(f'firmware is {fw_high}-{fw_low}')
logger.info("pairing completed")
def register_device(self):
if self.is_slate():
self.register_device_slate()
else:
self.register_device_spark()
def run(self):
if self._is_running:
logger.error('{}: already synching, ignoring this request'.format(self.device.address))
@ -579,11 +636,16 @@ class WacomDevice(GObject.Object):
logger.debug('{}: starting'.format(self.device.address))
self._is_running = True
try:
self.retrieve_data()
if self._pairing_mode:
self.register_device()
else:
self.retrieve_data()
finally:
self._pairing_mode = False
self._is_running = False
self.emit("done")
def start(self):
def start(self, pairing_mode):
self._pairing_mode = pairing_mode
self.thread = threading.Thread(target=self.run)
self.thread.start()