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
{
uint32_t source;
well_known_handle_t source;
uint16_t event;
byte param1;
byte param2;

34
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<Event*> m_events;
protected:
bool hasEvent();
Event* popEvent();
public:
void pushEvent(kernel_handle_t handle);
uint32_t getEventSourceMask();
uint16_t getEventTypeMask();
};
watchos::reference(handle);
m_event_queue->push(handle);
}

13
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<kernel_handle_t> 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

120
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<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()
{
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++)

19
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:
/// <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>
/// <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>
/// 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>
void* getHandle(kernel_handle_t handle);
/// <summary>
/// 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);
void useHandle(kernel_handle_t handle);
/// <summary>
/// Release a fetched reference to this object
@ -53,9 +52,15 @@ public:
/// <param name="handle">Handle to release</param>
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();
};

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<T>::Queue()
Queue::Queue()
{
for (int i = 0; i < QUEUE_RING_SIZE; i++)
{
m_item[i] = nullptr;
m_item[i] = WATCHOS_HANDLE_NULL;
}
}
template<typename T>
void Queue<T>::push(T* item)
void Queue::push(kernel_handle_t item)
{
if (m_full)
{
@ -31,8 +29,7 @@ void Queue<T>::push(T* item)
}
}
template<typename T>
T* Queue<T>::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<T>::peek()
return m_item[m_read];
}
template<typename T>
T* Queue<T>::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<T>::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<T>::pop()
return nextItem;
}
template<typename T>
bool Queue<T>::isEmpty()
bool Queue::isEmpty()
{
return m_read == m_write && !m_full;
}
template<typename T>
int Queue<T>::next(int n)
int Queue::next(int n)
{
if (n + 1 == QUEUE_RING_SIZE)
return 0;

11
watchos2/Queue.h

@ -1,21 +1,22 @@
#ifndef _QUEUE_h
#define _QUEUE_h
#include "watchos_types.h"
#define QUEUE_RING_SIZE 8
template<typename T>
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();
};

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();
};
#endif
#endif

18
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();
}
}
};

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);
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<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_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

3
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);
}

2
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

3
watchos2/watchos_types.h

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

Loading…
Cancel
Save