Browse Source

Eventing system, queues, tasks

master
Adam PIppin 3 years ago
parent
commit
e60ef05c05
  1. 2
      watchos2/Event.h
  2. 34
      watchos2/EventListener.cpp
  3. 13
      watchos2/EventListener.h
  4. 120
      watchos2/Kernel.cpp
  5. 19
      watchos2/Kernel.h
  6. 0
      watchos2/Module_UI.cpp
  7. 21
      watchos2/Module_UI.h
  8. 24
      watchos2/Queue.cpp
  9. 11
      watchos2/Queue.h
  10. 4
      watchos2/Queues.cpp
  11. 3
      watchos2/Task.h
  12. 18
      watchos2/Task_Test.cpp
  13. 2
      watchos2/__vm/Compile.vmps.xml
  14. 2
      watchos2/__vm/Upload.vmps.xml
  15. 42
      watchos2/watchos.cpp
  16. 14
      watchos2/watchos.h
  17. 3
      watchos2/watchos2.ino
  18. 2
      watchos2/watchos_consts.h
  19. 3
      watchos2/watchos_types.h

2
watchos2/Events.h → watchos2/Event.h

@ -3,7 +3,7 @@
struct Event struct Event
{ {
uint32_t source; well_known_handle_t source;
uint16_t event; uint16_t event;
byte param1; byte param1;
byte param2; byte param2;

34
watchos2/EventListener.cpp

@ -1,26 +1,34 @@
#include "watchos.h"
#include "EventListener.h" #include "EventListener.h"
EventListener::EventListener()
{
m_event_queue = new Queue();
}
bool EventListener::hasEvent() 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: watchos::reference(handle);
Queue<Event*> m_events; m_event_queue->push(handle);
protected: }
bool hasEvent();
Event* popEvent();
public:
void pushEvent(kernel_handle_t handle);
uint32_t getEventSourceMask();
uint16_t getEventTypeMask();
};

13
watchos2/EventListener.h

@ -1,22 +1,21 @@
#ifndef _EVENTLISTENER_h #ifndef _EVENTLISTENER_h
#define _EVENTLISTENER_h #define _EVENTLISTENER_h
#include "watchos.h" #include "watchos_consts.h"
#include "Queue.h" #include "Queue.h"
#include "Events.h" #include "Event.h"
class EventListener class EventListener
{ {
private: private:
Queue<kernel_handle_t> m_event_queue; Queue* m_event_queue;
protected: protected:
bool hasEvent(); bool hasEvent();
Event* popEvent(); Event* getEvent();
void releaseEvent(kernel_handle_t handle); void popEvent();
public: public:
EventListener();
void pushEvent(kernel_handle_t handle); void pushEvent(kernel_handle_t handle);
uint32_t getEventSourceMask();
uint16_t getEventTypeMask();
}; };
#endif #endif

120
watchos2/Kernel.cpp

@ -1,4 +1,6 @@
#include "watchos.h" #include "watchos.h"
#include "Event.h"
#include "EventListener.h"
#include "IRunnable.h" #include "IRunnable.h"
struct KernelHandle struct KernelHandle
@ -16,13 +18,39 @@ struct KernelTask
Task* task; 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) void destruct_task(kernel_handle_t handle, void* object)
{ {
delete object; Task* task = static_cast<Task*>(object);
g_kernel->unregisterTask(task);
delete static_cast<Task*>(task);
}
void destruct_event(kernel_handle_t, void* object)
{
delete static_cast<Event*>(object);
}
void destruct_event_subscription(kernel_handle_t, void* object)
{
KernelEventSubscription* sub = static_cast<KernelEventSubscription*>(object);
g_kernel->unsubscribeEvent(sub);
delete static_cast<KernelEventSubscription*>(sub);
} }
Kernel::Kernel() Kernel::Kernel()
{ {
g_kernel = this;
for (int i = 0; i < KERNEL_MAX_HANDLES; i++) for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
{ {
m_handle[i] = nullptr; m_handle[i] = nullptr;
@ -32,6 +60,11 @@ Kernel::Kernel()
{ {
m_task[i] = nullptr; 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) 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) if (m_handle[i] == nullptr)
{ {
m_handle[i] = new KernelHandle(); 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]->destructor = destructor;
m_handle[i]->object = object; m_handle[i]->object = object;
m_handle[i]->references = 1; m_handle[i]->references = 0;
m_handle[i]->well_known = well_known; m_handle[i]->well_known = well_known;
return m_handle[i]->handle; return m_handle[i]->handle;
} }
@ -64,6 +97,7 @@ void Kernel::freeHandle(kernel_handle_t handle)
} }
delete m_handle[i]; delete m_handle[i];
m_handle[i] = nullptr; 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) if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
{ {
m_handle[i]->references++;
return m_handle[i]->object; return m_handle[i]->object;
} }
} }
watchos::panic("Attempt to access invalid Kernel handle"); 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++) for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
{ {
if (m_handle[i] != nullptr && m_handle[i]->well_known == well_known) 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++; 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) void Kernel::releaseHandle(kernel_handle_t handle)
@ -121,8 +167,9 @@ kernel_handle_t Kernel::registerTask(Task* task)
if (m_task[i] == nullptr) if (m_task[i] == nullptr)
{ {
m_task[i] = new KernelTask(); 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; m_task[i]->task = task;
useHandle(m_task[i]->handle);
return 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) if (m_task[i] != nullptr && m_task[i]->task == task)
{ {
releaseHandle(m_task[i]->handle); delete m_task[i]->task;
delete m_task[i]; delete m_task[i];
m_task[i] = nullptr; m_task[i] = nullptr;
return; 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() void Kernel::tick()
{ {
for (int i = 0; i < KERNEL_MAX_TASKS; i++) for (int i = 0; i < KERNEL_MAX_TASKS; i++)

19
watchos2/Kernel.h

@ -2,14 +2,17 @@
#define _KERNEL_h #define _KERNEL_h
#include "Task.h" #include "Task.h"
#include "EventListener.h"
#define KERNEL_MAX_HANDLES 256 #define KERNEL_MAX_HANDLES 256
#define KERNEL_MAX_TASKS 32 #define KERNEL_MAX_TASKS 32
#define KERNEL_MAX_EVENT_SUBSCRIPTIONS 64
typedef void (*kernel_handle_destructor_t)(kernel_handle_t, void*); typedef void (*kernel_handle_destructor_t)(kernel_handle_t, void*);
struct KernelHandle; struct KernelHandle;
struct KernelTask; struct KernelTask;
struct KernelEventSubscription;
class Kernel class Kernel
{ {
@ -17,6 +20,7 @@ private:
KernelHandle* m_handle[KERNEL_MAX_HANDLES]; KernelHandle* m_handle[KERNEL_MAX_HANDLES];
int m_next_handle = 1; int m_next_handle = 1;
KernelTask* m_task[KERNEL_MAX_TASKS]; KernelTask* m_task[KERNEL_MAX_TASKS];
KernelEventSubscription* m_event_subscription[KERNEL_MAX_EVENT_SUBSCRIPTIONS];
void freeHandle(kernel_handle_t handle); void freeHandle(kernel_handle_t handle);
@ -31,7 +35,7 @@ public:
/// <param name="destructor">Function to call when this handle has released all references</param> /// <param name="destructor">Function to call when this handle has released all references</param>
/// <param name="well_known">Specify a 'well_known' value this pointer can be fetched by</param> /// <param name="well_known">Specify a 'well_known' value this pointer can be fetched by</param>
/// <returns>A handle which can be used to fetch or release this object</returns> /// <returns>A handle which can be used to fetch or release this object</returns>
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);
/// <summary> /// <summary>
/// Fetch the object referenced by this handle, increasing the reference count /// Fetch the object referenced by this handle, increasing the reference count
@ -40,12 +44,7 @@ public:
/// <returns>A pointer to the object the handle references</returns> /// <returns>A pointer to the object the handle references</returns>
void* getHandle(kernel_handle_t handle); void* getHandle(kernel_handle_t handle);
/// <summary> void useHandle(kernel_handle_t handle);
/// Fetch an object by its well-known value, increasing the reference count
/// </summary>
/// <param name="well_known">Well-known id of handle</param>
/// <returns>A pointer to the object the handle references</returns>
void* getHandle(byte well_known);
/// <summary> /// <summary>
/// Release a fetched reference to this object /// Release a fetched reference to this object
@ -53,9 +52,15 @@ public:
/// <param name="handle">Handle to release</param> /// <param name="handle">Handle to release</param>
void releaseHandle(kernel_handle_t handle); void releaseHandle(kernel_handle_t handle);
kernel_handle_t getHandleForWellKnown(well_known_handle_t handle);
kernel_handle_t registerTask(Task* task); kernel_handle_t registerTask(Task* task);
void unregisterTask(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(); void tick();
}; };

0
watchos2/Module_UI.cpp

21
watchos2/Module_UI.h

@ -0,0 +1,21 @@
#ifndef _MODULE_UI_h
#define _MODULE_UI_h
#include <Arduino.h>
#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

24
watchos2/Queue.cpp

@ -1,16 +1,14 @@
#include "Queue.h" #include "watchos.h"
template<typename T> Queue::Queue()
Queue<T>::Queue()
{ {
for (int i = 0; i < QUEUE_RING_SIZE; i++) for (int i = 0; i < QUEUE_RING_SIZE; i++)
{ {
m_item[i] = nullptr; m_item[i] = WATCHOS_HANDLE_NULL;
} }
} }
template<typename T> void Queue::push(kernel_handle_t item)
void Queue<T>::push(T* item)
{ {
if (m_full) if (m_full)
{ {
@ -31,8 +29,7 @@ void Queue<T>::push(T* item)
} }
} }
template<typename T> kernel_handle_t Queue::peek()
T* Queue<T>::peek()
{ {
// If the next position to read and write match but the buffer isn't full, // If the next position to read and write match but the buffer isn't full,
// then the buffer is empty // then the buffer is empty
@ -44,8 +41,7 @@ T* Queue<T>::peek()
return m_item[m_read]; return m_item[m_read];
} }
template<typename T> kernel_handle_t Queue::pop()
T* Queue<T>::pop()
{ {
// If the next position to read and write match but the buffer isn't full, // If the next position to read and write match but the buffer isn't full,
// then the buffer is empty // then the buffer is empty
@ -54,7 +50,7 @@ T* Queue<T>::pop()
watchos::panic("Cannot dequeue event: ring buffer empty"); 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 // Move to the next read position
m_read = next(m_read); m_read = next(m_read);
// We can never be full if we just removed an item // We can never be full if we just removed an item
@ -63,14 +59,12 @@ T* Queue<T>::pop()
return nextItem; return nextItem;
} }
template<typename T> bool Queue::isEmpty()
bool Queue<T>::isEmpty()
{ {
return m_read == m_write && !m_full; return m_read == m_write && !m_full;
} }
template<typename T> int Queue::next(int n)
int Queue<T>::next(int n)
{ {
if (n + 1 == QUEUE_RING_SIZE) if (n + 1 == QUEUE_RING_SIZE)
return 0; return 0;

11
watchos2/Queue.h

@ -1,21 +1,22 @@
#ifndef _QUEUE_h #ifndef _QUEUE_h
#define _QUEUE_h #define _QUEUE_h
#include "watchos_types.h"
#define QUEUE_RING_SIZE 8 #define QUEUE_RING_SIZE 8
template<typename T>
class Queue class Queue
{ {
private: private:
T* m_item[QUEUE_RING_SIZE]; kernel_handle_t m_item[QUEUE_RING_SIZE];
int m_read = 0, m_write = 0; int m_read = 0, m_write = 0;
bool m_full = false; bool m_full = false;
int next(int n); int next(int n);
public: public:
Queue(); Queue();
void push(T* item); void push(kernel_handle_t item);
T* pop(); kernel_handle_t pop();
T* peek(); kernel_handle_t peek();
bool isEmpty(); bool isEmpty();
}; };

4
watchos2/Queues.cpp

@ -1,4 +0,0 @@
#include "Queue.h"
#include "Queue.cpp"
template class Queue<int>;

3
watchos2/Task.h

@ -9,5 +9,4 @@ public:
virtual void suspend(); virtual void suspend();
}; };
#endif #endif

18
watchos2/Task_Test.cpp

@ -1,12 +1,22 @@
#include "watchos.h" #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: public:
Task_Test()
{
watchos::subscribe(this, 0xffffffffffffffffu, 0xffffu);
}
void tick() 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();
}
} }
}; };

2
watchos2/__vm/Compile.vmps.xml

File diff suppressed because one or more lines are too long

2
watchos2/__vm/Upload.vmps.xml

File diff suppressed because one or more lines are too long

42
watchos2/watchos.cpp

@ -27,9 +27,13 @@ void watchos::panic(char* fmt...)
vsprintf(msg, fmt, args); vsprintf(msg, fmt, args);
va_end(args); va_end(args);
Serial.println(msg); Serial.println(msg);
#ifdef WATCHOS_DEBUG
for (;;) {}
#else
delay(3000); delay(3000);
Serial.println("Resetting..."); Serial.println("Resetting...");
ESP.restart(); ESP.restart();
#endif
} }
void watchos::debug(char* fmt...) void watchos::debug(char* fmt...)
@ -42,4 +46,42 @@ void watchos::debug(char* fmt...)
va_end(args); va_end(args);
Serial.println(msg); Serial.println(msg);
#endif #endif
}
Event* watchos::event(kernel_handle_t event)
{
return static_cast<Event*>(kernel()->getHandle(event));
}
Task* watchos::task(kernel_handle_t task)
{
return static_cast<Task*>(kernel()->getHandle(task));
}
Task* watchos::task(well_known_handle_t handle)
{
return static_cast<Task*>(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<EventListener*>(task);
if (el == nullptr)
watchos::panic("Cannot subscribe task to events--must implement EventListener");
return kernel()->subscribeEvent(el, source_mask, event_mask);
} }

14
watchos2/watchos.h

@ -7,7 +7,11 @@
#include "watchos_hw.h" #include "watchos_hw.h"
#include "watchos_types.h" #include "watchos_types.h"
#include "Event.h"
#include "EventListener.h"
#include "Kernel.h" #include "Kernel.h"
#include "Task.h"
#include "IRunnable.h"
class watchos class watchos
{ {
@ -20,6 +24,16 @@ public:
static void panic(char* fmt...); static void panic(char* fmt...);
static void debug(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 #endif

3
watchos2/watchos2.ino

@ -13,8 +13,9 @@ void setup() {
delay(500); delay(500);
watchos::initialize(); watchos::initialize();
Kernel* kernel = watchos::kernel(); Kernel* kernel = watchos::kernel();
kernel->registerTask(new Task_Test()); watchos::run(new Task_Test());
watchos::debug("Setup done!"); watchos::debug("Setup done!");
kernel->pushEvent(0xDEADBEEFu, 0x01, 0x10, 0x20);
} }

2
watchos2/watchos_consts.h

@ -8,5 +8,7 @@
#define WATCHOS_HANDLE_NULL 0x00000000 #define WATCHOS_HANDLE_NULL 0x00000000
#define WATCHOS_HANDLE_TYPE_TASK 0x01 #define WATCHOS_HANDLE_TYPE_TASK 0x01
#define WATCHOS_HANDLE_TYPE_EVENT 0x02
#define WATCHOS_HANDLE_TYPE_EVENT_SUBSCRIPTION 0x03
#endif #endif

3
watchos2/watchos_types.h

@ -4,6 +4,7 @@
/// <summary> /// <summary>
/// A handle to any kernel object /// A handle to any kernel object
/// </summary> /// </summary>
typedef uint32_t kernel_handle_t; typedef uint16_t kernel_handle_t;
typedef uint64_t well_known_handle_t;
#endif #endif

Loading…
Cancel
Save