Browse Source

Move button press detection to kernel based off of wake event

Change process callback to pass in process's pid
master
Adam Pippin 4 years ago
parent
commit
771a68ea28
  1. 131
      Kernel.cpp
  2. 33
      Kernel.h
  3. 74
      PowerManagement.cpp
  4. 3
      PowerManagement.h
  5. 25
      UserInput.cpp
  6. 2
      UserInput.h
  7. 26
      watchos.ino

131
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; i<MAX_TASKS; i++)
{
if (tasks[i].pid != 0 && tasks[i].running == true)
{
tasks[i].signal |= signal;
}
}
}
void Kernel_signal(int pid, unsigned int signal)
{
struct Task *process = Kernel_get_task(pid);
if (process->pid == 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; i<MAX_TASKS; i++)
{
if (tasks[i].pid != 0 && tasks[i].running)
{
count++;
}
}
return count;
}
int Kernel_get_exit_code(int pid)
{
struct Task *process = Kernel_get_task(pid);
@ -91,6 +151,13 @@ bool Kernel_is_exited(int pid)
return process->pid != 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<MAX_TASKS; i++)
@ -124,25 +191,33 @@ void Kernel_tick()
// Make sure we found at least one active process, because if not we dead.
running_tasks++;
// 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)
// 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<MAX_TASKS; i++)
{
if (tasks[i].signal != SIGNAL_NONE)
{
signals_pending = true;
}
}
if (!signals_pending)
{
esp_sleep_enable_timer_wakeup(next_tick_due * 1000);
esp_sleep_enable_ext0_wakeup((gpio_num_t)37, LOW);
esp_sleep_enable_ext1_wakeup(0x8000000000, ESP_EXT1_WAKEUP_ALL_LOW);
esp_light_sleep_start();
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason){
case ESP_SLEEP_WAKEUP_TIMER : break;
case ESP_SLEEP_WAKEUP_EXT0 : inputs[0] = true; break;
case ESP_SLEEP_WAKEUP_EXT1 : inputs[1] = true; break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : break;
case ESP_SLEEP_WAKEUP_ULP : break;
case ESP_SLEEP_WAKEUP_GPIO : break;
case ESP_SLEEP_WAKEUP_UART : break;
default : break;
}
}
}

33
Kernel.h

@ -4,7 +4,7 @@ struct Task
int pid = 0;
bool running = false;
int exit_code = 0;
int (*callback)(unsigned int);
int (*callback)(int, unsigned int);
unsigned long run_interval = 0;
unsigned long run_accumulator = 0;
unsigned int signal = 0;
@ -18,7 +18,7 @@ void Kernel_tick();
void Kernel_panic(char* message);
// Start a new process
void Kernel_start(int (*callback)(unsigned int), unsigned long interval);
void Kernel_start(int (*callback)(int, unsigned int), unsigned long interval);
// Continue execution of a process
void Kernel_enable(int pid);
// Pause execution of a process
@ -26,12 +26,33 @@ void Kernel_disable(int pid);
// Clean up exited process
void Kernel_reap(int pid);
// Send a signal to a/all processes
void Kernel_signal(int pid, unsigned int signal);
void Kernel_signal(unsigned int signal);
// Set a tasks's signal mask
void Kernel_signal_mask(int pid, unsigned int signal_mask);
// Get the run interval of a process
unsigned long Kernel_get_run_interval(int pid);
// Count how many tasks are running
int Kernel_count_running_tasks();
// 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
// Check if a button was pressed
bool Kernel_read_input(int input);
#define SIGNAL_NONE 0x0000
#define SIGNAL_TICK 0x0001
#define SIGNAL_START 0x0002
#define SIGNAL_STOP 0x0004
#define SIGNAL_INPUT_A 0x0008
#define SIGNAL_INPUT_B 0x0010
#define KERNEL_INPUT_BUTTON_A 0
#define KERNEL_INPUT_BUTTON_B 1

74
PowerManagement.cpp

@ -1,10 +1,78 @@
#include <M5StickC.h>
#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;
}

3
PowerManagement.h

@ -1,3 +1,2 @@
void PowerManagement_setup();
void PowerManagement_tick();
int PowerManagement(int pid, unsigned int signal);

25
UserInput.cpp

@ -0,0 +1,25 @@
#include <M5StickC.h>
#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;
}

2
UserInput.h

@ -0,0 +1,2 @@
int UserInput(int pid, unsigned int signal);

26
watchos.ino

@ -1,10 +1,12 @@
#include <M5StickC.h>
#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();
}

Loading…
Cancel
Save