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.
308 lines
6.2 KiB
308 lines
6.2 KiB
// Arduino System
|
|
#include <Arduino.h>
|
|
// RTC
|
|
#include <DS3232RTC.h>
|
|
// I2C Library
|
|
#include <Wire.h>
|
|
// Hardware information
|
|
#include "watchos_hw.h"
|
|
|
|
#include "watchos.h"
|
|
|
|
#define SCOPE_SIZE 64
|
|
|
|
Kernel* Kernel::s_kernel = nullptr;
|
|
char scope[SCOPE_SIZE];
|
|
|
|
struct EventSubscription
|
|
{
|
|
int handle;
|
|
void (*callback)(Event* e); // module, event, param1, param2
|
|
Task* target;
|
|
byte source_mask = 0;
|
|
byte event_mask = 0;
|
|
|
|
};
|
|
|
|
Kernel::Kernel()
|
|
{
|
|
sprintf(scope, "[SYSTEM]");
|
|
|
|
Wire.begin(HW_I2C_SDA, HW_I2C_SCL);
|
|
|
|
// Initialize empty tasks
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
m_task[i] = nullptr;
|
|
}
|
|
|
|
// Initialize empty modules
|
|
for (int i = 0; i < KERNEL_MAX_MODULES; i++)
|
|
{
|
|
m_module[i] = nullptr;
|
|
}
|
|
|
|
// Initialize event callbacks
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
m_event_subscription[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a singleton instance of the kernel
|
|
*/
|
|
void Kernel::initialize()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_MODULES; i++)
|
|
{
|
|
if (m_module[i] != nullptr)
|
|
{
|
|
sprintf(scope, "[MODULE:%d]", m_module[i]->getId());
|
|
m_module[i]->initialize();
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
sprintf(scope, "[TASK:%d]", m_task[i]->getId());
|
|
m_task[i]->initialize();
|
|
}
|
|
}
|
|
sprintf(scope, "[SYSTEM]");
|
|
}
|
|
|
|
/**
|
|
* Fetch the singleton instance of the kernel
|
|
*/
|
|
Kernel* Kernel::get()
|
|
{
|
|
if (s_kernel == nullptr)
|
|
{
|
|
s_kernel = new Kernel();
|
|
}
|
|
return s_kernel;
|
|
}
|
|
|
|
/**
|
|
* Unrecoverable error -- shut everything down
|
|
*/
|
|
void Kernel::panic(char* message)
|
|
{
|
|
// TODO: Would be good to print to screen once display module exists
|
|
Serial.printf("Kernel panic!\n");
|
|
if (xPortGetCoreID() == 0)
|
|
Serial.printf("Scope: %s\n", scope);
|
|
else
|
|
Serial.printf("Scope: UI Draw\n");
|
|
Serial.printf("%s\n", message);
|
|
while (true) {}
|
|
}
|
|
|
|
/**
|
|
* Write out debug messaging
|
|
*/
|
|
void Kernel::debug(char* message)
|
|
{
|
|
// TODO: Print active PID
|
|
Serial.printf("%s %s\n", scope, message);
|
|
}
|
|
|
|
/**
|
|
* Tick -- run all processes/modules as appropriate
|
|
*/
|
|
void Kernel::tick()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_MODULES; i++)
|
|
{
|
|
if (m_module[i] != nullptr)
|
|
{
|
|
sprintf(scope, "[MODULE:%d]", m_module[i]->getId());
|
|
m_module[i]->tick();
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
sprintf(scope, "[TASK:%d]", m_task[i]->getId());
|
|
m_task[i]->tick(0);
|
|
}
|
|
}
|
|
|
|
sprintf(scope, "[SYSTEM]");
|
|
}
|
|
|
|
/**
|
|
* Tell all processes/modules to suspend
|
|
*/
|
|
void Kernel::suspend()
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_MODULES; i++)
|
|
{
|
|
if (m_module[i] != nullptr)
|
|
{
|
|
sprintf(scope, "[MODULE:%d]", m_module[i]->getId());
|
|
m_module[i]->suspend();
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr)
|
|
{
|
|
sprintf(scope, "[TASK:%d]", m_task[i]->getId());
|
|
m_task[i]->suspend();
|
|
}
|
|
}
|
|
|
|
sprintf(scope, "[SYSTEM]");
|
|
}
|
|
|
|
/**
|
|
* Register a new task in the kernel
|
|
*/
|
|
int Kernel::registerTask(Task* task)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] == nullptr)
|
|
{
|
|
m_task[i] = task;
|
|
task->setId(m_pid++); // TODO: real pid
|
|
return i;
|
|
}
|
|
}
|
|
Kernel::panic("Exceeded KERNEL_MAX_TASKS!");
|
|
}
|
|
|
|
void Kernel::unregisterTask(int pid)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr && m_task[i]->getId() == pid)
|
|
{
|
|
delete m_task[i];
|
|
m_task[i] = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Kernel::isTaskRunning(int pid)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
|
|
{
|
|
if (m_task[i] != nullptr && m_task[i]->getId() == pid)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Register a new module in the kernel
|
|
*/
|
|
void Kernel::registerModule(Module* module)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_MODULES; i++)
|
|
{
|
|
if (m_module[i] == nullptr)
|
|
{
|
|
m_module[i] = module;
|
|
return;
|
|
}
|
|
}
|
|
Kernel::panic("Exceeded KERNEL_MAX_MODULES!");
|
|
}
|
|
|
|
Module* Kernel::getModule(int module_id)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_MODULES; i++)
|
|
{
|
|
if (m_module[i] != nullptr && m_module[i]->getId() == module_id)
|
|
{
|
|
return m_module[i];
|
|
}
|
|
}
|
|
Kernel::panic("Module not found");
|
|
}
|
|
|
|
void Kernel::event(byte source, byte event, byte param1, byte param2)
|
|
{
|
|
Event* e = new Event();
|
|
e->source = source;
|
|
e->event = event;
|
|
e->param1 = param1;
|
|
e->param2 = param2;
|
|
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] != nullptr)
|
|
{
|
|
if ((m_event_subscription[i]->source_mask & source) == source &&
|
|
(m_event_subscription[i]->event_mask & event) == event)
|
|
{
|
|
if (m_event_subscription[i]->callback != nullptr)
|
|
{
|
|
m_event_subscription[i]->callback(e);
|
|
}
|
|
else if (m_event_subscription[i]->target != nullptr)
|
|
{
|
|
m_event_subscription[i]->target->pushEvent(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int Kernel::subscribe(void (*callback)(Event* e), byte source_mask, byte event_mask)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] == nullptr)
|
|
{
|
|
m_event_subscription[i] = new EventSubscription();
|
|
m_event_subscription[i]->handle = ++m_handle;
|
|
m_event_subscription[i]->callback = callback;
|
|
m_event_subscription[i]->source_mask = source_mask;
|
|
m_event_subscription[i]->event_mask = event_mask;
|
|
return m_event_subscription[i]->handle;
|
|
}
|
|
}
|
|
Kernel::panic("Exceeded KERNEL_MAX_EVENT_SUBSCRIPTIONS!");
|
|
}
|
|
|
|
int Kernel::subscribe(Task* task, byte source_mask, byte event_mask)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] == nullptr)
|
|
{
|
|
m_event_subscription[i] = new EventSubscription();
|
|
m_event_subscription[i]->handle = ++m_handle;
|
|
m_event_subscription[i]->target = task;
|
|
m_event_subscription[i]->source_mask = source_mask;
|
|
m_event_subscription[i]->event_mask = event_mask;
|
|
return m_event_subscription[i]->handle;
|
|
}
|
|
}
|
|
|
|
Kernel::panic("Exceeded KERNEL_MAX_EVENT_SUBSCRIPTIONS!");
|
|
}
|
|
|
|
void Kernel::unsubscribe(int handle)
|
|
{
|
|
for (int i = 0; i < KERNEL_MAX_EVENT_SUBSCRIPTIONS; i++)
|
|
{
|
|
if (m_event_subscription[i] != nullptr && m_event_subscription[i]->handle == handle)
|
|
{
|
|
delete m_event_subscription[i];
|
|
return;
|
|
}
|
|
}
|
|
}
|