Make keypad select/poll'able for better async

This allows a small wrapper class to be written
```py
class AsyncEventQueue:
    def __init__(self, events):
        self._events = events

    async def __await__(self):
        yield asyncio.core._io_queue.queue_read(self._events)
        return self._events.get()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        pass

```
and used to just "await" the next event:
```py
async def key_task():
    print("waiting for keypresses")
    with keypad.KeyMatrix([board.D4], [board.D5]) as keys, AsyncEventQueue(keys.events) as ev:
        while True:
            print(await ev)
```

Because checking the empty status of the EventQueue does not enter
CircuitPython bytecode, it's assumed (but not measured) that this is
more efficient than an equivalent loop with an `await async.sleep(0)`
yield and introduces less latency than any non-zero sleep value.
This commit is contained in:
Jeff Epler 2022-08-08 14:28:30 -05:00
parent f1826b054a
commit 76f03a2bee
No known key found for this signature in database
GPG Key ID: D5BF15AB975AB4DE
1 changed files with 32 additions and 0 deletions

View File

@ -24,8 +24,11 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "py/ioctl.h"
#include "py/mperrno.h"
#include "py/objproperty.h" #include "py/objproperty.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "py/stream.h"
#include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Event.h"
#include "shared-bindings/keypad/EventQueue.h" #include "shared-bindings/keypad/EventQueue.h"
@ -141,12 +144,41 @@ STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table);
#if MICROPY_PY_USELECT
STATIC mp_uint_t eventqueue_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
(void)errcode;
keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
switch (request) {
case MP_STREAM_POLL: {
mp_uint_t flags = arg;
mp_uint_t ret = 0;
if ((flags & MP_IOCTL_POLL_RD) && common_hal_keypad_eventqueue_get_length(self)) {
ret |= MP_IOCTL_POLL_RD;
}
return ret;
}
default:
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}
}
STATIC const mp_stream_p_t eventqueue_p = {
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.ioctl = eventqueue_ioctl,
};
#endif
const mp_obj_type_t keypad_eventqueue_type = { const mp_obj_type_t keypad_eventqueue_type = {
{ &mp_type_type }, { &mp_type_type },
.flags = MP_TYPE_FLAG_EXTENDED, .flags = MP_TYPE_FLAG_EXTENDED,
.name = MP_QSTR_EventQueue, .name = MP_QSTR_EventQueue,
MP_TYPE_EXTENDED_FIELDS( MP_TYPE_EXTENDED_FIELDS(
.unary_op = keypad_eventqueue_unary_op, .unary_op = keypad_eventqueue_unary_op,
#if MICROPY_PY_USELECT
.protocol = &eventqueue_p,
#endif
), ),
.locals_dict = (mp_obj_t)&keypad_eventqueue_locals_dict, .locals_dict = (mp_obj_t)&keypad_eventqueue_locals_dict,
}; };