I'm writing a Linux driver for a USB HID device in Python. The device has two ways it sends data, both of which are needed: feature reports (synchronous) and input reports (asynchronous). Using the hidapi Cython library I have only one instance of the device to work with, but I need to set up a listener for hid.read() that will run constantly AND allow synchronous methods to be called at will by the application to send feature reports.
Currently I have the listener in one thread and the synchronous calls in another. When I run the program, my synchronous calls are not happening, though they work fine if I never start the listener; so it appears the listener thread is taking over.
Below is the troubling piece of code:
app.py
# app.py
import threading
import time
import myhiddriver
# Code that sets mydevice
class Reader:
def start(self, device):
self.requests = myhiddriver.DeviceRequest(device)
# Wait a bit before firing, for testing
time.sleep(3)
self.requests.request_swipe_card()
def start_listener(self, device):
self.listener = myhiddriver.DeviceListener(device)
reader = Reader()
thread1 = threading.Thread(target=reader.start, args=(mydevice,))
thread1.daemon = True
thread2 = threading.Thread(target=reader.start_listener, args=(mydevice,))
thread2.daemon = True
thread1.start()
thread2.start()
# Keep this puppy running
while True:
pass
myhiddriver.py
import threading
LOCK = threading.Lock()
class DeviceRequest:
def __init__(self, device):
# Lock it up first
LOCK.acquire()
self.device = device
LOCK.release()
def request_swipe_card(self):
# Lock this up too
LOCK.acquire()
self.device.set_feature_report(insert data here)
LOCK.release()
class DeviceListener:
def __init__(self, device):
# Lock me up
LOCK.acquire()
self.device = device
self.start_listener()
LOCK.release()
def start_listener(self):
while True:
# Should I be locking this up?
LOCK.acquire()
data = self.device.read(255)
LOCK.release()
if data:
print data
else:
pass
My Question: Why is my synchronous call (request_swipe_card) not following through? Or, how can I better architect this to have an endless listener AND the ability to make synchronous calls on the same object?
from the looks of the code, it is because you are locking it up
When the state is unlocked, acquire() changes the state to locked and returns immediately. When the state is locked, acquire() blocks until a call to release() in another thread changes it to unlocked
here is the problem:
class DeviceListener:
def __init__(self, device):
LOCK.acquire() # first you lock it up
self.device = device
self.start_listener()
LOCK.release()
def start_listener(self):
while True: # because of the loop, the lock wouldn't get release even if the LOCK below doesn't exist
LOCK.acquire() # it end up blocking here and oops, it locked up xD
data = self.device.read(255) # so it wouldn't be able to read here
LOCK.release()
if data:
print data
else:
pass
and when the request_swipe_card
end up being call in the other thread, it end up blocking there too
def request_swipe_card(self):
LOCK.acquire() # right here xD
self.device.set_feature_report(insert data here)
LOCK.release()