From e60ef05c058e9f24f35928567c76b3947df5d726 Mon Sep 17 00:00:00 2001 From: Adam PIppin Date: Fri, 2 Jul 2021 00:26:52 -0700 Subject: [PATCH] Eventing system, queues, tasks --- watchos2/{Events.h => Event.h} | 2 +- watchos2/EventListener.cpp | 34 ++++++---- watchos2/EventListener.h | 13 ++-- watchos2/Kernel.cpp | 120 ++++++++++++++++++++++++++++++--- watchos2/Kernel.h | 19 ++++-- watchos2/Module_UI.cpp | 0 watchos2/Module_UI.h | 21 ++++++ watchos2/Queue.cpp | 24 +++---- watchos2/Queue.h | 11 +-- watchos2/Queues.cpp | 4 -- watchos2/Task.h | 3 +- watchos2/Task_Test.cpp | 18 +++-- watchos2/__vm/Compile.vmps.xml | 2 +- watchos2/__vm/Upload.vmps.xml | 2 +- watchos2/watchos.cpp | 42 ++++++++++++ watchos2/watchos.h | 14 ++++ watchos2/watchos2.ino | 3 +- watchos2/watchos_consts.h | 2 + watchos2/watchos_types.h | 3 +- 19 files changed, 266 insertions(+), 71 deletions(-) rename watchos2/{Events.h => Event.h} (68%) create mode 100644 watchos2/Module_UI.cpp create mode 100644 watchos2/Module_UI.h delete mode 100644 watchos2/Queues.cpp diff --git a/watchos2/Events.h b/watchos2/Event.h similarity index 68% rename from watchos2/Events.h rename to watchos2/Event.h index adefa6a..182f277 100644 --- a/watchos2/Events.h +++ b/watchos2/Event.h @@ -3,7 +3,7 @@ struct Event { - uint32_t source; + well_known_handle_t source; uint16_t event; byte param1; byte param2; diff --git a/watchos2/EventListener.cpp b/watchos2/EventListener.cpp index 20544b2..fa2c37d 100644 --- a/watchos2/EventListener.cpp +++ b/watchos2/EventListener.cpp @@ -1,26 +1,34 @@ +#include "watchos.h" #include "EventListener.h" +EventListener::EventListener() +{ + m_event_queue = new Queue(); +} + bool EventListener::hasEvent() { + return !m_event_queue->isEmpty(); } -Event* EventListener::popEvent() +Event* EventListener::getEvent() { + kernel_handle_t handle = m_event_queue->peek(); + // Fetch and immediately release, the event queue still holds the reference. + Event* e = watchos::event(handle); + return e; } -void EventListener::pushEvent(kernel_handle_t handle) +void EventListener::popEvent() { + // Once we're done with the event, remove from the event queue and release + // the reference it holds. + kernel_handle_t handle = m_event_queue->pop(); + watchos::release(handle); } -class IEventListener +void EventListener::pushEvent(kernel_handle_t handle) { -private: - Queue m_events; -protected: - bool hasEvent(); - Event* popEvent(); -public: - void pushEvent(kernel_handle_t handle); - uint32_t getEventSourceMask(); - uint16_t getEventTypeMask(); -}; \ No newline at end of file + watchos::reference(handle); + m_event_queue->push(handle); +} \ No newline at end of file diff --git a/watchos2/EventListener.h b/watchos2/EventListener.h index dee6946..bd64433 100644 --- a/watchos2/EventListener.h +++ b/watchos2/EventListener.h @@ -1,22 +1,21 @@ #ifndef _EVENTLISTENER_h #define _EVENTLISTENER_h -#include "watchos.h" +#include "watchos_consts.h" #include "Queue.h" -#include "Events.h" +#include "Event.h" class EventListener { private: - Queue m_event_queue; + Queue* m_event_queue; protected: bool hasEvent(); - Event* popEvent(); - void releaseEvent(kernel_handle_t handle); + Event* getEvent(); + void popEvent(); public: + EventListener(); void pushEvent(kernel_handle_t handle); - uint32_t getEventSourceMask(); - uint16_t getEventTypeMask(); }; #endif \ No newline at end of file diff --git a/watchos2/Kernel.cpp b/watchos2/Kernel.cpp index fdf75fa..6a4effd 100644 --- a/watchos2/Kernel.cpp +++ b/watchos2/Kernel.cpp @@ -1,4 +1,6 @@ #include "watchos.h" +#include "Event.h" +#include "EventListener.h" #include "IRunnable.h" struct KernelHandle @@ -16,13 +18,39 @@ struct KernelTask Task* task; }; +struct KernelEventSubscription +{ + kernel_handle_t handle; + well_known_handle_t source_mask; + uint16_t event_mask; + EventListener* listener; +}; + +Kernel* g_kernel; + void destruct_task(kernel_handle_t handle, void* object) { - delete object; + Task* task = static_cast(object); + g_kernel->unregisterTask(task); + delete static_cast(task); +} + +void destruct_event(kernel_handle_t, void* object) +{ + delete static_cast(object); +} + +void destruct_event_subscription(kernel_handle_t, void* object) +{ + KernelEventSubscription* sub = static_cast(object); + g_kernel->unsubscribeEvent(sub); + delete static_cast(sub); } Kernel::Kernel() { + g_kernel = this; + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) { m_handle[i] = nullptr; @@ -32,6 +60,11 @@ Kernel::Kernel() { m_task[i] = nullptr; } + + for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++) + { + m_event_subscription[i] = nullptr; + } } kernel_handle_t Kernel::allocHandle(byte type, void* object, kernel_handle_destructor_t destructor, uint32_t well_known) @@ -41,10 +74,10 @@ kernel_handle_t Kernel::allocHandle(byte type, void* object, kernel_handle_destr if (m_handle[i] == nullptr) { m_handle[i] = new KernelHandle(); - m_handle[i]->handle = type | m_next_handle++; + m_handle[i]->handle = (type << 24) | m_next_handle++; m_handle[i]->destructor = destructor; m_handle[i]->object = object; - m_handle[i]->references = 1; + m_handle[i]->references = 0; m_handle[i]->well_known = well_known; return m_handle[i]->handle; } @@ -64,6 +97,7 @@ void Kernel::freeHandle(kernel_handle_t handle) } delete m_handle[i]; m_handle[i] = nullptr; + return; } } } @@ -74,24 +108,36 @@ void* Kernel::getHandle(kernel_handle_t handle) { if (m_handle[i] != nullptr && m_handle[i]->handle == handle) { - m_handle[i]->references++; return m_handle[i]->object; } } watchos::panic("Attempt to access invalid Kernel handle"); } -void* Kernel::getHandle(uint32_t well_known) +kernel_handle_t Kernel::getHandleForWellKnown(well_known_handle_t well_known) { for (int i = 0; i < KERNEL_MAX_HANDLES; i++) { if (m_handle[i] != nullptr && m_handle[i]->well_known == well_known) + { + return m_handle[i]->handle; + } + } + watchos::panic("Attempt to get handle for invalid well-known id: %#010x", well_known); +} + +void Kernel::useHandle(kernel_handle_t handle) +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + if (m_handle[i] != nullptr && m_handle[i]->handle == handle) { m_handle[i]->references++; - return m_handle[i]->object; + return; } } - watchos::panic("Attempt to access invalid Kernel handle by well-known id: %#10x", well_known); + + watchos::panic("Attempt to increase ref count on invalid Kernel handle"); } void Kernel::releaseHandle(kernel_handle_t handle) @@ -121,8 +167,9 @@ kernel_handle_t Kernel::registerTask(Task* task) if (m_task[i] == nullptr) { m_task[i] = new KernelTask(); - m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, (void*)destruct_task); + m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, task, (kernel_handle_destructor_t)destruct_task); m_task[i]->task = task; + useHandle(m_task[i]->handle); return m_task[i]->handle; } } @@ -136,7 +183,7 @@ void Kernel::unregisterTask(Task* task) { if (m_task[i] != nullptr && m_task[i]->task == task) { - releaseHandle(m_task[i]->handle); + delete m_task[i]->task; delete m_task[i]; m_task[i] = nullptr; return; @@ -144,6 +191,61 @@ void Kernel::unregisterTask(Task* task) } } +void Kernel::pushEvent(well_known_handle_t source, uint16_t event, byte param1, byte param2) +{ + Event* e = new Event(); + e->source = source; + e->event = event; + e->param1 = param1; + e->param2 = param2; + kernel_handle_t handle = allocHandle(WATCHOS_HANDLE_TYPE_EVENT, e, (kernel_handle_destructor_t)destruct_event); + useHandle(handle); + + for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++) + { + if (m_event_subscription[i] != nullptr && + (m_event_subscription[i]->source_mask & source) == source && + (m_event_subscription[i]->event_mask & event) == event) + { + m_event_subscription[i]->listener->pushEvent(handle); + } + } + + // Now release our reference to it, if we've passed it to anyone they have open references. + // If nothing matched, that was the last reference and we'll just clean it up right away. + releaseHandle(handle); +} + +kernel_handle_t Kernel::subscribeEvent(EventListener* listener, well_known_handle_t source_mask, uint16_t event_mask) +{ + for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++) + { + if (m_event_subscription[i] == nullptr) + { + m_event_subscription[i] = new KernelEventSubscription(); + m_event_subscription[i]->source_mask = source_mask; + m_event_subscription[i]->event_mask = event_mask; + m_event_subscription[i]->listener = listener; + m_event_subscription[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_EVENT_SUBSCRIPTION, m_event_subscription[i], (kernel_handle_destructor_t)destruct_event_subscription); + useHandle(m_event_subscription[i]->handle); + return m_event_subscription[i]->handle; + } + } + watchos::panic("Exceeded KERNEL_MAX_EVENT_SUBSCRIPTIONS"); +} + +void Kernel::unsubscribeEvent(KernelEventSubscription* subscription) +{ + for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++) + { + if (m_event_subscription[i] != nullptr && m_event_subscription[i] == subscription) + { + m_event_subscription[i] = nullptr; + return; + } + } +} + void Kernel::tick() { for (int i = 0; i < KERNEL_MAX_TASKS; i++) diff --git a/watchos2/Kernel.h b/watchos2/Kernel.h index 9cf9531..62f0485 100644 --- a/watchos2/Kernel.h +++ b/watchos2/Kernel.h @@ -2,14 +2,17 @@ #define _KERNEL_h #include "Task.h" +#include "EventListener.h" #define KERNEL_MAX_HANDLES 256 #define KERNEL_MAX_TASKS 32 +#define KERNEL_MAX_EVENT_SUBSCRIPTIONS 64 typedef void (*kernel_handle_destructor_t)(kernel_handle_t, void*); struct KernelHandle; struct KernelTask; +struct KernelEventSubscription; class Kernel { @@ -17,6 +20,7 @@ private: KernelHandle* m_handle[KERNEL_MAX_HANDLES]; int m_next_handle = 1; KernelTask* m_task[KERNEL_MAX_TASKS]; + KernelEventSubscription* m_event_subscription[KERNEL_MAX_EVENT_SUBSCRIPTIONS]; void freeHandle(kernel_handle_t handle); @@ -31,7 +35,7 @@ public: /// Function to call when this handle has released all references /// Specify a 'well_known' value this pointer can be fetched by /// A handle which can be used to fetch or release this object - kernel_handle_t allocHandle(byte type, void* object, kernel_handle_destructor_t destructor = nullptr, byte well_known = 0); + kernel_handle_t allocHandle(byte type, void* object, kernel_handle_destructor_t destructor = nullptr, uint32_t well_known = 0); /// /// Fetch the object referenced by this handle, increasing the reference count @@ -40,12 +44,7 @@ public: /// A pointer to the object the handle references void* getHandle(kernel_handle_t handle); - /// - /// Fetch an object by its well-known value, increasing the reference count - /// - /// Well-known id of handle - /// A pointer to the object the handle references - void* getHandle(byte well_known); + void useHandle(kernel_handle_t handle); /// /// Release a fetched reference to this object @@ -53,9 +52,15 @@ public: /// Handle to release void releaseHandle(kernel_handle_t handle); + kernel_handle_t getHandleForWellKnown(well_known_handle_t handle); + kernel_handle_t registerTask(Task* task); void unregisterTask(Task* task); + void pushEvent(well_known_handle_t source, uint16_t event, byte param1, byte param2); + kernel_handle_t subscribeEvent(EventListener* listener, well_known_handle_t source_mask, uint16_t event_mask); + void unsubscribeEvent(KernelEventSubscription* subscription); + void tick(); }; diff --git a/watchos2/Module_UI.cpp b/watchos2/Module_UI.cpp new file mode 100644 index 0000000..e69de29 diff --git a/watchos2/Module_UI.h b/watchos2/Module_UI.h new file mode 100644 index 0000000..b0be076 --- /dev/null +++ b/watchos2/Module_UI.h @@ -0,0 +1,21 @@ +#ifndef _MODULE_UI_h +#define _MODULE_UI_h + +#include +#include "watchos_consts.h" +#include "watchos_hw.h" +#include "watchos_types.h" + +#include "Task.h" +#include "IRunnable.h" + +#define MODULE_UI_MAX_WINDOWS 32 + +struct UiWindow; + +class Module_UI : public Task, public IRunnable +{ + UiWindow* m_window[MODULE_UI_MAX_WINDOWS]; +}; + +#endif \ No newline at end of file diff --git a/watchos2/Queue.cpp b/watchos2/Queue.cpp index d8499e2..3b43db1 100644 --- a/watchos2/Queue.cpp +++ b/watchos2/Queue.cpp @@ -1,16 +1,14 @@ -#include "Queue.h" +#include "watchos.h" -template -Queue::Queue() +Queue::Queue() { for (int i = 0; i < QUEUE_RING_SIZE; i++) { - m_item[i] = nullptr; + m_item[i] = WATCHOS_HANDLE_NULL; } } -template -void Queue::push(T* item) +void Queue::push(kernel_handle_t item) { if (m_full) { @@ -31,8 +29,7 @@ void Queue::push(T* item) } } -template -T* Queue::peek() +kernel_handle_t Queue::peek() { // If the next position to read and write match but the buffer isn't full, // then the buffer is empty @@ -44,8 +41,7 @@ T* Queue::peek() return m_item[m_read]; } -template -T* Queue::pop() +kernel_handle_t Queue::pop() { // If the next position to read and write match but the buffer isn't full, // then the buffer is empty @@ -54,7 +50,7 @@ T* Queue::pop() watchos::panic("Cannot dequeue event: ring buffer empty"); } - T* nextItem = m_item[m_read]; + kernel_handle_t nextItem = m_item[m_read]; // Move to the next read position m_read = next(m_read); // We can never be full if we just removed an item @@ -63,14 +59,12 @@ T* Queue::pop() return nextItem; } -template -bool Queue::isEmpty() +bool Queue::isEmpty() { return m_read == m_write && !m_full; } -template -int Queue::next(int n) +int Queue::next(int n) { if (n + 1 == QUEUE_RING_SIZE) return 0; diff --git a/watchos2/Queue.h b/watchos2/Queue.h index 3e0c0c4..cb8e8cf 100644 --- a/watchos2/Queue.h +++ b/watchos2/Queue.h @@ -1,21 +1,22 @@ #ifndef _QUEUE_h #define _QUEUE_h +#include "watchos_types.h" + #define QUEUE_RING_SIZE 8 -template class Queue { private: - T* m_item[QUEUE_RING_SIZE]; + kernel_handle_t m_item[QUEUE_RING_SIZE]; int m_read = 0, m_write = 0; bool m_full = false; int next(int n); public: Queue(); - void push(T* item); - T* pop(); - T* peek(); + void push(kernel_handle_t item); + kernel_handle_t pop(); + kernel_handle_t peek(); bool isEmpty(); }; diff --git a/watchos2/Queues.cpp b/watchos2/Queues.cpp deleted file mode 100644 index e315d34..0000000 --- a/watchos2/Queues.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "Queue.h" -#include "Queue.cpp" - -template class Queue; \ No newline at end of file diff --git a/watchos2/Task.h b/watchos2/Task.h index 303947f..ec072fb 100644 --- a/watchos2/Task.h +++ b/watchos2/Task.h @@ -9,5 +9,4 @@ public: virtual void suspend(); }; -#endif - +#endif \ No newline at end of file diff --git a/watchos2/Task_Test.cpp b/watchos2/Task_Test.cpp index 8fface7..23c3832 100644 --- a/watchos2/Task_Test.cpp +++ b/watchos2/Task_Test.cpp @@ -1,12 +1,22 @@ #include "watchos.h" -#include "Task.h" -#include "IRunnable.h" -class Task_Test : public IRunnable, public Task +class Task_Test : public IRunnable, public Task, public EventListener { public: + Task_Test() + { + watchos::subscribe(this, 0xffffffffffffffffu, 0xffffu); + } void tick() { - watchos::debug("Tick!"); + Event* e; + while (this->hasEvent()) + { + e = this->getEvent(); + + watchos::debug("Got event: src %#020llx evt %#06x param1 %#04x param2 %#04x", e->source, e->event, e->param1, e->param2); + + this->popEvent(); + } } }; \ No newline at end of file diff --git a/watchos2/__vm/Compile.vmps.xml b/watchos2/__vm/Compile.vmps.xml index a8054e2..2040ddf 100644 --- a/watchos2/__vm/Compile.vmps.xml +++ b/watchos2/__vm/Compile.vmps.xml @@ -2,7 +2,7 @@ - + diff --git a/watchos2/__vm/Upload.vmps.xml b/watchos2/__vm/Upload.vmps.xml index 502d680..5d6debe 100644 --- a/watchos2/__vm/Upload.vmps.xml +++ b/watchos2/__vm/Upload.vmps.xml @@ -2,7 +2,7 @@ - + diff --git a/watchos2/watchos.cpp b/watchos2/watchos.cpp index 1b8b620..9dcf0bb 100644 --- a/watchos2/watchos.cpp +++ b/watchos2/watchos.cpp @@ -27,9 +27,13 @@ void watchos::panic(char* fmt...) vsprintf(msg, fmt, args); va_end(args); Serial.println(msg); +#ifdef WATCHOS_DEBUG + for (;;) {} +#else delay(3000); Serial.println("Resetting..."); ESP.restart(); +#endif } void watchos::debug(char* fmt...) @@ -42,4 +46,42 @@ void watchos::debug(char* fmt...) va_end(args); Serial.println(msg); #endif +} + +Event* watchos::event(kernel_handle_t event) +{ + return static_cast(kernel()->getHandle(event)); +} + +Task* watchos::task(kernel_handle_t task) +{ + return static_cast(kernel()->getHandle(task)); +} + +Task* watchos::task(well_known_handle_t handle) +{ + return static_cast(kernel()->getHandle(kernel()->getHandleForWellKnown(handle))); +} + +void watchos::reference(kernel_handle_t handle) +{ + kernel()->useHandle(handle); +} + +void watchos::release(kernel_handle_t handle) +{ + kernel()->releaseHandle(handle); +} + +kernel_handle_t watchos::run(Task* task) +{ + return kernel()->registerTask(task); +} + +kernel_handle_t watchos::subscribe(Task* task, well_known_handle_t source_mask, uint16_t event_mask) +{ + EventListener* el = dynamic_cast(task); + if (el == nullptr) + watchos::panic("Cannot subscribe task to events--must implement EventListener"); + return kernel()->subscribeEvent(el, source_mask, event_mask); } \ No newline at end of file diff --git a/watchos2/watchos.h b/watchos2/watchos.h index d2bd21f..64da8be 100644 --- a/watchos2/watchos.h +++ b/watchos2/watchos.h @@ -7,7 +7,11 @@ #include "watchos_hw.h" #include "watchos_types.h" +#include "Event.h" +#include "EventListener.h" #include "Kernel.h" +#include "Task.h" +#include "IRunnable.h" class watchos { @@ -20,6 +24,16 @@ public: static void panic(char* fmt...); static void debug(char* fmt...); + static Event* event(kernel_handle_t event); + static Task* task(kernel_handle_t task); + static Task* task(well_known_handle_t handle); + + static void reference(kernel_handle_t handle); + static void release(kernel_handle_t handle); + + static kernel_handle_t run(Task* task); + static kernel_handle_t subscribe(Task* task, well_known_handle_t source_mask, uint16_t event_mask); + }; #endif diff --git a/watchos2/watchos2.ino b/watchos2/watchos2.ino index 62f1f8c..f52a46d 100644 --- a/watchos2/watchos2.ino +++ b/watchos2/watchos2.ino @@ -13,8 +13,9 @@ void setup() { delay(500); watchos::initialize(); Kernel* kernel = watchos::kernel(); - kernel->registerTask(new Task_Test()); + watchos::run(new Task_Test()); watchos::debug("Setup done!"); + kernel->pushEvent(0xDEADBEEFu, 0x01, 0x10, 0x20); } diff --git a/watchos2/watchos_consts.h b/watchos2/watchos_consts.h index 1ff4a8d..6134f3e 100644 --- a/watchos2/watchos_consts.h +++ b/watchos2/watchos_consts.h @@ -8,5 +8,7 @@ #define WATCHOS_HANDLE_NULL 0x00000000 #define WATCHOS_HANDLE_TYPE_TASK 0x01 +#define WATCHOS_HANDLE_TYPE_EVENT 0x02 +#define WATCHOS_HANDLE_TYPE_EVENT_SUBSCRIPTION 0x03 #endif \ No newline at end of file diff --git a/watchos2/watchos_types.h b/watchos2/watchos_types.h index ee69ec5..36d669e 100644 --- a/watchos2/watchos_types.h +++ b/watchos2/watchos_types.h @@ -4,6 +4,7 @@ /// /// A handle to any kernel object /// -typedef uint32_t kernel_handle_t; +typedef uint16_t kernel_handle_t; +typedef uint64_t well_known_handle_t; #endif