diff --git a/apps/latency_test.yml b/apps/latency_test.yml new file mode 100644 index 0000000..322c6db --- /dev/null +++ b/apps/latency_test.yml @@ -0,0 +1,18 @@ +version: '3.7' + +services: + + test-latency: + image: iitschri/hidman:latest + + command: python3 /usr/local/src/hidman/apps/python-examples/latency_test.py + + privileged: true + stdin_open: true + tty: true + network_mode: host + + volumes: + - type: bind + source: ../ + target: /usr/local/src/hidman diff --git a/apps/lsl/lsl-client.py b/apps/lsl/lsl-client.py index 9aeba53..b360c5e 100644 --- a/apps/lsl/lsl-client.py +++ b/apps/lsl/lsl-client.py @@ -28,6 +28,7 @@ def update(self, sample): def worker(self): while self._capturing: sample = self._dev.waitKey() + print(sample) self.update(sample) def getSample(self): diff --git a/apps/lsl/lsl.yml b/apps/lsl/lsl.yml index 1001485..950a2ee 100644 --- a/apps/lsl/lsl.yml +++ b/apps/lsl/lsl.yml @@ -26,7 +26,7 @@ services: dockerfile: Dockerfile args: DOCKER_SRC: iitschri/lsl:v1.14.0 - HIDMAN_VER: 0.2 + HIDMAN_VER: 0.7 privileged: true stdin_open: true @@ -49,7 +49,7 @@ services: dockerfile: Dockerfile args: DOCKER_SRC: iitschri/lsl:v1.14.0 - HIDMAN_VER: 0.2 + HIDMAN_VER: 0.7 privileged: true stdin_open: true diff --git a/apps/python-examples/client.py b/apps/python-examples/client.py index e4986cd..86fa69c 100644 --- a/apps/python-examples/client.py +++ b/apps/python-examples/client.py @@ -1,6 +1,5 @@ from hidman.core import HIDClient - dev = HIDClient(address="tcp://localhost:6666") print(dev.waitKey()) diff --git a/apps/python-examples/client_timeout.py b/apps/python-examples/client_timeout.py index b38ff4c..3e7ab84 100644 --- a/apps/python-examples/client_timeout.py +++ b/apps/python-examples/client_timeout.py @@ -6,4 +6,4 @@ i = 0 while True: i=i+1 - print(i, dev.waitKeyRelease(keyList=['KEY_4'], timeout_ms=3000)) + print(i, dev.waitKeyRelease(keyList=['KEY_1'], timeout_ms=3000)) diff --git a/apps/python-examples/latency_test.py b/apps/python-examples/latency_test.py new file mode 100644 index 0000000..3787bb2 --- /dev/null +++ b/apps/python-examples/latency_test.py @@ -0,0 +1,16 @@ +import threading +import time +import statistics + +from hidman.core import HIDServer, HIDClient + +serv = HIDServer(address="tcp://*:6666") +t = threading.Thread(target=serv.run) +t.start() +client = HIDClient(address="tcp://localhost:6666") +trials = [] +for i in range(0,5000): + trials.append(client.waitEvent()[1]) +print("Latency mean=%.6f std=%.6f" % (statistics.mean(trials), statistics.stdev(trials)) ) +serv.close() +t.join() diff --git a/hidman/__init__.py b/hidman/__init__.py index b140631..273ba6b 100644 --- a/hidman/__init__.py +++ b/hidman/__init__.py @@ -1,6 +1,6 @@ __authors__ = 'Davide De Tommaso' __emails__ = 'davide.detommaso@iit.it' __license__ = 'MIT' -__version__ = '0.6' +__version__ = '0.7' __description__ = 'A Python based HID (Human Interface Device) events manager' __requirements__ = ['pytest>=6.2.4', 'evdev>=1.4.0', 'pyzmq>=22.1.0'] diff --git a/hidman/core.py b/hidman/core.py index 303cee8..ce0841a 100644 --- a/hidman/core.py +++ b/hidman/core.py @@ -2,25 +2,29 @@ import evdev import time import zmq -import statistics -import logging import threading -from select import select class HIDDevice: def __init__(self, device=None): - self._device = InputDevice(device) + if not device is None: + self._device = InputDevice(device) + else: + self._device = device def clear(self): - while not self._device.read_one() is None: - return + if not self._device is None: + while not self._device.read_one() is None: + return def read(self): - return self._device.read_one() + if not self._device is None: + return self._device.read_one() + return 0 def close(self): - self._device.close() + if not self._device is None: + self._device.close() class HIDEvent: @@ -30,6 +34,8 @@ class HIDEvent: @staticmethod def parse(event, event_type=None, event_code=None, event_status=None): + if event == 0: + return "VIRTUAL EVENT" if event_type and event.type == ecodes.EV_KEY: data = categorize(event) if event_status is None: @@ -48,29 +54,35 @@ def parse(event, event_type=None, event_code=None, event_status=None): class HIDServer: - def __init__(self, device, address="ipc://pyboard"): + def __init__(self, device=None, address="ipc://pyboard"): self._device = HIDDevice(device) self._context = zmq.Context() - self._socket = self._context.socket(zmq.PAIR) + self._socket = self._context.socket(zmq.PUB) self._socket.bind(address) + self._running = False def run(self): - while True: + self._running = True + while self._running: event = self._device.read() - if event: - data = categorize(event) + if not event is None: self._socket.send_pyobj(event) - def __del__(self): + def close(self): + self._running = False self._device.close() + def __del__(self): + self.close() + class HIDClient: def __init__(self, address="ipc://pyboard"): self._address = address self._context = zmq.Context() - self._socket = self._context.socket(zmq.PAIR) + self._socket = self._context.socket(zmq.SUB) self._socket.connect(self._address) + self._socket.setsockopt(zmq.SUBSCRIBE, b'') def waitEvent(self, event_type=None, event_code=None, event_status=None, timeout_ms=None): t0 = time.perf_counter() @@ -103,8 +115,6 @@ def waitKeyPress(self, keyList=None, evstate=HIDEvent.KEY_DOWN, timeout_ms=None) def waitKeyRelease(self, keyList=None, evstate=HIDEvent.KEY_UP, timeout_ms=None): return self.waitEvent(event_type=ecodes.EV_KEY, event_code=keyList, event_status=evstate, timeout_ms=timeout_ms) - def close(self): - self._socket.send_pyobj(None) - def __del__(self): self._socket.disconnect(self._address) + self._socket.close() diff --git a/tests/test_basic.py b/tests/test_basic.py index 0022e34..2c4eb3f 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -9,4 +9,10 @@ class TestLatency: def test_run(self): - pass + serv = HIDServer() + t = threading.Thread(target=serv.run) + t.start() + client = HIDClient() + client.waitEvent() + serv.close() + t.join()