Skip to content

Cp10 #1111

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Cp10 #1111

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ configuration, documentation, etc. concerns.
- Bluetooth HID and split keyboards. No more wires.

## Getting Started
KMK requires [CircuitPython](https://circuitpython.org/) version 7.0 or higher.

KMK requires [CircuitPython](https://circuitpython.org/) version 8.0 or higher.
Our getting started guide can be found
[here](/docs/en/Getting_Started.md).

Expand Down
10 changes: 5 additions & 5 deletions kmk/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ def __init__(self, func: Callable[[None], None], period: int) -> None:

def call(self) -> None:
after_ms = ticks_add(self._task.ph_key, self.period)
_task_queue.push_sorted(self._task, after_ms)
_task_queue.push(self._task, after_ms)
self._coro()

def restart(self) -> None:
_task_queue.push_sorted(self._task)
_task_queue.push(self._task)


def create_task(
Expand All @@ -52,9 +52,9 @@ def create_task(
t = r = Task(func)

if after_ms > 0:
_task_queue.push_sorted(t, ticks_add(ticks_ms(), after_ms))
_task_queue.push(t, ticks_add(ticks_ms(), after_ms))
elif after_ms == 0:
_task_queue.push_head(t)
_task_queue.push(t)

return r

Expand All @@ -65,7 +65,7 @@ def get_due_task() -> [Callable, None]:
t = _task_queue.peek()
if not t or ticks_diff(t.ph_key, now) > 0:
break
_task_queue.pop_head()
_task_queue.pop()
yield t.coro


Expand Down
60 changes: 42 additions & 18 deletions tests/task.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
#
# CIRCUITPY-CHANGE
# This code comes from MicroPython, and has not been run through black or pylint there.
# Altering these files significantly would make merging difficult, so we will not use
# pylint or black.
# pylint: skip-file
# fmt: off

# This file contains the core TaskQueue based on a pairing heap, and the core Task class.
# They can optionally be replaced by C implementations.
Expand Down Expand Up @@ -89,8 +96,6 @@ def ph_delete(heap, node):
n = parent.ph_child
while node is not n.ph_next:
n = n.ph_next
if not n:
return heap
child = node.ph_child
next = node.ph_next
node.ph_child = None
Expand All @@ -115,22 +120,18 @@ def __init__(self):
def peek(self):
return self.heap

def push_sorted(self, v, key=None):
if key is None:
key = ticks_ms()
def push(self, v, key=None):
assert v.ph_child is None
assert v.ph_next is None
v.data = None
v.ph_key = key
v.ph_child = None
v.ph_next = None
v.ph_key = key if key is not None else ticks_ms()
self.heap = ph_meld(v, self.heap)

def push_head(self, v):
self.push_sorted(v, ticks_ms())

def pop_head(self):
def pop(self):
v = self.heap
assert v.ph_next is None
self.heap = ph_pairing(v.ph_child)
# v.ph_child = None
v.ph_child = None
return v

def remove(self, v):
Expand All @@ -139,27 +140,42 @@ def remove(self, v):

# Task class representing a coroutine, can be waited on and cancelled.
class Task:
# CIRCUITPY-CHANGE: doc
'''This object wraps a coroutine into a running task. Tasks can be waited on
using ``await task``, which will wait for the task to complete and return the
return value of the task.

Tasks should not be created directly, rather use ``create_task`` to create them.
'''

def __init__(self, coro, globals=None):
self.coro = coro # Coroutine of this Task
self.data = None # General data for queue it is waiting on
self.state = True # None, False, True or a TaskQueue instance
self.state = True # None, False, True, a callable, or a TaskQueue instance
self.ph_key = 0 # Pairing heap
self.ph_child = None # Paring heap
self.ph_child_last = None # Paring heap
self.ph_next = None # Paring heap
self.ph_rightmost_parent = None # Paring heap

def __await__(self):
def __iter__(self):
if not self.state:
# Task finished, signal that is has been await'ed on.
self.state = False
elif self.state is True:
# Allocated head of linked list of Tasks waiting on completion of this task.
self.state = TaskQueue()
elif type(self.state) is not TaskQueue:
# Task has state used for another purpose, so can't also wait on it.
raise RuntimeError("can't wait")
return self

# CICUITPY-CHANGE: CircuitPython needs __await()__.
__await__ = __iter__

def __next__(self):
if not self.state:
# CIRCUITPY-CHANGE
if self.data is None:
# Task finished but has already been sent to the loop's exception handler.
raise StopIteration
Expand All @@ -168,14 +184,22 @@ def __next__(self):
raise self.data
else:
# Put calling task on waiting queue.
self.state.push_head(cur_task)
self.state.push(cur_task)
# Set calling task's data to this task that it waits on, to double-link it.
cur_task.data = self

def done(self):
# CIRCUITPY-CHANGE: doc
'''Whether the task is complete.'''

return not self.state

def cancel(self):
# CIRCUITPY-CHANGE: doc
'''Cancel the task by injecting a ``CancelledError`` into it. The task
may or may not ignore this exception.
'''

# Check if task is already finished.
if not self.state:
return False
Expand All @@ -189,10 +213,10 @@ def cancel(self):
if hasattr(self.data, 'remove'):
# Not on the main running queue, remove the task from the queue it's on.
self.data.remove(self)
__task_queue.push_head(self)
__task_queue.push(self)
elif ticks_diff(self.ph_key, ticks_ms()) > 0:
# On the main running queue but scheduled in the future, so bring it forward to now.
__task_queue.remove(self)
__task_queue.push_head(self)
__task_queue.push(self)
self.data = CancelledError
return True