Adam Pippin
4 years ago
commit
a02be354e0
8 changed files with 301 additions and 0 deletions
@ -0,0 +1,19 @@ |
|||||
|
#define TFT_BLACK 0x0000 |
||||
|
#define TFT_NAVY 0x000F |
||||
|
#define TFT_DARKGREEN 0x03E0 |
||||
|
#define TFT_MAROON 0x7800 |
||||
|
#define TFT_PURPLE 0x780F |
||||
|
#define TFT_OLIVE 0x7BE0 |
||||
|
#define TFT_LIGHTGREY 0xC618 |
||||
|
#define TFT_DARKGREY 0x7BEF |
||||
|
#define TFT_BLUE 0x001F |
||||
|
#define TFT_GREENYELLOW 0xB7E0 |
||||
|
#define TFT_GREEN 0x07E0 |
||||
|
#define TFT_YELLOW 0xFFE0 |
||||
|
#define TFT_ORANGE 0xFDA0 |
||||
|
#define TFT_PINK 0xFC9F |
||||
|
#define TFT_CYAN 0x07FF |
||||
|
#define TFT_DARKCYAN 0x03EF |
||||
|
#define TFT_RED 0xF800 |
||||
|
#define TFT_MAGENTA 0xF81F |
||||
|
#define TFT_WHITE 0xFFFF |
@ -0,0 +1,170 @@ |
|||||
|
#include <M5StickC.h> |
||||
|
#include "Kernel.h" |
||||
|
#include "Util.h" |
||||
|
#include "Colours.h" |
||||
|
|
||||
|
#define MAX_TASKS 8 |
||||
|
|
||||
|
struct Task *Kernel_get_task(int pid); |
||||
|
|
||||
|
struct Task tasks[MAX_TASKS]; |
||||
|
int next_pid = 1; |
||||
|
unsigned long last_tick; |
||||
|
|
||||
|
void Kernel_panic(char* message) |
||||
|
{ |
||||
|
M5.Lcd.setRotation(3); |
||||
|
M5.Lcd.fillScreen(TFT_BLUE); |
||||
|
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLUE); |
||||
|
M5.Lcd.setCursor(0, 0); |
||||
|
M5.Lcd.print("Panic! "); |
||||
|
M5.Lcd.print(message); |
||||
|
while(true) {} |
||||
|
} |
||||
|
|
||||
|
void Kernel_setup() |
||||
|
{ |
||||
|
last_tick = millis(); |
||||
|
} |
||||
|
|
||||
|
void Kernel_start(int (*callback)(unsigned int), unsigned long interval) |
||||
|
{ |
||||
|
struct Task *process = Kernel_get_task(0); |
||||
|
if (process->pid == -1) |
||||
|
{ |
||||
|
Kernel_panic("Could not start process -- reached MAX_TASKS"); |
||||
|
} |
||||
|
|
||||
|
process->pid = next_pid++; |
||||
|
process->callback = callback; |
||||
|
process->run_interval = interval; |
||||
|
process->run_accumulator = interval; |
||||
|
process->signal = SIGNAL_START | SIGNAL_TICK; |
||||
|
process->running = true; |
||||
|
} |
||||
|
|
||||
|
void Kernel_enable(int pid) |
||||
|
{ |
||||
|
struct Task *process = Kernel_get_task(pid); |
||||
|
if (process->pid == pid) |
||||
|
{ |
||||
|
process->running = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Kernel_disable(int pid) |
||||
|
{ |
||||
|
struct Task *process = Kernel_get_task(pid); |
||||
|
if (process->pid == pid) |
||||
|
{ |
||||
|
process->running = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Kernel_reap(int pid) |
||||
|
{ |
||||
|
struct Task *process = Kernel_get_task(pid); |
||||
|
if (process->pid != pid || process->running) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
process->pid = 0; |
||||
|
process->running = false; |
||||
|
process->exit_code = 0; |
||||
|
process->run_interval = 0; |
||||
|
process->run_accumulator = 0; |
||||
|
process->signal = SIGNAL_NONE; |
||||
|
process->signal_mask = 0xFFFF; |
||||
|
} |
||||
|
|
||||
|
int Kernel_get_exit_code(int pid) |
||||
|
{ |
||||
|
struct Task *process = Kernel_get_task(pid); |
||||
|
int exit_code = process->pid != pid || process->running == true ? -1 : process->exit_code; |
||||
|
Kernel_reap(pid); |
||||
|
return exit_code; |
||||
|
} |
||||
|
|
||||
|
bool Kernel_is_exited(int pid) |
||||
|
{ |
||||
|
struct Task *process = Kernel_get_task(pid); |
||||
|
return process->pid != pid || process->running == false; |
||||
|
} |
||||
|
|
||||
|
struct Task *Kernel_get_task(int pid) |
||||
|
{ |
||||
|
for (int i=0; i<MAX_TASKS; i++) |
||||
|
{ |
||||
|
if (tasks[i].pid == pid) |
||||
|
{ |
||||
|
return &tasks[i]; |
||||
|
} |
||||
|
} |
||||
|
struct Task empty = Task(); |
||||
|
empty.pid = -1; |
||||
|
return ∅ |
||||
|
} |
||||
|
|
||||
|
void Kernel_tick() |
||||
|
{ |
||||
|
unsigned long duration = millis_since(last_tick); |
||||
|
// Store the last runtime so we can calculate duration next tick. We do this at the beginning of the method
|
||||
|
// so it counts the time spent running tasks as time elapsed.
|
||||
|
last_tick = millis(); |
||||
|
|
||||
|
unsigned long next_tick_due = ULONG_MAX; |
||||
|
|
||||
|
for (int i=0; i<MAX_TASKS; i++) |
||||
|
{ |
||||
|
// If the task is initialized (non-zero PID) and is marked as running
|
||||
|
if (tasks[i].pid != 0 && tasks[i].running == true) |
||||
|
{ |
||||
|
|
||||
|
// Check if this tick's duration will push us over the run interval and if so set the TICK signal
|
||||
|
if (tasks[i].run_accumulator + duration > tasks[i].run_interval) |
||||
|
{ |
||||
|
// Set signal
|
||||
|
tasks[i].signal |= SIGNAL_TICK; |
||||
|
// Reset accumulator so we can start counting again
|
||||
|
tasks[i].run_accumulator = 0; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// Otherwise, accumulate time
|
||||
|
tasks[i].run_accumulator += duration; |
||||
|
} |
||||
|
|
||||
|
// If the process has any non-masked signals pending, run it
|
||||
|
if ((tasks[i].signal & tasks[i].signal_mask) != 0) |
||||
|
{ |
||||
|
// Run the task
|
||||
|
int task_return = (*tasks[i].callback)(tasks[i].signal); |
||||
|
// Reset the signal
|
||||
|
tasks[i].signal = SIGNAL_NONE; |
||||
|
|
||||
|
// If the tasks's return value was non-zero, it has exited.
|
||||
|
if (task_return != 0) |
||||
|
{ |
||||
|
// Mark it as no longer running
|
||||
|
tasks[i].running = false; |
||||
|
// Store the exit code
|
||||
|
tasks[i].exit_code = task_return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// Check each task to see if it's the one scheduled to run on the next closest tick, and track it
|
||||
|
// so we can put the processor to sleep until then.
|
||||
|
if (tasks[i].run_interval - tasks[i].run_accumulator < next_tick_due) |
||||
|
{ |
||||
|
next_tick_due = tasks[i].run_interval - tasks[i].run_accumulator; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Put processor to sleep until the next scheduled run of a task
|
||||
|
// Leave the home button enabled to force a wake-up before then
|
||||
|
esp_sleep_enable_timer_wakeup(next_tick_due * 1000); |
||||
|
esp_sleep_enable_ext0_wakeup((gpio_num_t)37, LOW); |
||||
|
esp_light_sleep_start(); |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
|
||||
|
struct Task |
||||
|
{ |
||||
|
int pid = 0; |
||||
|
bool running = false; |
||||
|
int exit_code = 0; |
||||
|
int (*callback)(unsigned int); |
||||
|
unsigned long run_interval = 0; |
||||
|
unsigned long run_accumulator = 0; |
||||
|
unsigned int signal = 0; |
||||
|
unsigned int signal_mask = 0xFFFF; |
||||
|
}; |
||||
|
|
||||
|
void Kernel_setup(); |
||||
|
void Kernel_tick(); |
||||
|
|
||||
|
// Panic and stop everything
|
||||
|
void Kernel_panic(char* message); |
||||
|
|
||||
|
// Start a new process
|
||||
|
void Kernel_start(int (*callback)(unsigned int), unsigned long interval); |
||||
|
// Continue execution of a process
|
||||
|
void Kernel_enable(int pid); |
||||
|
// Pause execution of a process
|
||||
|
void Kernel_disable(int pid); |
||||
|
// Clean up exited process
|
||||
|
void Kernel_reap(int pid); |
||||
|
|
||||
|
// Check if process has exited
|
||||
|
bool Kernel_is_exited(int pid); |
||||
|
// Get exit code of process
|
||||
|
int Kernel_get_exit_code(int pid); |
||||
|
|
||||
|
#define SIGNAL_NONE 0 |
||||
|
#define SIGNAL_TICK 1 |
||||
|
#define SIGNAL_START 2 |
||||
|
#define SIGNAL_STOP 4 |
@ -0,0 +1,10 @@ |
|||||
|
|
||||
|
void PowerManagement_setup() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void PowerManagement_tick() |
||||
|
{ |
||||
|
|
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
|
||||
|
void PowerManagement_setup(); |
||||
|
void PowerManagement_tick(); |
@ -0,0 +1,16 @@ |
|||||
|
#include <M5StickC.h> |
||||
|
#include "Util.h" |
||||
|
|
||||
|
unsigned long millis_since(unsigned long timestamp) |
||||
|
{ |
||||
|
unsigned long now = millis(); |
||||
|
|
||||
|
if (now < timestamp) |
||||
|
{ |
||||
|
return (4294967295 - timestamp) + millis(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return millis() - timestamp; |
||||
|
} |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
|
||||
|
unsigned long millis_since(unsigned long timestamp); |
@ -0,0 +1,44 @@ |
|||||
|
#include <M5StickC.h> |
||||
|
#include "PowerManagement.h" |
||||
|
#include "Kernel.h" |
||||
|
#include "Colours.h" |
||||
|
|
||||
|
int count = 0; |
||||
|
int test_func(unsigned int signal) |
||||
|
{ |
||||
|
M5.Lcd.fillScreen(TFT_DARKGREY); |
||||
|
M5.Lcd.setCursor(0, 0); |
||||
|
if (signal & SIGNAL_START) |
||||
|
{ |
||||
|
M5.Lcd.setRotation(3); |
||||
|
M5.Lcd.print("Initializing..."); |
||||
|
} |
||||
|
if (signal & SIGNAL_STOP) |
||||
|
{ |
||||
|
M5.Lcd.print("Stopping"); |
||||
|
return 255; |
||||
|
} |
||||
|
if (signal & SIGNAL_TICK) |
||||
|
{ |
||||
|
count++; |
||||
|
M5.Lcd.print("Ran: "); |
||||
|
M5.Lcd.print(String(count)); |
||||
|
M5.Lcd.print(" times"); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void setup() |
||||
|
{ |
||||
|
M5.begin(); |
||||
|
Kernel_setup(); |
||||
|
PowerManagement_setup(); |
||||
|
|
||||
|
Kernel_start(&test_func, 1000); |
||||
|
} |
||||
|
|
||||
|
void loop() |
||||
|
{ |
||||
|
Kernel_tick(); |
||||
|
PowerManagement_tick(); |
||||
|
} |
Loading…
Reference in new issue