Rename "pair" to "register"
"pair" is alrady taken by Bluetooth and since we have a bluetooth device here, it can cause confusion. Use "register" instead, with an explanation in the README for the more paranoid of us. Fixes #67
This commit is contained in:
parent
fc219e4c57
commit
5e82d1b378
97
README.md
97
README.md
|
@ -16,21 +16,33 @@ Devices tested and known to be supported:
|
|||
* Bamboo Spark
|
||||
* Bamboo Slate
|
||||
|
||||
Warning
|
||||
-------
|
||||
Registering devices
|
||||
-------------------
|
||||
|
||||
A device can only be paired with one application at a time. Thus, when a
|
||||
device is paired with Tuhi, other applications (e.g. Wacom Inkspace)
|
||||
cannot not connect to the device anymore. Likewise, when paired with another
|
||||
application, Tuhi cannot connect.
|
||||
For a device to work with Tuhi, it must be registered first. This is
|
||||
achieved by holiding the device button for 6 or more seconds until the blue
|
||||
LED starts blinking. Only in that mode can Tuhi detect it during
|
||||
`Searching` and register it.
|
||||
|
||||
To make the tablet connect again, simply re-pair with the respective
|
||||
Registration sends a randomly generated UUID to the device. Subsequent
|
||||
connections must use that UUID as identifier for the tablet device to
|
||||
respond. Without knowing that UUID, other applications cannot connect.
|
||||
|
||||
A device can only be registered with one application at a time. Thus, when a
|
||||
device is registered with Tuhi, other applications (e.g. Wacom Inkspace)
|
||||
cannot not connect to the device anymore. Likewise, when registered with
|
||||
another application, Tuhi cannot connect.
|
||||
|
||||
To make the tablet connect again, simply re-register with the respective
|
||||
application or Tuhi, whichever desired.
|
||||
|
||||
The reason for this behavior is that pairing assigns a application-generated
|
||||
unique UUID to the device. Subsequent connections must use that UUID for the
|
||||
tablet device to respond. Without knowing that UUID, other applications
|
||||
cannot connect.
|
||||
This is not registering the device with some cloud service, vendor, or
|
||||
other networked service. It is a communication between Tuhi and the firmware
|
||||
on the device only. It is merely a process of "your ID is now $foo" followed
|
||||
by "hi $foo, I want to connect".
|
||||
|
||||
The word "register" was chosen because "pairing" is already in use by
|
||||
Bluetooth.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
@ -64,36 +76,35 @@ The following interfaces are provided:
|
|||
org.freedesktop.tuhi1.Manager
|
||||
|
||||
Property: Devices (ao)
|
||||
Array of object paths to known (previously paired, but not necessarily
|
||||
connected) devices. Note that a "paired" device is one that has been
|
||||
initialized via the Wacom SmartPad custom protocol. This
|
||||
initialization is independent of the Bluetooth pairing process. A Tuhi
|
||||
paired device may or may not be paired over Bluetooth.
|
||||
Array of object paths to known (previously registered, but not necessarily
|
||||
connected) devices. Note that a "registered" device is one that has been
|
||||
initialized via the Wacom SmartPad custom protocol. A device does not
|
||||
need to be paired over Bluetooth to register.
|
||||
|
||||
Property: Searching (b)
|
||||
Indicates whether the daemon is currently searching for pairable devices.
|
||||
Indicates whether the daemon is currently searching for devices.
|
||||
|
||||
This property is set to True when a StartSearching() request initiates
|
||||
the search for device connections. When the StartSearching() request
|
||||
completes upon timeout, or when StopSearching() is called, the property
|
||||
is set to False.
|
||||
|
||||
When a pariable device is found, the PairableDevice signal is sent to
|
||||
When a pariable device is found, the UnregisteredDevice signal is sent to
|
||||
the caller that initiated the search process.
|
||||
|
||||
Read-only
|
||||
|
||||
Method: StartSearch() -> ()
|
||||
Start searching for available devices in pairing mode for an
|
||||
unspecified timeout. When the timeout expires or an error occurs, a
|
||||
SearchStopped signal is sent indicating success or error.
|
||||
Start searching for available devices ready for registering
|
||||
for an unspecified timeout. When the timeout expires or an error
|
||||
occurs, a SearchStopped signal is sent indicating success or error.
|
||||
|
||||
If a client that successfully initated a listening process calls
|
||||
StartSearching() again, that call is ignored and no signal is
|
||||
generated for that call.
|
||||
|
||||
Method: StopSearch() -> ()
|
||||
Stop listening to available devices in pairing mode. If called after
|
||||
Stop listening to available devices ready for registering. If called after
|
||||
StartSearch() and before a SearchStopped signal has been received,
|
||||
this method triggers the SearchStopped signal. That signal indicates
|
||||
success or an error.
|
||||
|
@ -102,10 +113,10 @@ org.freedesktop.tuhi1.Manager
|
|||
SearchStopped signal, it is ignored and no signal is generated.
|
||||
|
||||
Note that between calling StopSearch() and the SearchStopped signal
|
||||
arriving, PairableDevice signals may still arrive.
|
||||
arriving, UnregisteredDevice signals may still arrive.
|
||||
|
||||
Signal: PairableDevice(o)
|
||||
Indicates that a device is available for pairing. This signal may be
|
||||
Signal: UnregisteredDevice(o)
|
||||
Indicates that a device can be registered. This signal may be
|
||||
sent after a StartSearch() call and before SearchStopped(). This
|
||||
signal is sent once per available device and only to the client that
|
||||
initiated the search process with StartSearch.
|
||||
|
@ -113,18 +124,18 @@ org.freedesktop.tuhi1.Manager
|
|||
When this signal is sent, a org.freedesktop.tuhi1.Device object was
|
||||
created, the object path is the argument to this signal.
|
||||
|
||||
A client must immediately call Pair() on that object if pairing with
|
||||
that object is desired. See the documentation for that interface
|
||||
for details.
|
||||
A client must immediately call Register() on that object if
|
||||
registering with that object is desired. See the documentation for
|
||||
that interface for details.
|
||||
|
||||
When the search timeout expires, the device may be removed by the
|
||||
daemon again. Note that until the device is paired, the device is not
|
||||
daemon again. Note that until the device is registered, the device is not
|
||||
listed in the managers Devices property.
|
||||
|
||||
Signal: SearchStopped(i)
|
||||
Sent when the search has stopped. An argument of 0 indicates a
|
||||
successful termination of the search process, either when a device
|
||||
has been paired or the timeout expired.
|
||||
has been registered or the timeout expired.
|
||||
|
||||
If the errno is -EAGAIN, the daemon is already searching for devices
|
||||
on behalf of another client. In this case, this client should wait for
|
||||
|
@ -132,8 +143,8 @@ org.freedesktop.tuhi1.Manager
|
|||
property is set to False.
|
||||
|
||||
Once this signal has been sent, all devices announced through
|
||||
PairableDevice signals should be considered invalidated. Attempting to
|
||||
Pair() one of the devices after the SearchStopped() signal may result
|
||||
UnregisteredDevice signals should be considered invalidated. Attempting to
|
||||
Register() one of the devices after the SearchStopped() signal may result
|
||||
in an error.
|
||||
|
||||
In case of error, the argument is a negative errno.
|
||||
|
@ -208,11 +219,11 @@ org.freedesktop.tuhi1.Device
|
|||
|
||||
Read-only
|
||||
|
||||
Method: Pair() -> (i)
|
||||
Pair the device. If the device is already paired, calls to this method
|
||||
immediately return success.
|
||||
Method: Register() -> (i)
|
||||
Register the device. If the device is already registered, calls to
|
||||
this method immediately return success.
|
||||
|
||||
Otherwise, the device is paired and this function returns success (0)
|
||||
Otherwise, the device is registered and this function returns success (0)
|
||||
or a negative errno on failure.
|
||||
|
||||
Method: StartListening() -> ()
|
||||
|
@ -270,14 +281,14 @@ org.freedesktop.tuhi1.Device
|
|||
the Listening property to change and StartListening() once the
|
||||
property is set to False.
|
||||
|
||||
If the error is -EBADE, the device is not in pairing/listening mode
|
||||
and pairing/listening was requested. In this case, the client should
|
||||
indicate to the user that the device needs to be paired first or
|
||||
switched to listening mode.
|
||||
If the error is -EBADE, the device is not ready for registering/in
|
||||
listening mode and registration/listening was requested. In
|
||||
this case, the client should indicate to the user that the device
|
||||
needs to be registered first or switched to listening mode.
|
||||
|
||||
If the error is -EACCES, the device is not paired with the daemon or
|
||||
incorrectly paired. This may happen when the device was paired with
|
||||
another host since the last connection.
|
||||
If the error is -EACCES, the device is not registered with the daemon
|
||||
or incorrectly registered. This may happen when the device was
|
||||
registered with another host since the last connection.
|
||||
|
||||
The following other errnos may be sent by the daemon:
|
||||
-EPROTO: the daemon has encountered a protocol error with the device.
|
||||
|
|
|
@ -168,7 +168,7 @@ class TuhiKeteDevice(_DBusObject):
|
|||
ORG_FREEDESKTOP_TUHI1_DEVICE,
|
||||
objpath)
|
||||
self.manager = manager
|
||||
self.is_pairing = False
|
||||
self.is_registering = False
|
||||
self._bluez_device = BlueZDevice(self.property('BlueZDevice'))
|
||||
|
||||
@classmethod
|
||||
|
@ -201,13 +201,13 @@ class TuhiKeteDevice(_DBusObject):
|
|||
def battery_state(self):
|
||||
return self.property('BatteryState')
|
||||
|
||||
def pair(self):
|
||||
logger.debug(f'{self}: Pairing')
|
||||
# FIXME: Pair() doesn't return anything useful yet, so we wait until
|
||||
def register(self):
|
||||
logger.debug(f'{self}: Register')
|
||||
# FIXME: Register() doesn't return anything useful yet, so we wait until
|
||||
# the device is in the Manager's Devices property
|
||||
self.s1 = self.manager.connect('notify::devices', self._on_mgr_devices_updated)
|
||||
self.is_pairing = True
|
||||
self.proxy.Pair()
|
||||
self.is_registering = True
|
||||
self.proxy.Register()
|
||||
|
||||
def start_listening(self):
|
||||
self.proxy.StartListening()
|
||||
|
@ -224,7 +224,7 @@ class TuhiKeteDevice(_DBusObject):
|
|||
elif signal == 'ListeningStopped':
|
||||
err = parameters[0]
|
||||
if err == -errno.EACCES:
|
||||
logger.error(f'{self}: wrong device, please redo pairing.')
|
||||
logger.error(f'{self}: wrong device, please re-register.')
|
||||
elif err < 0:
|
||||
logger.error(f'{self}: an error occured: {os.strerror(-err)}')
|
||||
self.notify('listening')
|
||||
|
@ -248,15 +248,15 @@ class TuhiKeteDevice(_DBusObject):
|
|||
return f'{self.address} - {self.name}'
|
||||
|
||||
def _on_mgr_devices_updated(self, manager, pspec):
|
||||
if not self.is_pairing:
|
||||
if not self.is_registering:
|
||||
return
|
||||
|
||||
for d in manager.devices:
|
||||
if d.address == self.address:
|
||||
self.is_pairing = False
|
||||
self.is_registering = False
|
||||
self.manager.disconnect(self.s1)
|
||||
del(self.s1)
|
||||
logger.info(f'{self}: Pairing successful')
|
||||
logger.info(f'{self}: Registration successful')
|
||||
|
||||
def terminate(self):
|
||||
try:
|
||||
|
@ -269,7 +269,7 @@ class TuhiKeteDevice(_DBusObject):
|
|||
|
||||
class TuhiKeteManager(_DBusObject):
|
||||
__gsignals__ = {
|
||||
'pairable-device':
|
||||
'unregistered-device':
|
||||
(GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ class TuhiKeteManager(_DBusObject):
|
|||
ROOT_PATH)
|
||||
|
||||
self._devices = {}
|
||||
self._pairable_devices = {}
|
||||
self._unregistered_devices = {}
|
||||
|
||||
for objpath in self.property('Devices'):
|
||||
device = TuhiKeteDevice(self, objpath)
|
||||
|
@ -290,15 +290,15 @@ class TuhiKeteManager(_DBusObject):
|
|||
return [v for k, v in self._devices.items()]
|
||||
|
||||
@GObject.Property
|
||||
def pairable_devices(self):
|
||||
return [v for k, v in self._pairable_devices.items()]
|
||||
def unregistered_devices(self):
|
||||
return [v for k, v in self._unregistered_devices.items()]
|
||||
|
||||
@GObject.Property
|
||||
def searching(self):
|
||||
return self.proxy.get_cached_property('Searching')
|
||||
|
||||
def start_search(self):
|
||||
self._pairable_devices = {}
|
||||
self._unregistered_devices = {}
|
||||
self.proxy.StartSearch()
|
||||
|
||||
def stop_search(self):
|
||||
|
@ -309,13 +309,13 @@ class TuhiKeteManager(_DBusObject):
|
|||
e.code != Gio.IOErrorEnum.EXISTS or
|
||||
Gio.dbus_error_get_remote_error(e) != 'org.freedesktop.DBus.Error.ServiceUnknown'):
|
||||
raise e
|
||||
self._pairable_devices = {}
|
||||
self._unregistered_devices = {}
|
||||
|
||||
def terminate(self):
|
||||
for dev in self._devices.values():
|
||||
dev.terminate()
|
||||
self._devices = {}
|
||||
self._pairable_devices = {}
|
||||
self._unregistered_devices = {}
|
||||
super(TuhiKeteManager, self).terminate()
|
||||
|
||||
def _on_properties_changed(self, proxy, changed_props, invalidated_props):
|
||||
|
@ -328,24 +328,24 @@ class TuhiKeteManager(_DBusObject):
|
|||
objpaths = changed_props['Devices']
|
||||
for objpath in objpaths:
|
||||
try:
|
||||
d = self._pairable_devices[objpath]
|
||||
d = self._unregistered_devices[objpath]
|
||||
self._devices[d.address] = d
|
||||
del self._pairable_devices[objpath]
|
||||
del self._unregistered_devices[objpath]
|
||||
except KeyError:
|
||||
# if we called Pair() on an existing device it's not in
|
||||
# pairable devices
|
||||
# if we called Register() on an existing device it's not
|
||||
# in unregistered devices
|
||||
pass
|
||||
self.notify('devices')
|
||||
|
||||
def _on_signal_received(self, proxy, sender, signal, parameters):
|
||||
if signal == 'SearchStopped':
|
||||
self.notify('searching')
|
||||
elif signal == 'PairableDevice':
|
||||
elif signal == 'UnregisteredDevice':
|
||||
objpath = parameters[0]
|
||||
device = TuhiKeteDevice(self, objpath)
|
||||
self._pairable_devices[objpath] = device
|
||||
logger.debug(f'Found pairable device: {device}')
|
||||
self.emit('pairable-device', device)
|
||||
self._unregistered_devices[objpath] = device
|
||||
logger.debug(f'Found unregistered device: {device}')
|
||||
self.emit('unregistered-device', device)
|
||||
|
||||
def __getitem__(self, btaddr):
|
||||
return self._devices[btaddr]
|
||||
|
@ -374,7 +374,7 @@ class Searcher(Worker):
|
|||
def __init__(self, manager, args):
|
||||
super(Searcher, self).__init__(manager)
|
||||
self.s1 = self.manager.connect('notify::searching', self._on_notify_search)
|
||||
self.s2 = self.manager.connect('pairable-device', self._on_pairable_device)
|
||||
self.s2 = self.manager.connect('unregistered-device', self._on_unregistered_device)
|
||||
|
||||
def run(self):
|
||||
if self.manager.searching:
|
||||
|
@ -385,7 +385,7 @@ class Searcher(Worker):
|
|||
logger.debug('Started searching')
|
||||
|
||||
for d in self.manager.devices:
|
||||
self._on_pairable_device(self.manager, d)
|
||||
self._on_unregistered_device(self.manager, d)
|
||||
|
||||
def stop(self):
|
||||
if self.manager.searching:
|
||||
|
@ -399,8 +399,8 @@ class Searcher(Worker):
|
|||
if not manager.searching:
|
||||
logger.info('Search cancelled')
|
||||
|
||||
def _on_pairable_device(self, manager, device):
|
||||
logger.info(f'Pairable device: {device}')
|
||||
def _on_unregistered_device(self, manager, device):
|
||||
logger.info(f'Unregistered device: {device}')
|
||||
|
||||
|
||||
class Listener(Worker):
|
||||
|
@ -655,7 +655,8 @@ class TuhiKeteShell(cmd.Cmd):
|
|||
self._workers = []
|
||||
|
||||
def do_devices(self, arg):
|
||||
'''List known devices. These are devices previously paired with the daemon.'''
|
||||
'''List known devices. These are devices previously registered with
|
||||
the daemon.'''
|
||||
logger.debug('Listing available devices:')
|
||||
for d in self._manager.devices:
|
||||
print(d)
|
||||
|
@ -840,8 +841,8 @@ class TuhiKeteShell(cmd.Cmd):
|
|||
|
||||
def do_search(self, args):
|
||||
desc = '''
|
||||
Start/Stop listening for devices that can be paired with the daemon.
|
||||
The devices must be in pairable mode (blue LED blinking).
|
||||
Start/Stop listening for devices that can be registered with the
|
||||
daemon. The devices must be in registration mode (blue LED blinking).
|
||||
'''
|
||||
parser = argparse.ArgumentParser(prog='search',
|
||||
description=desc,
|
||||
|
@ -869,10 +870,10 @@ class TuhiKeteShell(cmd.Cmd):
|
|||
else:
|
||||
logger.info('Already searching')
|
||||
|
||||
def help_pair(self):
|
||||
self.do_pair('-h')
|
||||
def help_register(self):
|
||||
self.do_register('-h')
|
||||
|
||||
def complete_pair(self, text, line, begidx, endidx):
|
||||
def complete_register(self, text, line, begidx, endidx):
|
||||
# mark the end of the line so we can match on the number of fields
|
||||
if line.endswith(' '):
|
||||
line += 'm'
|
||||
|
@ -880,29 +881,29 @@ class TuhiKeteShell(cmd.Cmd):
|
|||
|
||||
completion = []
|
||||
if len(fields) == 2:
|
||||
for device in self._manager.pairable_devices + self._manager.devices:
|
||||
for device in self._manager.unregistered_devices + self._manager.devices:
|
||||
if device.address.startswith(text.upper()):
|
||||
completion.append(device.address)
|
||||
|
||||
return completion
|
||||
|
||||
def do_pair(self, args):
|
||||
def do_register(self, args):
|
||||
if not self._manager.searching and '-h' not in args.split():
|
||||
print('please call search first')
|
||||
return
|
||||
|
||||
desc = '''
|
||||
Pair the given device. The device must be in pairable mode (blue LED
|
||||
blinking).
|
||||
Register the given device. The device must be in registration mode
|
||||
(blue LED blinking).
|
||||
'''
|
||||
parser = argparse.ArgumentParser(prog='pair',
|
||||
parser = argparse.ArgumentParser(prog='register',
|
||||
description=desc,
|
||||
add_help=False)
|
||||
parser.add_argument('-h', action='help', help=argparse.SUPPRESS)
|
||||
parser.add_argument('address', metavar='12:34:56:AB:CD:EF',
|
||||
type=TuhiKeteDevice.is_device_address,
|
||||
default=None,
|
||||
help='the address of the device to pair')
|
||||
help='the address of the device to register')
|
||||
|
||||
try:
|
||||
parsed_args = parser.parse_args(args.split())
|
||||
|
@ -918,7 +919,7 @@ class TuhiKeteShell(cmd.Cmd):
|
|||
if worker.device.address == address:
|
||||
self.terminate_worker(worker)
|
||||
|
||||
for d in self._manager.devices + self._manager.pairable_devices:
|
||||
for d in self._manager.devices + self._manager.unregistered_devices:
|
||||
if d.address == address:
|
||||
device = d
|
||||
break
|
||||
|
@ -926,7 +927,7 @@ class TuhiKeteShell(cmd.Cmd):
|
|||
logger.error(f'{address}: device not found')
|
||||
return
|
||||
|
||||
device.pair()
|
||||
device.register()
|
||||
|
||||
def help_info(self):
|
||||
self.do_info('-h')
|
||||
|
|
50
tuhi/base.py
50
tuhi/base.py
|
@ -51,13 +51,13 @@ class TuhiDevice(GObject.Object):
|
|||
|
||||
BATTERY_UPDATE_MIN_INTERVAL = 300
|
||||
|
||||
def __init__(self, bluez_device, config, uuid=None, paired=True):
|
||||
def __init__(self, bluez_device, config, uuid=None, registered=True):
|
||||
GObject.Object.__init__(self)
|
||||
self.config = config
|
||||
self._wacom_device = None
|
||||
# We need either uuid or paired as false
|
||||
assert uuid is not None or paired is False
|
||||
self.paired = paired
|
||||
# We need either uuid or registered as false
|
||||
assert uuid is not None or registered is False
|
||||
self.registered = registered
|
||||
self._uuid = uuid
|
||||
self._battery_state = TuhiDevice.BatteryState.UNKNOWN
|
||||
self._battery_percent = 0
|
||||
|
@ -71,12 +71,12 @@ class TuhiDevice(GObject.Object):
|
|||
self._tuhi_dbus_device = None
|
||||
|
||||
@GObject.Property
|
||||
def paired(self):
|
||||
return self._paired
|
||||
def registered(self):
|
||||
return self._registered
|
||||
|
||||
@paired.setter
|
||||
def paired(self, paired):
|
||||
self._paired = paired
|
||||
@registered.setter
|
||||
def registered(self, registered):
|
||||
self._registered = registered
|
||||
|
||||
@GObject.Property
|
||||
def name(self):
|
||||
|
@ -98,7 +98,7 @@ class TuhiDevice(GObject.Object):
|
|||
def dbus_device(self, device):
|
||||
assert self._tuhi_dbus_device is None
|
||||
self._tuhi_dbus_device = device
|
||||
self._tuhi_dbus_device.connect('pair-requested', self._on_pair_requested)
|
||||
self._tuhi_dbus_device.connect('register-requested', self._on_register_requested)
|
||||
self._tuhi_dbus_device.connect('notify::listening', self._on_listening_updated)
|
||||
|
||||
drawings = self.config.load_drawings(self.address)
|
||||
|
@ -140,14 +140,14 @@ class TuhiDevice(GObject.Object):
|
|||
self._wacom_device.connect('notify::uuid', self._on_uuid_updated, bluez_device)
|
||||
self._wacom_device.connect('battery-status', self._on_battery_status, bluez_device)
|
||||
|
||||
self._wacom_device.start(not self.paired)
|
||||
self.pairing_mode = False
|
||||
self._wacom_device.start(not self.registered)
|
||||
self.registering_mode = False
|
||||
|
||||
def _on_bluez_device_disconnected(self, bluez_device):
|
||||
logger.debug(f'{bluez_device.address}: disconnected')
|
||||
|
||||
def _on_pair_requested(self, dbus_device):
|
||||
if self.paired:
|
||||
def _on_register_requested(self, dbus_device):
|
||||
if self.registered:
|
||||
return
|
||||
|
||||
self.connect_device()
|
||||
|
@ -168,7 +168,7 @@ class TuhiDevice(GObject.Object):
|
|||
|
||||
def _on_uuid_updated(self, wacom_device, pspec, bluez_device):
|
||||
self.config.new_device(bluez_device.address, wacom_device.uuid)
|
||||
self.paired = True
|
||||
self.registered = True
|
||||
|
||||
def _on_listening_updated(self, dbus_device, pspec):
|
||||
self.notify('listening')
|
||||
|
@ -243,7 +243,7 @@ class Tuhi(GObject.Object):
|
|||
self._search_device_handler = None
|
||||
|
||||
@classmethod
|
||||
def _is_pairing_device(cls, bluez_device):
|
||||
def _device_in_register_mode(cls, bluez_device):
|
||||
if bluez_device.vendor_id != WACOM_COMPANY_ID:
|
||||
return False
|
||||
|
||||
|
@ -278,29 +278,29 @@ class Tuhi(GObject.Object):
|
|||
|
||||
# if event is set, the device has been 'hotplugged' in the bluez stack
|
||||
# so ManufacturerData is reliable. Else, consider the device not in
|
||||
# the pairing mode
|
||||
pairing_device = False
|
||||
# the register mode
|
||||
register_mode = False
|
||||
if event:
|
||||
pairing_device = Tuhi._is_pairing_device(bluez_device)
|
||||
register_mode = Tuhi._device_in_register_mode(bluez_device)
|
||||
|
||||
if not pairing_device:
|
||||
if not register_mode:
|
||||
if uuid is None:
|
||||
logger.info(f'{bluez_device.address}: device without config, must be paired first')
|
||||
logger.info(f'{bluez_device.address}: device without config, must be registered first')
|
||||
return
|
||||
logger.debug(f'{bluez_device.address}: UUID {uuid}')
|
||||
|
||||
# create the device if unknown from us
|
||||
if bluez_device.address not in self.devices:
|
||||
d = TuhiDevice(bluez_device, self.config, uuid=uuid, paired=not pairing_device)
|
||||
d = TuhiDevice(bluez_device, self.config, uuid=uuid, registered=not register_mode)
|
||||
d.dbus_device = self.server.create_device(d)
|
||||
d.connect('notify::listening', self._on_listening_updated)
|
||||
self.devices[bluez_device.address] = d
|
||||
|
||||
d = self.devices[bluez_device.address]
|
||||
|
||||
if pairing_device:
|
||||
d.paired = False
|
||||
logger.debug(f'{bluez_device.objpath}: call Pair() on device')
|
||||
if register_mode:
|
||||
d.registered = False
|
||||
logger.debug(f'{bluez_device.objpath}: call Register() on device')
|
||||
elif d.listening:
|
||||
d.connect_device()
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ INTROSPECTION_XML = '''
|
|||
<arg name='status' type='i' />
|
||||
</signal>
|
||||
|
||||
<signal name='PairableDevice'>
|
||||
<signal name='UnregisteredDevice'>
|
||||
<arg name='info' type='o' />
|
||||
</signal>
|
||||
</interface>
|
||||
|
@ -62,7 +62,7 @@ INTROSPECTION_XML = '''
|
|||
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
|
||||
</property>
|
||||
|
||||
<method name='Pair'>
|
||||
<method name='Register'>
|
||||
<arg name='result' type='i' direction='out'/>
|
||||
</method>
|
||||
|
||||
|
@ -134,7 +134,7 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
handles the DBus bits, communication with the device is done elsewhere.
|
||||
'''
|
||||
__gsignals__ = {
|
||||
'pair-requested':
|
||||
'register-requested':
|
||||
(GObject.SignalFlags.RUN_FIRST, None, ()),
|
||||
}
|
||||
|
||||
|
@ -147,13 +147,13 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
self.name = device.name
|
||||
self.width, self.height = 0, 0
|
||||
self.drawings = {}
|
||||
self.paired = device.paired
|
||||
self.registered = device.registered
|
||||
self._listening = False
|
||||
self._listening_client = None
|
||||
self._dbusid = self._register_object(connection)
|
||||
self._battery_percent = 0
|
||||
self._battery_state = device.battery_state
|
||||
device.connect('notify::paired', self._on_device_paired)
|
||||
device.connect('notify::registered', self._on_device_registered)
|
||||
device.connect('notify::battery-percent', self._on_battery_percent)
|
||||
device.connect('notify::battery-state', self._on_battery_state)
|
||||
device.connect('device-error', self._on_device_error)
|
||||
|
@ -171,12 +171,12 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
self.properties_changed({'Listening': GLib.Variant.new_boolean(value)})
|
||||
|
||||
@GObject.Property
|
||||
def paired(self):
|
||||
return self._paired
|
||||
def registered(self):
|
||||
return self._registered
|
||||
|
||||
@paired.setter
|
||||
def paired(self, paired):
|
||||
self._paired = paired
|
||||
@registered.setter
|
||||
def registered(self, registered):
|
||||
self._registered = registered
|
||||
|
||||
@GObject.Property
|
||||
def battery_percent(self):
|
||||
|
@ -219,10 +219,10 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
if interface != self.interface:
|
||||
return None
|
||||
|
||||
if methodname == 'Pair':
|
||||
if methodname == 'Register':
|
||||
# FIXME: we should cache the method invocation here, wait for a
|
||||
# successful result from Tuhi and then return the value
|
||||
self._pair()
|
||||
self._register()
|
||||
result = GLib.Variant.new_int32(0)
|
||||
invocation.return_value(GLib.Variant.new_tuple(result))
|
||||
elif methodname == 'StartListening':
|
||||
|
@ -262,13 +262,13 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
def _property_write_cb(self):
|
||||
pass
|
||||
|
||||
def _pair(self):
|
||||
self.emit('pair-requested')
|
||||
def _register(self):
|
||||
self.emit('register-requested')
|
||||
|
||||
def _on_device_paired(self, device, pspec):
|
||||
if self.paired == device.paired:
|
||||
def _on_device_registered(self, device, pspec):
|
||||
if self.registered == device.registered:
|
||||
return
|
||||
self.paired = device.paired
|
||||
self.registered = device.registered
|
||||
|
||||
def _on_battery_percent(self, device, pspec):
|
||||
self.battery_percent = device.battery_percent
|
||||
|
@ -378,7 +378,7 @@ class TuhiDBusServer(_TuhiDBus):
|
|||
def __init__(self):
|
||||
_TuhiDBus.__init__(self, None, BASE_PATH, INTF_MANAGER)
|
||||
self._devices = []
|
||||
self._pairable_devices = {}
|
||||
self._unregistered_devices = {}
|
||||
self._dbus = Gio.bus_own_name(Gio.BusType.SESSION,
|
||||
BUS_NAME,
|
||||
Gio.BusNameOwnerFlags.NONE,
|
||||
|
@ -435,7 +435,7 @@ class TuhiDBusServer(_TuhiDBus):
|
|||
return None
|
||||
|
||||
if propname == 'Devices':
|
||||
return GLib.Variant.new_objv([d.objpath for d in self._devices if d.paired])
|
||||
return GLib.Variant.new_objv([d.objpath for d in self._devices if d.registered])
|
||||
elif propname == 'Searching':
|
||||
return GLib.Variant.new_boolean(self.is_searching)
|
||||
|
||||
|
@ -469,8 +469,8 @@ class TuhiDBusServer(_TuhiDBus):
|
|||
|
||||
self.emit('search-start-requested', self._on_search_stop)
|
||||
for d in self._devices:
|
||||
if not d.paired:
|
||||
self._emit_pairable_signal(d)
|
||||
if not d.registered:
|
||||
self._emit_unregistered_signal(d)
|
||||
|
||||
def _on_name_owner_changed_signal_cb(self, connection, sender, object_path,
|
||||
interface_name, node,
|
||||
|
@ -500,29 +500,29 @@ class TuhiDBusServer(_TuhiDBus):
|
|||
self._searching_client = None
|
||||
|
||||
for dev in self._devices:
|
||||
if dev.paired:
|
||||
if dev.registered:
|
||||
continue
|
||||
|
||||
dev.remove()
|
||||
self._devices = [d for d in self._devices if d.paired]
|
||||
self._devices = [d for d in self._devices if d.registered]
|
||||
|
||||
def cleanup(self):
|
||||
Gio.bus_unown_name(self._dbus)
|
||||
|
||||
def create_device(self, device):
|
||||
dev = TuhiDBusDevice(device, self.connection)
|
||||
dev.connect('notify::paired', self._on_device_paired)
|
||||
dev.connect('notify::registered', self._on_device_registered)
|
||||
self._devices.append(dev)
|
||||
if not device.paired:
|
||||
self._emit_pairable_signal(dev)
|
||||
if not device.registered:
|
||||
self._emit_unregistered_signal(dev)
|
||||
return dev
|
||||
|
||||
def _on_device_paired(self, device, param):
|
||||
def _on_device_registered(self, device, param):
|
||||
objpaths = GLib.Variant.new_array(GLib.VariantType('o'),
|
||||
[GLib.Variant.new_object_path(d.objpath)
|
||||
for d in self._devices if d.paired])
|
||||
for d in self._devices if d.registered])
|
||||
self.properties_changed({'Devices': objpaths})
|
||||
|
||||
def _emit_pairable_signal(self, device):
|
||||
def _emit_unregistered_signal(self, device):
|
||||
arg = GLib.Variant.new_object_path(device.objpath)
|
||||
self.signal('PairableDevice', arg, dest=self._searching_client[0])
|
||||
self.signal('UnregisteredDevice', arg, dest=self._searching_client[0])
|
||||
|
|
|
@ -82,7 +82,7 @@ class WacomWrongModeException(WacomException):
|
|||
errno = errno.EBADE
|
||||
|
||||
|
||||
class WacomNotPairedException(WacomException):
|
||||
class WacomNotRegisteredException(WacomException):
|
||||
errno = errno.EACCES
|
||||
|
||||
|
||||
|
@ -239,7 +239,7 @@ class WacomDevice(GObject.Object):
|
|||
str_b = binascii.hexlify(bytes(data))
|
||||
raise WacomException(f'unexpected data: {str_b}')
|
||||
if data[0] == 0x07:
|
||||
raise WacomNotPairedException(f'wrong device, please redo pairing')
|
||||
raise WacomNotRegisteredException(f'wrong device, please re-register')
|
||||
if data[0] == 0x02:
|
||||
raise WacomEEAGAINException(f'unexpected answer: {data[0]:02x}')
|
||||
if data[0] == 0x01:
|
||||
|
@ -574,7 +574,7 @@ 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 pair_device_slate(self):
|
||||
def register_device_slate(self):
|
||||
self.register_connection()
|
||||
logger.info('Press the button now to confirm')
|
||||
self.emit('button-press-required')
|
||||
|
@ -594,7 +594,7 @@ class WacomDevice(GObject.Object):
|
|||
fw_low = self.get_firmware_version(1)
|
||||
logger.info(f'firmware is {fw_high}-{fw_low}')
|
||||
|
||||
def pair_device_spark(self):
|
||||
def register_device_spark(self):
|
||||
try:
|
||||
self.check_connection()
|
||||
except WacomWrongModeException:
|
||||
|
@ -619,14 +619,14 @@ class WacomDevice(GObject.Object):
|
|||
fw_low = self.get_firmware_version(1)
|
||||
logger.info(f'firmware is {fw_high}-{fw_low}')
|
||||
|
||||
def pair_device(self):
|
||||
def register_device(self):
|
||||
self._uuid = uuid.uuid4().hex[:12]
|
||||
logger.debug(f'{self.device.address}: pairing device, assigned {self.uuid}')
|
||||
logger.debug(f'{self.device.address}: registering device, assigned {self.uuid}')
|
||||
if self.is_spark():
|
||||
self.pair_device_spark()
|
||||
self.register_device_spark()
|
||||
else:
|
||||
self.pair_device_slate()
|
||||
logger.info('pairing completed')
|
||||
self.register_device_slate()
|
||||
logger.info('registration completed')
|
||||
self.notify('uuid')
|
||||
|
||||
def run(self):
|
||||
|
@ -638,19 +638,19 @@ class WacomDevice(GObject.Object):
|
|||
self._is_running = True
|
||||
exception = None
|
||||
try:
|
||||
if self._pairing_mode:
|
||||
self.pair_device()
|
||||
if self._register_mode:
|
||||
self.register_device()
|
||||
else:
|
||||
self.retrieve_data()
|
||||
except WacomException as e:
|
||||
logger.error(f'**** Exception: {e} ****')
|
||||
exception = e
|
||||
finally:
|
||||
self._pairing_mode = False
|
||||
self._register_mode = False
|
||||
self._is_running = False
|
||||
self.emit('done', exception)
|
||||
|
||||
def start(self, pairing_mode):
|
||||
self._pairing_mode = pairing_mode
|
||||
def start(self, register_mode):
|
||||
self._register_mode = register_mode
|
||||
self.thread = threading.Thread(target=self.run)
|
||||
self.thread.start()
|
||||
|
|
Loading…
Reference in New Issue