platform for developing on SQFMI's Watchy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

295 lines
6.8 KiB

#include "watchos.h"
#include "Event.h"
#include "EventListener.h"
#include "IRunnable.h"
struct KernelHandle
{
kernel_handle_t handle;
kernel_handle_destructor_t destructor;
void* object;
uint references;
uint32_t well_known = 0;
};
struct KernelTask
{
kernel_handle_t handle;
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)
{
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;
}
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
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)
{
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
{
if (m_handle[i] == nullptr)
{
m_handle[i] = new KernelHandle();
m_handle[i]->handle = (type << 24) | m_next_handle++;
m_handle[i]->destructor = destructor;
m_handle[i]->object = object;
m_handle[i]->references = 0;
m_handle[i]->well_known = well_known;
return m_handle[i]->handle;
}
}
watchos::panic("Exceeded KERNEL_MAX_HANDLES");
}
void Kernel::freeHandle(kernel_handle_t handle)
{
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
{
if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
{
if (m_handle[i]->destructor != nullptr)
{
(m_handle[i]->destructor)(handle, m_handle[i]->object);
}
delete m_handle[i];
m_handle[i] = nullptr;
return;
}
}
}
void* Kernel::getHandle(kernel_handle_t handle)
{
for (int i = 0; i < KERNEL_MAX_HANDLES; i++)
{
if (m_handle[i] != nullptr && m_handle[i]->handle == handle)
{
return m_handle[i]->object;
}
}
watchos::panic("Attempt to access invalid Kernel handle");
}
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;
}
}
watchos::panic("Attempt to increase ref count on invalid Kernel handle");
}
void Kernel::releaseHandle(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--;
if (m_handle[i]->references == 0)
{
freeHandle(handle);
}
return;
}
}
watchos::panic("Attempt to release invalid Kernel handle");
}
kernel_handle_t Kernel::registerTask(Task* task, well_known_handle_t wk_handle)
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] == nullptr)
{
m_task[i] = new KernelTask();
m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, task, (kernel_handle_destructor_t)destruct_task, wk_handle);
m_task[i]->task = task;
useHandle(m_task[i]->handle);
return m_task[i]->handle;
}
}
watchos::panic("Exceeded KERNEL_MAX_TASKS");
}
void Kernel::unregisterTask(Task* task)
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr && m_task[i]->task == task)
{
delete m_task[i]->task;
delete m_task[i];
m_task[i] = nullptr;
return;
}
}
}
void Kernel::initialize()
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr)
{
m_task[i]->task->initialize();
}
}
}
void Kernel::start()
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr)
{
m_task[i]->task->start();
}
}
}
void Kernel::suspend()
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr)
{
m_task[i]->task->suspend();
}
}
}
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++)
{
if (m_task[i] != nullptr)
{
IRunnable* runnable = dynamic_cast<IRunnable*>(m_task[i]->task);
if (runnable != nullptr)
{
runnable->tick();
}
}
}
}