Adam PIppin
3 years ago
20 changed files with 638 additions and 89 deletions
@ -0,0 +1,111 @@ |
|||
#include "watchos.h" |
|||
#include "watchos_hw.h" |
|||
#include "Module_Input.h" |
|||
|
|||
struct ButtonState |
|||
{ |
|||
byte button; |
|||
byte pin; |
|||
uint64_t mask; |
|||
bool pressed = false; |
|||
byte reserved1; |
|||
}; |
|||
|
|||
uint64_t wakeup_bits; |
|||
|
|||
Module_Input::Module_Input() |
|||
{ |
|||
for (int i = 0; i < MODULE_INPUT_BUTTONS; i++) |
|||
{ |
|||
m_button[i] = new ButtonState(); |
|||
} |
|||
|
|||
// TODO: Figure out a way to not hardcode this
|
|||
m_button[0]->button = MODULE_INPUT_BUTTON_BACK; |
|||
m_button[0]->pin = HW_BUTTON_TL; |
|||
m_button[0]->mask = HW_BUTTON_TL_MASK; |
|||
m_button[1]->button = MODULE_INPUT_BUTTON_MENU; |
|||
m_button[1]->pin = HW_BUTTON_BL; |
|||
m_button[1]->mask = HW_BUTTON_BL_MASK; |
|||
m_button[2]->button = MODULE_INPUT_BUTTON_UP; |
|||
m_button[2]->pin = HW_BUTTON_TR; |
|||
m_button[2]->mask = HW_BUTTON_TR_MASK; |
|||
m_button[3]->button = MODULE_INPUT_BUTTON_DOWN; |
|||
m_button[3]->pin = HW_BUTTON_BR; |
|||
m_button[3]->mask = HW_BUTTON_BR_MASK; |
|||
|
|||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT1) |
|||
{ |
|||
wakeup_bits = esp_sleep_get_ext1_wakeup_status(); |
|||
} |
|||
else |
|||
{ |
|||
wakeup_bits = 0; |
|||
} |
|||
} |
|||
|
|||
void Module_Input::initialize() |
|||
{ |
|||
|
|||
} |
|||
|
|||
void Module_Input::suspend() |
|||
{ |
|||
} |
|||
|
|||
int Module_Input::getId() |
|||
{ |
|||
return MODULE_INPUT; |
|||
} |
|||
|
|||
void Module_Input::tick() |
|||
{ |
|||
poll(); |
|||
wakeup_bits = 0; |
|||
} |
|||
|
|||
void Module_Input::poll() |
|||
{ |
|||
byte pressed = 0; |
|||
char msg[255]; |
|||
|
|||
for (int i = 0; i < MODULE_INPUT_BUTTONS; i++) |
|||
{ |
|||
if (digitalRead(m_button[i]->pin) == 1 || (wakeup_bits & m_button[i]->mask) != 0) |
|||
{ |
|||
if (!m_button[i]->pressed) |
|||
{ |
|||
sprintf(msg, "Button pressed: %d", i); |
|||
Kernel::debug(msg); |
|||
pressed |= m_button[i]->button; |
|||
m_button[i]->pressed = true; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
m_button[i]->pressed = false; |
|||
} |
|||
} |
|||
|
|||
if (pressed != 0) |
|||
{ |
|||
Kernel::get()->event(MODULE_INPUT, MODULE_INPUT_EVENT_PRESS, pressed, 0); |
|||
} |
|||
} |
|||
|
|||
bool Module_Input::isAnyPressed() |
|||
{ |
|||
for (int i = 0; i < MODULE_INPUT_BUTTONS; i++) |
|||
{ |
|||
if (m_button[i]->pressed) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool Module_Input::isPressed(byte button) |
|||
{ |
|||
return m_button[button]->pressed; |
|||
} |
@ -0,0 +1,25 @@ |
|||
#ifndef MODULE_INPUT_H |
|||
#define MODULE_INPUT_H |
|||
|
|||
#include "watchos.h" |
|||
|
|||
struct ButtonState; |
|||
|
|||
class Module_Input : public Module |
|||
{ |
|||
ButtonState* m_button[MODULE_INPUT_BUTTONS]; |
|||
|
|||
void poll(); |
|||
|
|||
public: |
|||
Module_Input(); |
|||
void initialize(); |
|||
void suspend(); |
|||
int getId(); |
|||
void tick(); |
|||
|
|||
bool isAnyPressed(); |
|||
bool isPressed(byte button); |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,102 @@ |
|||
#include "watchos_hw.h" |
|||
#include "Module_Power.h" |
|||
#include "Module_Input.h" |
|||
#include "Events.h" |
|||
|
|||
Module_Input* module_input; |
|||
|
|||
Module_Power::Module_Power() |
|||
{ |
|||
module_input = (Module_Input*)Kernel::get()->getModule(MODULE_INPUT); |
|||
m_last_tick = 0; |
|||
m_accumulator = 0; |
|||
|
|||
switch (esp_sleep_get_wakeup_cause()) |
|||
{ |
|||
case ESP_SLEEP_WAKEUP_EXT1: // Button press
|
|||
// Button press
|
|||
m_light_sleep_delay = 2000; |
|||
m_deep_sleep_delay = 5000; |
|||
break; |
|||
case ESP_SLEEP_WAKEUP_EXT0: // External RTC
|
|||
case ESP_SLEEP_WAKEUP_TIMER: // Internal RTC
|
|||
default: |
|||
m_light_sleep_delay = 100; |
|||
m_deep_sleep_delay = 1000; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void Module_Power::initialize() |
|||
{ |
|||
} |
|||
|
|||
void Module_Power::suspend() |
|||
{ |
|||
} |
|||
|
|||
int Module_Power::getId() |
|||
{ |
|||
return MODULE_POWER; |
|||
} |
|||
|
|||
void Module_Power::disableSleep() |
|||
{ |
|||
m_sleep_enabled = false; |
|||
} |
|||
|
|||
void Module_Power::enableSleep() |
|||
{ |
|||
m_sleep_enabled = true; |
|||
} |
|||
|
|||
void Module_Power::tick() |
|||
{ |
|||
if (m_last_tick == 0) |
|||
{ |
|||
m_accumulator = 0; |
|||
} |
|||
else if (m_sleep_enabled) |
|||
{ |
|||
m_accumulator += millis() - m_last_tick; |
|||
} |
|||
m_last_tick = millis(); |
|||
|
|||
if (module_input->isAnyPressed()) |
|||
{ |
|||
// In case we woke up because of RTC/etc, but have since received a button press
|
|||
m_light_sleep_delay = 2000; |
|||
m_deep_sleep_delay = 5000; |
|||
m_accumulator = 0; |
|||
} |
|||
|
|||
if (m_accumulator > m_deep_sleep_delay) |
|||
{ |
|||
Kernel::debug("Going into deep sleep"); |
|||
m_accumulator = 0; |
|||
|
|||
Kernel::get()->suspend(); |
|||
|
|||
// TODO: Configure a... hourly? alarm to wake up and refresh other things
|
|||
// Interrogate tasks for next required wakeup?
|
|||
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); |
|||
esp_sleep_enable_ext0_wakeup(HW_RTC, 0); |
|||
esp_sleep_enable_ext1_wakeup(HW_BUTTON_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); |
|||
esp_deep_sleep_start(); |
|||
} |
|||
else if (m_accumulator > m_light_sleep_delay) |
|||
{ |
|||
Kernel::debug("Going into light sleep"); |
|||
|
|||
// If nothing else happens, wake up when it's time to hibernate.
|
|||
esp_sleep_enable_timer_wakeup((m_deep_sleep_delay * 1000) - m_accumulator); |
|||
// Wake up if the RTC fires
|
|||
esp_sleep_enable_ext0_wakeup(HW_RTC, 0); |
|||
// Wake up if any button presses
|
|||
esp_sleep_enable_ext1_wakeup(HW_BUTTON_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); |
|||
// Go into light sleep
|
|||
esp_light_sleep_start(); |
|||
|
|||
// And we're back, let everything continue
|
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
#ifndef MODULE_POWER_H |
|||
#define MODULE_POWER_H |
|||
|
|||
#include "watchos.h" |
|||
|
|||
class Module_Power : public Module |
|||
{ |
|||
int m_light_sleep_delay = 0; |
|||
int m_deep_sleep_delay = 0; |
|||
int m_accumulator = 0; |
|||
unsigned long m_last_tick; |
|||
bool m_sleep_enabled = true; |
|||
|
|||
public: |
|||
Module_Power(); |
|||
void initialize(); |
|||
void suspend(); |
|||
int getId(); |
|||
void tick(); |
|||
void disableSleep(); |
|||
void enableSleep(); |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,63 @@ |
|||
#include "watchos.h" |
|||
#include "watchos_hw.h" |
|||
#include "Module_UI.h" |
|||
#include "watchos_fonts.h" |
|||
#include "Events.h" |
|||
|
|||
class Task_Battery : public Task |
|||
{ |
|||
private: |
|||
int hwnd; |
|||
Module_UI* ui; |
|||
int voltage = 0; |
|||
int last_update; |
|||
|
|||
int getBatteryVoltage() |
|||
{ |
|||
float raw_value = (analogRead(HW_BATTERY_ADC_PIN) / 4096.0 * 7.23); |
|||
return (int)round(raw_value * 10); |
|||
} |
|||
|
|||
public: |
|||
Task_Battery(int parent_hwnd) |
|||
{ |
|||
ui = (Module_UI*)Kernel::get()->getModule(MODULE_UI); |
|||
hwnd = ui->createWindow((Task*)this, parent_hwnd, 0); |
|||
voltage = getBatteryVoltage(); |
|||
} |
|||
|
|||
void initialize() |
|||
{ |
|||
ui->setDirty(hwnd); |
|||
} |
|||
|
|||
void tick(unsigned int signal) |
|||
{ |
|||
|
|||
while (this->hasEvent()) { this->popEvent(); } |
|||
int new_voltage = getBatteryVoltage(); |
|||
if (voltage != new_voltage && (millis() - last_update > 1000)) |
|||
{ |
|||
last_update = millis(); |
|||
ui->setDirty(hwnd); |
|||
voltage = new_voltage; |
|||
} |
|||
} |
|||
|
|||
void suspend() |
|||
{ |
|||
} |
|||
|
|||
void draw(int hwnd, int x, int y, int width, int height) |
|||
{ |
|||
char str[8]; |
|||
float voltage_display = ((float)voltage) / 10.0f; |
|||
sprintf(str, "%.1fv", voltage_display); |
|||
Module_UI* ui = (Module_UI*)Kernel::get()->getModule(MODULE_UI); |
|||
ui->getGfx()->fillRect(x, y, width, height, COLOUR_SECONDARY); |
|||
ui->getGfx()->setFont(&FreeMono12pt7b); |
|||
ui->getGfx()->setTextColor(COLOUR_PRIMARY); |
|||
ui->getGfx()->setCursor(x, y + height); |
|||
ui->getGfx()->print(str); |
|||
} |
|||
}; |
@ -0,0 +1,75 @@ |
|||
#include "watchos.h" |
|||
#include "Module_UI.h" |
|||
#include "Module_EAT.h" |
|||
#include "watchos_fonts.h" |
|||
#include "Events.h" |
|||
|
|||
class Task_Counter : public Task |
|||
{ |
|||
private: |
|||
int hwnd; |
|||
Module_UI* ui; |
|||
Module_EAT* eat; |
|||
int count = 0; |
|||
|
|||
public: |
|||
Task_Counter(int parent_hwnd) |
|||
{ |
|||
ui = (Module_UI*)Kernel::get()->getModule(MODULE_UI); |
|||
hwnd = ui->createWindow((Task*)this, parent_hwnd, 0); |
|||
|
|||
eat = (Module_EAT*)Kernel::get()->getModule(MODULE_EAT); |
|||
if (!eat->allocate(3, 4)) |
|||
{ |
|||
// Read count
|
|||
count = (eat->read(3, 0) << 24) | (eat->read(3, 1) << 16) | (eat->read(3, 2) << 8) | eat->read(3, 3); |
|||
} |
|||
} |
|||
|
|||
void initialize() |
|||
{ |
|||
ui->setDirty(hwnd); |
|||
} |
|||
|
|||
void tick(unsigned int signal) |
|||
{ |
|||
bool dirty = false; |
|||
while (this->hasEvent()) |
|||
{ |
|||
Event* e = this->popEvent(); |
|||
|
|||
if (e->source == MODULE_INPUT && e->event == MODULE_INPUT_EVENT_PRESS) |
|||
{ |
|||
count++; |
|||
dirty = true; |
|||
} |
|||
} |
|||
|
|||
if (dirty) |
|||
{ |
|||
Module_UI* ui = (Module_UI*)Kernel::get()->getModule(MODULE_UI); |
|||
ui->setDirty(hwnd); |
|||
} |
|||
} |
|||
|
|||
void suspend() |
|||
{ |
|||
eat->write(3, 0, (byte)(count >> 24)); |
|||
eat->write(3, 1, (byte)(count >> 16)); |
|||
eat->write(3, 2, (byte)(count >> 8)); |
|||
eat->write(3, 3, (byte)count); |
|||
} |
|||
|
|||
void draw(int hwnd, int x, int y, int width, int height) |
|||
{ |
|||
char str[5]; |
|||
sprintf(str, "%04d", count); |
|||
|
|||
Module_UI* ui = (Module_UI*)Kernel::get()->getModule(MODULE_UI); |
|||
ui->getGfx()->fillRect(x, y, width, height, COLOUR_SECONDARY); |
|||
ui->getGfx()->setFont(&FreeMono12pt7b); |
|||
ui->getGfx()->setTextColor(COLOUR_PRIMARY); |
|||
ui->getGfx()->setCursor(x, y + height); |
|||
ui->getGfx()->print(str); |
|||
} |
|||
}; |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue