简体   繁体   中英

Retrieve data/exception from a handler function

I'm trying to use Python and pywinusb-0.3.2 to read data from a USB weighing scale when a valid request hits the web server ( requested_serial_number is coming from the query string).

So I have the following code inside my do_GET :

all_hids = hid.find_all_hid_devices()

if all_hids:
    for index, device in enumerate(all_hids):
        if device.serial_number == requested_serial_number:
            device.open()
            try:
                device.set_raw_data_handler(scales_handler)
                while True:
                    sleep(0.1)
            except GotStableWeightException as e:
                self.do_HEAD(200)
                self.send_body(e.value)

And this is my scales_handler (plus custom exception definition):

def scales_handler(data):
    print("Byte 0: {0}".format(data[0]))
    print("Byte 1: {0}".format(data[1]))
    print("Byte 2: {0}".format(data[2]))
    print("Byte 3: {0}".format(data[3]))
    print("Byte 4: {0}".format(data[4]))
    print("Byte 5: {0}".format(data[5]))
    print("All: {0}".format(data))
    if data[1] == 4:
        raise GotStableWeightException(data[4] + (256 * data[5]))

class GotStableWeightException(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

So the process is:

  1. Python starts listening for requests on port 8000 using http.server's HTTPServer and BaseHTTPRequestHandler
  2. A request comes in and is routed to my do_GET function.
  3. The do_GET performs some basic validation and then searches for a matching USB HID (my first code sample).
  4. If it finds a match, it opens the device and passes in a data handler.

What I'm trying to achieve:

I want to allow the data handler to keep reading from the scale until data[1] == 4 (which indicates a stable reading from the scale). At that point, I want to retrieve this reading in my do_GET and send it to the waiting HTTP client, close the device and end the function.

However, my GotStableWeightException isn't caught inside my do_GET , I think because it is thrown in a different thread. I'm new to programming with multiple threads, and I'm having trouble working out how I can get the result back to do_GET once it matches the data[1] == 4 condition.

EDIT

What I get:

Here's the output I see in the terminal from scales_handler :

Byte 0: 3
Byte 1: 4
Byte 2: 2
Byte 3: 0
Byte 4: 204
Byte 5: 0
All: [3, 4, 2, 0, 204, 0]
Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Python33\lib\threading.py", line 639, in _bootstrap_inner
    self.run()
  File "C:\Python33\lib\site-packages\pywinusb-0.3.2-py3.3.egg\pywinusb\hid\core.py", line 886, in run
    hid_object._process_raw_report(raw_report)
  File "C:\Python33\lib\site-packages\pywinusb-0.3.2-py3.3.egg\pywinusb\hid\helpers.py", line 64, in new_function
    return function_target(*args, **kw)
  File "C:\Python33\lib\site-packages\pywinusb-0.3.2-py3.3.egg\pywinusb\hid\core.py", line 714, in _process_raw_report
    self.__raw_handler(helpers.ReadOnlyList(raw_report))
  File "C:\USB HID Scales\server.py", line 28, in scales_handler
    raise GotStableWeightException(data[4] + (256 * data[5]))
GotStableWeightException: 204

So device is a threaded HidDevice class. As you point out, raising an exception in this threaded object won't get caught by the handler (your do_GET ).

However, I'm wondering if raising an exception is really easiest thing to do (exceptions tend to be reserved for errors and problems). To achieve your aims, is it possible to use a global variable and do something like this;

global e_value
e_value = None

def scales_handler(data):
    print("Byte 0: {0}".format(data[0]))
    print("Byte 1: {0}".format(data[1]))
    print("Byte 2: {0}".format(data[2]))
    print("Byte 3: {0}".format(data[3]))
    print("Byte 4: {0}".format(data[4]))
    print("Byte 5: {0}".format(data[5]))
    print("All: {0}".format(data))
    if data[1] == 4:
        e_value = data[4] + (256 * data[5]))

devices = []
try:
    for index, device in enumerate(all_hids):
        if device.serial_number == requested_serial_number:
            devices.append(device)
            device.open()
            device.set_raw_data_handler(sample_handler)
    while True:  
        time.sleep(0.1)
finally:
    for device in devices:
        device.close()

if e_value is not None:
    self.do_HEAD(200)
    self.send_body(e_value) 

I can't attest to what your devices are, so I should warn that this isn't thread safe - if more than one device has data[1] == 4 you will only have e_value set by the last device to access it. (Though fixing this would be simple with a global array and counter object).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM