tuhi: hook up live mode
Currently just enable/disable live mode. The int parameter is doomed to be an opened fd to the uhid node
This commit is contained in:
parent
41a3c85b59
commit
1a6d0205df
16
tuhi/base.py
16
tuhi/base.py
|
@ -104,6 +104,7 @@ class TuhiDevice(GObject.Object):
|
|||
self._tuhi_dbus_device = device
|
||||
self._tuhi_dbus_device.connect('register-requested', self._on_register_requested)
|
||||
self._tuhi_dbus_device.connect('notify::listening', self._on_listening_updated)
|
||||
self._tuhi_dbus_device.connect('notify::live', self._on_live_updated)
|
||||
|
||||
drawings = self.config.load_drawings(self.address)
|
||||
if drawings:
|
||||
|
@ -115,6 +116,10 @@ class TuhiDevice(GObject.Object):
|
|||
def listening(self):
|
||||
return self._tuhi_dbus_device.listening
|
||||
|
||||
@GObject.Property
|
||||
def live(self):
|
||||
return self._tuhi_dbus_device.live
|
||||
|
||||
@GObject.Property
|
||||
def battery_percent(self):
|
||||
return self._battery_percent
|
||||
|
@ -154,6 +159,8 @@ class TuhiDevice(GObject.Object):
|
|||
|
||||
if mode == DeviceMode.REGISTER:
|
||||
self._wacom_device.start_register()
|
||||
elif mode == DeviceMode.LIVE:
|
||||
self._wacom_device.start_live(self._tuhi_dbus_device.uhid_fd)
|
||||
else:
|
||||
self._wacom_device.start_listen()
|
||||
|
||||
|
@ -184,6 +191,8 @@ class TuhiDevice(GObject.Object):
|
|||
self.config.store_drawing(self.address, drawing)
|
||||
|
||||
def _on_fetching_finished(self, device, exception, bluez_device):
|
||||
if self.live:
|
||||
return
|
||||
bluez_device.disconnect_device()
|
||||
if exception is not None:
|
||||
logger.info(exception)
|
||||
|
@ -202,6 +211,13 @@ class TuhiDevice(GObject.Object):
|
|||
def _on_listening_updated(self, dbus_device, pspec):
|
||||
self.notify('listening')
|
||||
|
||||
def _on_live_updated(self, dbus_device, pspec):
|
||||
if self.live:
|
||||
self._connect_device(DeviceMode.LIVE)
|
||||
else:
|
||||
if self._wacom_device is not None:
|
||||
self._wacom_device.stop_live()
|
||||
|
||||
def _on_battery_status(self, wacom_device, percent, is_charging, bluez_device):
|
||||
if is_charging:
|
||||
self.battery_state = TuhiDevice.BatteryState.CHARGING
|
||||
|
|
|
@ -52,6 +52,9 @@ INTROSPECTION_XML = '''
|
|||
<property type='b' name='Listening' access='read'>
|
||||
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
|
||||
</property>
|
||||
<property type='b' name='Live' access='read'>
|
||||
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
|
||||
</property>
|
||||
<property type='u' name='BatteryPercent' access='read'>
|
||||
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
|
||||
</property>
|
||||
|
@ -74,6 +77,15 @@ INTROSPECTION_XML = '''
|
|||
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
|
||||
</method>
|
||||
|
||||
<method name='StartLive'>
|
||||
<arg name='uhid' type='h' />
|
||||
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
|
||||
</method>
|
||||
|
||||
<method name='StopLive'>
|
||||
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
|
||||
</method>
|
||||
|
||||
<method name='GetJSONData'>
|
||||
<arg name='index' type='u' direction='in'/>
|
||||
<arg name='json' type='s' direction='out'/>
|
||||
|
@ -84,6 +96,10 @@ INTROSPECTION_XML = '''
|
|||
<signal name='ListeningStopped'>
|
||||
<arg name='status' type='i' />
|
||||
</signal>
|
||||
|
||||
<signal name='LiveStopped'>
|
||||
<arg name='status' type='i' />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
'''
|
||||
|
@ -150,6 +166,9 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
self.registered = device.registered
|
||||
self._listening = False
|
||||
self._listening_client = None
|
||||
self._live = False
|
||||
self._uhid_fd = None
|
||||
self._live_client = None
|
||||
self._dbusid = self._register_object(connection)
|
||||
self._battery_percent = 0
|
||||
self._battery_state = device.battery_state
|
||||
|
@ -170,6 +189,22 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
self._listening = value
|
||||
self.properties_changed({'Listening': GLib.Variant.new_boolean(value)})
|
||||
|
||||
@GObject.Property
|
||||
def live(self):
|
||||
return self._live
|
||||
|
||||
@live.setter
|
||||
def live(self, value):
|
||||
if self._live == value:
|
||||
return
|
||||
|
||||
self._live = value
|
||||
self.properties_changed({'Live': GLib.Variant.new_boolean(value)})
|
||||
|
||||
@GObject.Property
|
||||
def uhid_fd(self):
|
||||
return self._uhid_fd
|
||||
|
||||
@GObject.Property
|
||||
def registered(self):
|
||||
return self._registered
|
||||
|
@ -231,6 +266,12 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
elif methodname == 'StopListening':
|
||||
self._stop_listening(connection, sender)
|
||||
invocation.return_value()
|
||||
elif methodname == 'StartLive':
|
||||
self._start_live(connection, sender, args)
|
||||
invocation.return_value()
|
||||
elif methodname == 'StopLive':
|
||||
self._stop_live(connection, sender)
|
||||
invocation.return_value()
|
||||
elif methodname == 'GetJSONData':
|
||||
json = GLib.Variant.new_string(self._json_data(args))
|
||||
invocation.return_value(GLib.Variant.new_tuple(json))
|
||||
|
@ -252,6 +293,8 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
return ts
|
||||
elif propname == 'Listening':
|
||||
return GLib.Variant.new_boolean(self.listening)
|
||||
elif propname == 'Live':
|
||||
return GLib.Variant.new_boolean(self.live)
|
||||
elif propname == 'BatteryPercent':
|
||||
return GLib.Variant.new_uint32(self.battery_percent)
|
||||
elif propname == 'BatteryState':
|
||||
|
@ -315,6 +358,7 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
return
|
||||
|
||||
self._stop_listening(connection, user_data)
|
||||
self._stop_live(connection, user_data)
|
||||
|
||||
def _stop_listening(self, connection, sender, errno=0):
|
||||
if not self.listening or sender != self._listening_client[0]:
|
||||
|
@ -331,6 +375,43 @@ class TuhiDBusDevice(_TuhiDBus):
|
|||
self.listening = False
|
||||
self.notify('listening')
|
||||
|
||||
def _start_live(self, connection, sender, args):
|
||||
if self.live:
|
||||
logger.debug(f'{self} - already in live mode')
|
||||
|
||||
# silently ignore it for the current client but send EAGAIN to
|
||||
# other clients
|
||||
if sender != self._listening_client[0]:
|
||||
status = GLib.Variant.new_int32(-errno.EAGAIN)
|
||||
self.signal('LiveStopped', status, dest=sender)
|
||||
return
|
||||
|
||||
s = connection.signal_subscribe(sender='org.freedesktop.DBus',
|
||||
interface_name='org.freedesktop.DBus',
|
||||
member='NameOwnerChanged',
|
||||
object_path='/org/freedesktop/DBus',
|
||||
arg0=None,
|
||||
flags=Gio.DBusSignalFlags.NONE,
|
||||
callback=self._on_name_owner_changed_signal_cb,
|
||||
user_data=sender)
|
||||
self._live_client = (sender, s)
|
||||
logger.debug(f'Live mode started on {self.name} for {sender}')
|
||||
|
||||
self.live = True
|
||||
self._uhid_fd = args[0]
|
||||
|
||||
def _stop_live(self, connection, sender, errno=0):
|
||||
if not self.live or sender != self._live_client[0]:
|
||||
return
|
||||
|
||||
connection.signal_unsubscribe(self._live_client[1])
|
||||
self._live_client = None
|
||||
logger.debug(f'Live mode stopped on {self.name} for {sender}')
|
||||
|
||||
status = GLib.Variant.new_int32(errno)
|
||||
self.signal('LiveStopped', status, dest=sender)
|
||||
self.live = False
|
||||
|
||||
def _json_data(self, args):
|
||||
index = args[0]
|
||||
try:
|
||||
|
|
|
@ -51,6 +51,7 @@ class Protocol(enum.Enum):
|
|||
class DeviceMode(enum.Enum):
|
||||
REGISTER = 1
|
||||
LISTEN = 2
|
||||
LIVE = 3
|
||||
|
||||
|
||||
def signed_char_to_int(v):
|
||||
|
@ -274,6 +275,7 @@ class WacomProtocolBase(WacomProtocolLowLevelComm):
|
|||
def __init__(self, device, uuid):
|
||||
super().__init__(device)
|
||||
self._uuid = uuid
|
||||
self._timestamp = 0
|
||||
self.pen_data_buffer = []
|
||||
|
||||
device.connect_gatt_value(WACOM_CHRC_LIVE_PEN_DATA_UUID,
|
||||
|
@ -287,12 +289,14 @@ class WacomProtocolBase(WacomProtocolLowLevelComm):
|
|||
if value[0] == 0x10:
|
||||
pressure = int.from_bytes(value[2:4], byteorder='little')
|
||||
buttons = int(value[10])
|
||||
logger.info(f'New Pen Data: pressure: {pressure}, button: {buttons}')
|
||||
logger.debug(f'New Pen Data: pressure: {pressure}, button: {buttons}')
|
||||
elif value[0] == 0xa2:
|
||||
# entering proximity event
|
||||
length = value[1]
|
||||
pen_id = binascii.hexlify(bytes(value[2:]))
|
||||
logger.info(f'Pen {pen_id} entered proximity')
|
||||
# timestamp is now in ms
|
||||
timestamp = int.from_bytes(value[4:], byteorder='little') * 5
|
||||
self._timestamp = timestamp
|
||||
logger.debug(f'Pen entered proximity, timestamp: {timestamp}')
|
||||
elif value[0] == 0xa1:
|
||||
# data event
|
||||
length = value[1]
|
||||
|
@ -302,13 +306,14 @@ class WacomProtocolBase(WacomProtocolLowLevelComm):
|
|||
data = value[2:]
|
||||
while data:
|
||||
if bytes(data) == b'\xff\xff\xff\xff\xff\xff':
|
||||
logger.info(f'Pen left proximity')
|
||||
logger.debug(f'Pen left proximity')
|
||||
else:
|
||||
x = int.from_bytes(data[0:2], byteorder='little')
|
||||
y = int.from_bytes(data[2:4], byteorder='little')
|
||||
pressure = int.from_bytes(data[4:6], byteorder='little')
|
||||
self.logger.info(f'New Pen Data: ({x},{y}), pressure: {pressure}')
|
||||
logger.debug(f'New Pen Data: ({x},{y}), pressure: {pressure}')
|
||||
data = data[6:]
|
||||
self._timestamp += 5
|
||||
|
||||
def _on_pen_data_received(self, name, data):
|
||||
self.fw_logger.debug(f'RX Pen <-- {list2hex(data)}')
|
||||
|
@ -384,9 +389,10 @@ class WacomProtocolBase(WacomProtocolLowLevelComm):
|
|||
expected_opcode=0xb3,
|
||||
arguments=args)
|
||||
|
||||
def start_live(self):
|
||||
def start_live(self, uhid):
|
||||
self.send_nordic_command_sync(command=0xb1,
|
||||
expected_opcode=0xb3)
|
||||
logger.debug(f'Starting wacom live mode on fd: {uhid}')
|
||||
|
||||
def stop_live(self):
|
||||
args = [0x02]
|
||||
|
@ -609,6 +615,16 @@ class WacomProtocolBase(WacomProtocolLowLevelComm):
|
|||
fw_low = self.get_firmware_version(1)
|
||||
logger.info(f'firmware is {fw_high}-{fw_low}')
|
||||
|
||||
def live_mode(self, mode, uhid):
|
||||
try:
|
||||
if mode:
|
||||
self.check_connection()
|
||||
self.start_live(uhid)
|
||||
else:
|
||||
self.stop_live()
|
||||
except WacomEEAGAINException:
|
||||
logger.warning("no data, please make sure the LED is blue and the button is pressed to switch it back to green")
|
||||
|
||||
|
||||
class WacomProtocolSpark(WacomProtocolBase):
|
||||
'''
|
||||
|
@ -829,7 +845,10 @@ class WacomDevice(GObject.Object):
|
|||
self._is_running = True
|
||||
exception = None
|
||||
try:
|
||||
if mode == DeviceMode.REGISTER:
|
||||
if mode == DeviceMode.LIVE:
|
||||
assert self._wacom_protocol is not None
|
||||
self._wacom_protocol.live_mode(args[1], args[2])
|
||||
elif mode == DeviceMode.REGISTER:
|
||||
self.register_device()
|
||||
else:
|
||||
assert self._wacom_protocol is not None
|
||||
|
@ -845,6 +864,14 @@ class WacomDevice(GObject.Object):
|
|||
self.thread = threading.Thread(target=self._run, args=(DeviceMode.LISTEN,))
|
||||
self.thread.start()
|
||||
|
||||
def start_live(self, uhid_fd):
|
||||
self.thread = threading.Thread(target=self._run, args=(DeviceMode.LIVE, True, uhid_fd))
|
||||
self.thread.start()
|
||||
|
||||
def stop_live(self):
|
||||
self.thread = threading.Thread(target=self._run, args=(DeviceMode.LIVE, False, -1))
|
||||
self.thread.start()
|
||||
|
||||
def start_register(self):
|
||||
self.thread = threading.Thread(target=self._run, args=(DeviceMode.REGISTER,))
|
||||
self.thread.start()
|
||||
|
|
Loading…
Reference in New Issue