device: clean up pinging code

This commit is contained in:
Peter F. Patel-Schneider 2023-01-12 08:20:01 -05:00
parent 5657c1ac99
commit 0905ed5f43
2 changed files with 12 additions and 55 deletions

View File

@ -499,40 +499,29 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
def ping(handle, devnumber, long_message=False):
"""Check if a device is connected to the receiver.
:returns: The HID protocol supported by the device, as a floating point number, if the device is active.
"""
if _log.isEnabledFor(_DEBUG):
_log.debug('(%s) pinging device %d', handle, devnumber)
# import inspect as _inspect
# print ('\n '.join(str(s) for s in _inspect.stack()))
with acquire_timeout(handle_lock(handle), handle, 10.):
notifications_hook = getattr(handle, 'notifications_hook', None)
try:
_skip_incoming(handle, int(handle), notifications_hook)
except NoReceiver:
_log.warn('device or receiver disconnected')
return
# randomize the SoftwareId and mark byte to be able to identify the ping
# reply, and set most significant (0x8) bit in SoftwareId so that the reply
# is always distinguishable from notifications
request_id = 0x0018 | _random_bits(3)
request_data = _pack('!HBBB', request_id, 0, 0, _random_bits(8))
write(int(handle), devnumber, request_data, long_message)
ihandle = int(handle)
notifications_hook = getattr(handle, 'notifications_hook', None)
try:
_skip_incoming(handle, ihandle, notifications_hook)
except NoReceiver:
_log.warn('device or receiver disconnected')
return
write(ihandle, devnumber, request_data, long_message)
# we consider timeout from this point
request_started = _timestamp()
request_started = _timestamp() # we consider timeout from this point
delta = 0
while delta < _PING_TIMEOUT:
reply = _read(handle, _PING_TIMEOUT)
if reply:
report_id, reply_devnumber, reply_data = reply
if reply_devnumber == devnumber:
@ -540,17 +529,14 @@ def ping(handle, devnumber, long_message=False):
# HID++ 2.0+ device, currently connected
return ord(reply_data[2:3]) + ord(reply_data[3:4]) / 10.0
if report_id == HIDPP_SHORT_MESSAGE_ID and reply_data[:1] == b'\x8F' and reply_data[1:3] == request_data[:2
]:
if report_id == HIDPP_SHORT_MESSAGE_ID and reply_data[:1] == b'\x8F' and \
reply_data[1:3] == request_data[:2]: # error response
assert reply_data[-1:] == b'\x00'
error = ord(reply_data[3:4])
if error == _hidpp10.ERROR.invalid_SubID__command: # a valid reply from a HID++ 1.0 device
return 1.0
if error == _hidpp10.ERROR.resource_error: # device unreachable
return
if error == _hidpp10.ERROR.unknown_device: # no paired device with that number
_log.error('(%s) device %d error on ping request: unknown device', handle, devnumber)
raise NoSuchDevice(number=devnumber, request=request_id)
@ -565,4 +551,3 @@ def ping(handle, devnumber, long_message=False):
delta = _timestamp() - request_started
_log.warn('(%s) timeout (%0.2f/%0.2f) on device %d ping', handle, delta, _PING_TIMEOUT, devnumber)
# raise DeviceUnreachable(number=devnumber, request=request_id)

View File

@ -141,33 +141,20 @@ class EventsListener(_threading.Thread):
def __init__(self, receiver, notifications_callback):
super().__init__(name=self.__class__.__name__ + ':' + receiver.path.split('/')[2])
self.daemon = True
self._active = False
self.receiver = receiver
self._queued_notifications = _Queue(16)
self._notifications_callback = notifications_callback
# self.tick_period = 0
def run(self):
self._active = True
# replace the handle with a threaded one
self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle)
# get the right low-level handle for this thread
ihandle = int(self.receiver.handle)
if _log.isEnabledFor(_INFO):
_log.info('started with %s (%d)', self.receiver, ihandle)
_log.info('started with %s (%d)', self.receiver, int(self.receiver.handle))
self.has_started()
# last_tick = 0
# the first idle read -- delay it a bit, and make sure to stagger
# idle reads for multiple receivers
# idle_reads = _IDLE_READS + (ihandle % 5) * 2
if self.receiver.isDevice: # ping (wired or BT) devices to see if they are really online
if self.receiver.ping():
self.receiver.status.changed(True, reason='initialization')
@ -175,36 +162,21 @@ class EventsListener(_threading.Thread):
while self._active:
if self._queued_notifications.empty():
try:
# _log.debug("read next notification")
n = _base.read(self.receiver.handle, _EVENT_READ_TIMEOUT)
except _base.NoReceiver:
_log.warning('%s disconnected', self.receiver.name)
self.receiver.close()
break
if n:
n = _base.make_notification(*n)
else:
# deliver any queued notifications
n = self._queued_notifications.get()
n = self._queued_notifications.get() # deliver any queued notifications
if n:
# if _log.isEnabledFor(_DEBUG):
# _log.debug("%s: processing %s", self.receiver, n)
try:
self._notifications_callback(n)
except Exception:
_log.exception('processing %s', n)
# elif self.tick_period:
# idle_reads -= 1
# if idle_reads <= 0:
# idle_reads = _IDLE_READS
# now = _timestamp()
# if now - last_tick >= self.tick_period:
# last_tick = now
# self.tick(now)
del self._queued_notifications
self.has_stopped()