diff --git a/Kernel.cpp b/Kernel.cpp index 01e725f..2152ed5 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -10,6 +10,7 @@ struct Task *Kernel_get_task(int pid); struct Task tasks[MAX_TASKS]; int next_pid = 1; unsigned long last_tick; +bool inputs[2] = {false, false}; void Kernel_panic(char* message) { @@ -25,9 +26,10 @@ void Kernel_panic(char* message) void Kernel_setup() { last_tick = millis(); + //Serial.begin(115200); } -void Kernel_start(int (*callback)(unsigned int), unsigned long interval) +void Kernel_start(int (*callback)(int, unsigned int), unsigned long interval) { struct Task *process = Kernel_get_task(0); if (process->pid == -1) @@ -77,6 +79,64 @@ void Kernel_reap(int pid) process->signal_mask = 0xFFFF; } +void Kernel_signal(unsigned int signal) +{ + for (int i=0; ipid == pid) + { + process->signal |= signal; + } +} + +void Kernel_signal_mask(int pid, unsigned int signal_mask) +{ + struct Task *process = Kernel_get_task(pid); + if (process->pid == pid) + { + process->signal_mask = signal_mask; + } +} + +unsigned long Kernel_get_run_interval(int pid) +{ + struct Task *process = Kernel_get_task(pid); + return process->pid == pid ? process->run_interval : 0; +} + +void Kernel_set_run_interval(int pid, unsigned long interval) +{ + struct Task *process = Kernel_get_task(pid); + if (process->pid == pid) + { + process->run_interval = interval; + } + +} + +int Kernel_count_running_tasks() +{ + int count = 0; + for (int i=0; ipid != pid || process->running == false; } +bool Kernel_read_input(int input) +{ + bool value = inputs[input]; + inputs[input] = false; + return value; +} + struct Task *Kernel_get_task(int pid) { for (int i=0; i tasks[i].run_interval) + // Check if this process is running on a schedule and this tick's duration will push us over the run interval and if so set the TICK signal + // run_interval 0 is a special case of "run whenever we run", so set TICK any time we get here + if (tasks[i].run_interval > 0) { - // Set signal - tasks[i].signal |= SIGNAL_TICK; - // Reset accumulator so we can start counting again - tasks[i].run_accumulator = 0; + 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; + } } else { - // Otherwise, accumulate time - tasks[i].run_accumulator += duration; + tasks[i].signal |= SIGNAL_TICK; } // 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); + int task_return = (*tasks[i].callback)(tasks[i].pid, tasks[i].signal); // Reset the signal tasks[i].signal = SIGNAL_NONE; @@ -162,7 +237,7 @@ void Kernel_tick() // 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].running && tasks[i].run_interval - tasks[i].run_accumulator < next_tick_due) + if (tasks[i].running && tasks[i].run_interval > 0 && tasks[i].run_interval - tasks[i].run_accumulator < next_tick_due) { next_tick_due = tasks[i].run_interval - tasks[i].run_accumulator; } @@ -176,9 +251,35 @@ void Kernel_tick() Kernel_panic(panic_msg); } - // Put processor to sleep until the next scheduled run of a task + // If no signals pending, 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(); + bool signals_pending = false; + for (int i=0; i +#include "Kernel.h" +#include "PowerManagement.h" -void PowerManagement_setup() +#define IDLE_TIMEOUT 5000 +#define SLEEP_TIMEOUT 10000 + +#define POWER_STATE_WAKE 0 +#define POWER_STATE_IDLE 1 +#define POWER_STATE_SLEEP 2 + +unsigned long accumulator = 0; +int power_state = 0; + +void sleep() { - + power_state = POWER_STATE_SLEEP; + M5.Axp.DeepSleep(); } -void PowerManagement_tick() +void idle() { + power_state = POWER_STATE_IDLE; + M5.Axp.ScreenBreath(7); +} + +void wake() +{ + power_state = POWER_STATE_WAKE; + M5.Axp.ScreenBreath(12); +} +int PowerManagement(int pid, unsigned int signal) +{ + // Receive start/stop/input/tick signals + if (signal & SIGNAL_START) + { + Kernel_signal_mask(pid, SIGNAL_START | SIGNAL_STOP | SIGNAL_INPUT_A | SIGNAL_INPUT_B | SIGNAL_TICK); + } + + // Accumulate time every time we run + if ((signal & SIGNAL_START) == 0 && signal & SIGNAL_TICK) + { + accumulator += Kernel_get_run_interval(pid); + } + + // But reset it whenever a button is pressed + if ((signal & SIGNAL_INPUT_A) != 0 || (signal & SIGNAL_INPUT_B) != 0) + { + if (power_state != POWER_STATE_WAKE) + { + wake(); + } + accumulator = 0; + } + + switch (power_state) + { + case POWER_STATE_WAKE: + if (accumulator > IDLE_TIMEOUT) + { + idle(); + } + break; + case POWER_STATE_IDLE: + if (accumulator > SLEEP_TIMEOUT) + { + sleep(); + } + break; + } + + // TODO: On sleep, signal "STOP" to all tasks and reschedule ourselves more frequently + // Wait until Kernel_count_running == 1, then put chip to sleep + + return 0; + } diff --git a/PowerManagement.h b/PowerManagement.h index da44c18..9cc4c4e 100644 --- a/PowerManagement.h +++ b/PowerManagement.h @@ -1,3 +1,2 @@ -void PowerManagement_setup(); -void PowerManagement_tick(); +int PowerManagement(int pid, unsigned int signal); diff --git a/UserInput.cpp b/UserInput.cpp new file mode 100644 index 0000000..b8be5aa --- /dev/null +++ b/UserInput.cpp @@ -0,0 +1,25 @@ +#include +#include "Kernel.h" + +int UserInput(int pid, unsigned int signal) +{ + Serial.println("UserInput called"); + if (signal & SIGNAL_START) + { + Kernel_signal_mask(pid, SIGNAL_START | SIGNAL_STOP | SIGNAL_TICK); + } + if (signal & SIGNAL_TICK) + { + if (Kernel_read_input(KERNEL_INPUT_BUTTON_A)) + { + Kernel_signal(SIGNAL_INPUT_A); + } + + if (Kernel_read_input(KERNEL_INPUT_BUTTON_B)) + { + Kernel_signal(SIGNAL_INPUT_B); + } + } + + return 0; +} diff --git a/UserInput.h b/UserInput.h new file mode 100644 index 0000000..78c5588 --- /dev/null +++ b/UserInput.h @@ -0,0 +1,2 @@ + +int UserInput(int pid, unsigned int signal); diff --git a/watchos.ino b/watchos.ino index 22a4d10..e8a4a2f 100644 --- a/watchos.ino +++ b/watchos.ino @@ -1,10 +1,12 @@ #include -#include "PowerManagement.h" #include "Kernel.h" #include "Colours.h" +#include "PowerManagement.h" +#include "UserInput.h" + int count = 0; -int test_func(unsigned int signal) +int test_func(int pid, unsigned int signal) { M5.Lcd.fillScreen(TFT_DARKGREY); M5.Lcd.setCursor(0, 0); @@ -13,18 +15,28 @@ int test_func(unsigned int signal) M5.Lcd.setRotation(3); M5.Lcd.print("Initializing..."); } - if (signal & SIGNAL_STOP) + if ((signal & SIGNAL_STOP)) // || count == 5) { M5.Lcd.print("Stopping"); return 255; } - if (signal & SIGNAL_TICK) + if (signal & SIGNAL_TICK && (signal & SIGNAL_INPUT_A) == 0 && (signal & SIGNAL_INPUT_B) ==0) { count++; M5.Lcd.print("Ran: "); M5.Lcd.print(String(count)); M5.Lcd.print(" times"); } + + if (signal & SIGNAL_INPUT_A) + { + M5.Lcd.print("Input A!"); + } + + if (signal & SIGNAL_INPUT_B) + { + M5.Lcd.print("Input B!"); + } return 0; } @@ -32,13 +44,13 @@ void setup() { M5.begin(); Kernel_setup(); - PowerManagement_setup(); - + //Kernel_start(&PowerManagement, 1000); + Kernel_start(&UserInput, 0); Kernel_start(&test_func, 1000); } void loop() { + M5.update(); Kernel_tick(); - PowerManagement_tick(); }