-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: async/await + uselect + i2cslave #1415
Conversation
error: comparison between signed and unsigned integer expressions [-Werror=sign-compare] Use UINT_MAX instead of -1.
This adds MP_STREAM_POLL support to i2cslave.
Here's the output of a run: https://gist.github.com/notro/6e1028f000dd7d54de07a868d7519181
|
Example task using pulseio.Counter from PR #1423: import pulseio
class Button:
def __init__(self, pin, invert=True, debounce_ms=50):
self.counter = pulseio.Counter(pin)
self.debounce_ms = debounce_ms
self.invert = invert
self.last = False
def __enter__(self):
return self
def __exit__(self, *args):
self.counter.deinit()
@property
def value(self):
if self.invert:
return not self.counter.pinvalue
else:
return bool(self.counter.pinvalue)
async def __await__(self): # __await__ is not supported by MP
while True:
await poll(self.counter)
if self.debounce_ms:
await sleep(self.debounce_ms / 1000)
count = self.counter.clear()
if self.counter.count: # Settled?
continue
value = self.value
if value != self.last:
self.last = value
return value
async def button(pin):
with Button(pin) as b:
while True:
if await b.__await__():
print('BUTTON PRESSED')
else:
print('BUTTON RELEASED')
if not tasks and not sleeping and not polling:
break
import board
tasks.append(button(board.D5)) |
@notro Cool work! I have a few questions:
Thanks for this example code! |
SAMD51:
The main difference is that CPython polls on file descriptors: while MicroPython polls on objects: This object needs to support the stream protocol with its
Python supports an await method that makes objects awaitable (shown in the Button class in my pulseio.Counter example above). MicroPython does not currently support this. The problem with implementing this method on library or C-code, is that it needs to be tied to the eventloop implementation. However if we use uselect and implement the asyncio and curio use the selectors module which is a highlevel module on top of select. Here's the proposed ioctl implementation for i2cslave: 51e2e83#diff-a66dc4755d023a92be9fe9c94db0f94f Refs: |
Thanks for the info @notro. Do you think uselect and ioctl is the best way to go about it? The event mask bits seem a bit weird to me but I'm not sure what would be better. |
I think polling with uselect looks promising. It's the mechanism MicroPython has chosen for polling on I/O operations (in line with CPython) and is thus fairly future proof. The eventmask is just to specify which operations you're waiting for (read and/or write). I see that I need to be more precise with my i2cslave ioctl implementation and return MP_STREAM_POLL_RD or MP_STREAM_POLL_WR depending on the RD bit in the address. Edit: |
Deep sleep |
Deep sleep sounds awesome. You've done more async than I have now. :-) |
I was looking into how I could add support for the This is the small change necessary to my pulseio.Counter example: class Button:
+ __iter__ = __await__
async def button(pin):
with Button(pin) as b:
while True:
- if await b.__await__():
+ if await b:
print('BUTTON PRESSED')
else:
print('BUTTON RELEASED')
|
Closing this. New PRs can be made once a design is determined in #1380 |
I've had a longterm goal to try and use i2cslave with async/await since it looked like a simple way of gettting multitasking in CircuitPython.
Inspired by issue #1380 I set out to see what it could look like.
I haven't done much testing, the main purpose at this stage is to serve as an async/await example in the async discussion.
I was pleased to find that uselect had a flexible signalling mechanism for I/O. I think it can also be used for pin interrupts.
This scheduler/eventloop is based on an example in the curio docs:
Some tasks:
uio.IOBase gives access to the streaming protocol from python making it possible to hook python code into uselect.poll.