Adam PIppin
3 years ago
20 changed files with 955 additions and 23 deletions
@ -0,0 +1,79 @@ |
|||
#include "watchos.h" |
|||
#include "Module_Input.h" |
|||
|
|||
struct InputButtonState |
|||
{ |
|||
byte button; |
|||
byte pin; |
|||
uint64_t mask; |
|||
bool pressed = false; |
|||
}; |
|||
|
|||
uint64_t wakeup_bits; |
|||
|
|||
Module_Input::Module_Input() |
|||
{ |
|||
for (int i = 0; i < MODULE_INPUT_BUTTONS; i++) |
|||
{ |
|||
m_button[i] = new InputButtonState(); |
|||
} |
|||
|
|||
m_button[0]->button = WATCHOS_BUTTON_BACK; |
|||
m_button[0]->pin = HW_BUTTON_TL; |
|||
m_button[0]->mask = HW_BUTTON_TL_MASK; |
|||
|
|||
m_button[1]->button = WATCHOS_BUTTON_OK; |
|||
m_button[1]->pin = HW_BUTTON_BL; |
|||
m_button[1]->mask = HW_BUTTON_BL_MASK; |
|||
|
|||
m_button[2]->button = WATCHOS_BUTTON_UP; |
|||
m_button[2]->pin = HW_BUTTON_TR; |
|||
m_button[2]->mask = HW_BUTTON_TR_MASK; |
|||
|
|||
m_button[3]->button = WATCHOS_BUTTON_DOWN; |
|||
m_button[3]->pin = HW_BUTTON_BR; |
|||
m_button[3]->mask = HW_BUTTON_BR_MASK; |
|||
} |
|||
|
|||
void Module_Input::start() |
|||
{ |
|||
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::tick() |
|||
{ |
|||
byte pressed = 0; |
|||
|
|||
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) |
|||
{ |
|||
watchos::debug("Button pressed: %d", i); |
|||
pressed |= m_button[i]->button; |
|||
m_button[i]->pressed = true; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (m_button[i]->pressed) |
|||
watchos::debug("Button released!"); |
|||
m_button[i]->pressed = false; |
|||
} |
|||
} |
|||
|
|||
if (pressed != 0) |
|||
{ |
|||
watchos::kernel()->pushEvent(WATCHOS_MODULE_INPUT, WATCHOS_EVENT_TYPE_INPUT_PRESSED, pressed, 0); |
|||
} |
|||
|
|||
wakeup_bits = 0; |
|||
} |
@ -0,0 +1,19 @@ |
|||
#ifndef _MODULE_INPUT_h |
|||
#define _MODULE_INPUT_h |
|||
|
|||
#define MODULE_INPUT_BUTTONS 4 |
|||
|
|||
struct InputButtonState; |
|||
|
|||
class Module_Input : public Task, public IRunnable |
|||
{ |
|||
InputButtonState* m_button[MODULE_INPUT_BUTTONS]; |
|||
|
|||
public: |
|||
Module_Input(); |
|||
void start(); |
|||
void tick(); |
|||
}; |
|||
|
|||
|
|||
#endif |
@ -0,0 +1,129 @@ |
|||
#include "watchos.h" |
|||
#include "Module_Power.h" |
|||
|
|||
void Module_Power::start() |
|||
{ |
|||
// TODO: Fetch input module to poll for button presses
|
|||
|
|||
m_last_tick = 0; |
|||
m_light_sleep_accumulator = 0; |
|||
m_deep_sleep_accumulator = 0; |
|||
m_did_light_sleep = false; |
|||
|
|||
switch (esp_sleep_get_wakeup_cause()) |
|||
{ |
|||
// Interactive
|
|||
case ESP_SLEEP_WAKEUP_EXT1: // Button press
|
|||
m_light_sleep_delay = MODULE_POWER_INTERACTIVE_LIGHT_SLEEP_DELAY_MS; |
|||
m_deep_sleep_delay = MODULE_POWER_INTERACTIVE_DEEP_SLEEP_DELAY_MS; |
|||
break; |
|||
// Non-interactive
|
|||
case ESP_SLEEP_WAKEUP_EXT0: // External RTC
|
|||
case ESP_SLEEP_WAKEUP_TIMER: // Internal RTC
|
|||
default: // Reset or something else
|
|||
m_light_sleep_delay = MODULE_POWER_NONINTERACTIVE_LIGHT_SLEEP_DELAY_MS; |
|||
m_deep_sleep_delay = MODULE_POWER_NONINTERACTIVE_DEEP_SLEEP_DELAY_MS; |
|||
break; |
|||
} |
|||
|
|||
watchos::subscribe(this, WATCHOS_MODULE_INPUT, WATCHOS_EVENT_TYPE_INPUT_PRESSED); |
|||
} |
|||
|
|||
void Module_Power::tick() |
|||
{ |
|||
if (m_last_tick == 0) |
|||
{ |
|||
m_last_tick = millis(); |
|||
} |
|||
else |
|||
{ |
|||
if (m_light_sleep_enabled) |
|||
{ |
|||
m_light_sleep_accumulator += millis() - m_last_tick; |
|||
} |
|||
if (m_deep_sleep_enabled) |
|||
{ |
|||
m_deep_sleep_accumulator += millis() - m_last_tick; |
|||
} |
|||
} |
|||
|
|||
m_last_tick = millis(); |
|||
|
|||
Event* e; |
|||
while (this->hasEvent()) |
|||
{ |
|||
e = this->getEvent(); |
|||
|
|||
if (e->source == WATCHOS_MODULE_INPUT && e->event == WATCHOS_EVENT_TYPE_INPUT_PRESSED) |
|||
{ |
|||
watchos::debug("Resetting accumulators"); |
|||
m_light_sleep_delay = MODULE_POWER_INTERACTIVE_LIGHT_SLEEP_DELAY_MS; |
|||
m_deep_sleep_delay = MODULE_POWER_INTERACTIVE_DEEP_SLEEP_DELAY_MS; |
|||
m_light_sleep_accumulator = 0; |
|||
m_deep_sleep_accumulator = 0; |
|||
} |
|||
|
|||
this->popEvent(); |
|||
} |
|||
|
|||
if (m_deep_sleep_accumulator > m_deep_sleep_delay) |
|||
{ |
|||
watchos::debug("Going into deep sleep"); |
|||
//watchos::debug("Power: light %d/%d; heavy %d/%d", m_light_sleep_accumulator, m_light_sleep_delay, m_deep_sleep_accumulator, m_deep_sleep_delay);
|
|||
|
|||
watchos::kernel()->suspend(); |
|||
|
|||
// TODO: Configure a... hourly? alarm to wake up and refresh other things.
|
|||
// Interrogate tasks for next requested wakeup?
|
|||
if (m_did_light_sleep) |
|||
{ |
|||
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); |
|||
// Turn off RTC -- needs to be on to handle ext0/ext1 interrupts properly I guess
|
|||
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
|
|||
// Turn off RTC fast mem
|
|||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF); |
|||
// Keep RTC slow ram on explicitly
|
|||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); |
|||
esp_deep_sleep_start(); |
|||
} |
|||
else if (m_light_sleep_accumulator > m_light_sleep_delay) |
|||
{ |
|||
//watchos::debug("Going into light sleep");
|
|||
//watchos::debug("Power: light %d/%d; heavy %d/%d", m_light_sleep_accumulator, m_light_sleep_delay, m_deep_sleep_accumulator, m_deep_sleep_delay);
|
|||
m_did_light_sleep = true; |
|||
// If nothing else happens, wake up when it's time to hibernate.
|
|||
esp_sleep_enable_timer_wakeup((m_deep_sleep_delay - m_deep_sleep_accumulator) * 1000); |
|||
// Wake up if the RTC fires
|
|||
esp_sleep_enable_ext0_wakeup(HW_RTC, 0); |
|||
// Wake up if any button is pressed
|
|||
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!
|
|||
m_light_sleep_accumulator = 0; |
|||
} |
|||
} |
|||
|
|||
void Module_Power::disableLightSleep() |
|||
{ |
|||
m_light_sleep_enabled = false; |
|||
} |
|||
|
|||
void Module_Power::enableLightSleep() |
|||
{ |
|||
m_light_sleep_enabled = true; |
|||
} |
|||
|
|||
void Module_Power::disableDeepSleep() |
|||
{ |
|||
m_deep_sleep_enabled = false; |
|||
} |
|||
|
|||
void Module_Power::enableDeepSleep() |
|||
{ |
|||
m_deep_sleep_enabled = true; |
|||
} |
@ -0,0 +1,37 @@ |
|||
#ifndef _MODULE_POWER_h |
|||
#define _MODULE_POWER_h |
|||
|
|||
#include <Arduino.h> |
|||
#include "watchos_consts.h" |
|||
//#include "watchos_hw.h"
|
|||
//#include "watchos_types.h"
|
|||
#include "EventListener.h" |
|||
|
|||
#define MODULE_POWER_INTERACTIVE_LIGHT_SLEEP_DELAY_MS 200 |
|||
#define MODULE_POWER_INTERACTIVE_DEEP_SLEEP_DELAY_MS 3000 |
|||
|
|||
#define MODULE_POWER_NONINTERACTIVE_LIGHT_SLEEP_DELAY_MS 200 |
|||
#define MODULE_POWER_NONINTERACTIVE_DEEP_SLEEP_DELAY_MS 500 |
|||
|
|||
class Module_Power : public Task, public IRunnable, public EventListener |
|||
{ |
|||
int m_light_sleep_delay = 0, m_deep_sleep_delay = 0; |
|||
int m_light_sleep_accumulator = 0, m_deep_sleep_accumulator = 0; |
|||
|
|||
unsigned long m_last_tick; |
|||
bool m_did_light_sleep; |
|||
|
|||
bool m_light_sleep_enabled = true, m_deep_sleep_enabled = true; |
|||
|
|||
public: |
|||
void start(); |
|||
void tick(); |
|||
|
|||
void disableLightSleep(); |
|||
void enableLightSleep(); |
|||
void disableDeepSleep(); |
|||
void enableDeepSleep(); |
|||
|
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,102 @@ |
|||
#include "watchos.h" |
|||
#include "Module_RTC.h" |
|||
|
|||
#include <DS3232RTC.h> |
|||
// https://github.com/JChristensen/DS3232RTC
|
|||
|
|||
DS3232RTC RTC; |
|||
tmElements_t rtc_time; |
|||
|
|||
|
|||
Module_RTC::Module_RTC() |
|||
{ |
|||
RTC.squareWave(SQWAVE_NONE); |
|||
RTC.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 0); |
|||
RTC.alarmInterrupt(ALARM_2, true); |
|||
RTC.alarmInterrupt(ALARM_1, false); |
|||
refresh(); |
|||
} |
|||
|
|||
void Module_RTC::initialize() |
|||
{ |
|||
} |
|||
|
|||
void Module_RTC::start() |
|||
{ |
|||
} |
|||
|
|||
void Module_RTC::suspend() |
|||
{ |
|||
} |
|||
|
|||
void Module_RTC::refresh() |
|||
{ |
|||
byte read_result = RTC.read(rtc_time); |
|||
} |
|||
|
|||
void Module_RTC::tick() |
|||
{ |
|||
if (RTC.alarm(ALARM_2)) |
|||
{ |
|||
refresh(); |
|||
watchos::kernel()->pushEvent(WATCHOS_MODULE_RTC, WATCHOS_EVENT_TYPE_RTC_MINUTE, rtc_time.Hour, rtc_time.Minute); |
|||
watchos::debug("New time: %d:%d", rtc_time.Hour, rtc_time.Minute); |
|||
} |
|||
if (RTC.alarm(ALARM_1)) |
|||
{ |
|||
watchos::debug("Alarm 1 fired?"); |
|||
} |
|||
} |
|||
|
|||
int Module_RTC::getHour() |
|||
{ |
|||
return rtc_time.Hour; |
|||
} |
|||
|
|||
int Module_RTC::getMinute() |
|||
{ |
|||
return rtc_time.Minute; |
|||
} |
|||
|
|||
int Module_RTC::getSecond() |
|||
{ |
|||
return rtc_time.Second; |
|||
} |
|||
|
|||
int Module_RTC::getYear() |
|||
{ |
|||
return rtc_time.Year; |
|||
} |
|||
|
|||
int Module_RTC::getMonth() |
|||
{ |
|||
return rtc_time.Month; |
|||
} |
|||
|
|||
int Module_RTC::getDay() |
|||
{ |
|||
return rtc_time.Day; |
|||
} |
|||
|
|||
char* Module_RTC::getDayOfWeek() |
|||
{ |
|||
switch (rtc_time.Wday) |
|||
{ |
|||
case 1: |
|||
return "Sunday"; |
|||
case 2: |
|||
return "Monday"; |
|||
case 3: |
|||
return "Tuesday"; |
|||
case 4: |
|||
return "Wednesday"; |
|||
case 5: |
|||
return "Thursday"; |
|||
case 6: |
|||
return "Friday"; |
|||
case 7: |
|||
return "Saturday"; |
|||
default: |
|||
return "Unknown"; |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
#ifndef _MODULE_RTC_h |
|||
#define _MODULE_RTC_h |
|||
|
|||
#include "watchos_consts.h" |
|||
#include "watchos_types.h" |
|||
|
|||
#include "Task.h" |
|||
#include "IRunnable.h" |
|||
|
|||
class Module_RTC : public Task, public IRunnable |
|||
{ |
|||
void refresh(); |
|||
|
|||
public: |
|||
Module_RTC(); |
|||
void initialize(); |
|||
void start(); |
|||
void suspend(); |
|||
void tick(); |
|||
|
|||
int getHour(); |
|||
int getMinute(); |
|||
int getSecond(); |
|||
int getYear(); |
|||
int getMonth(); |
|||
int getDay(); |
|||
char* getDayOfWeek(); |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,219 @@ |
|||
#include <EEPROM.h> |
|||
|
|||
#include "watchos.h" |
|||
#include "Module_Storage.h" |
|||
|
|||
// TODO: Make tiered storage. Smaller allocations can go to RTC RAM.
|
|||
|
|||
struct StorageEntry |
|||
{ |
|||
byte module; |
|||
uint16_t length; |
|||
byte options; |
|||
}; |
|||
|
|||
#define MODULE_STORAGE_SIZE 3524 |
|||
#define MODULE_STORAGE_HEADER_SIZE 4 |
|||
#define MODULE_STORAGE_ENTRY_SIZE 4 |
|||
|
|||
#define MODULE_STORAGE_MAGIC 0x6580 |
|||
#define MODULE_STORAGE_VERSION 0x00 |
|||
|
|||
RTC_NOINIT_ATTR byte RTC_MEM[MODULE_STORAGE_SIZE]; |
|||
|
|||
byte read_rtc(uint16_t offset); |
|||
void write_rtc(uint16_t offset, byte value); |
|||
|
|||
void Module_Storage::initialize() |
|||
{ |
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
m_entry[i] = nullptr; |
|||
} |
|||
} |
|||
|
|||
void Module_Storage::start() |
|||
{ |
|||
load(); |
|||
} |
|||
|
|||
void Module_Storage::suspend() |
|||
{ |
|||
commit(); |
|||
} |
|||
|
|||
bool Module_Storage::isValid() |
|||
{ |
|||
return ((read_rtc(0) << 8) | read_rtc(1)) == MODULE_STORAGE_MAGIC; |
|||
} |
|||
|
|||
void Module_Storage::load() |
|||
{ |
|||
// Read rtc ram to m_entry
|
|||
m_magic = (read_rtc(0) << 8) | read_rtc(1); |
|||
m_version = read_rtc(2); |
|||
m_options = read_rtc(3); |
|||
|
|||
if (m_magic != MODULE_STORAGE_MAGIC) |
|||
watchos::panic("Invalid magic in persistent data"); |
|||
if (m_version != MODULE_STORAGE_VERSION) |
|||
watchos::panic("Invalid version of persistent data"); |
|||
|
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
int offset = MODULE_STORAGE_HEADER_SIZE + (MODULE_STORAGE_ENTRY_SIZE * i); |
|||
byte module = read_rtc(offset + 0); |
|||
if (module == 0xFF) |
|||
continue; |
|||
|
|||
m_entry[i] = new StorageEntry(); |
|||
m_entry[i]->module = module; |
|||
m_entry[i]->length = (read_rtc(offset + 1) << 8) | read_rtc(offset + 2); |
|||
m_entry[i]->options = read_rtc(offset + 3); |
|||
} |
|||
} |
|||
|
|||
void Module_Storage::commit() |
|||
{ |
|||
// Sync allocations into RTC memory
|
|||
write_rtc(0, (byte)(m_magic >> 8)); |
|||
write_rtc(1, (byte)(m_magic)); |
|||
write_rtc(2, m_version); |
|||
write_rtc(3, m_options); |
|||
|
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
int offset = MODULE_STORAGE_HEADER_SIZE + (MODULE_STORAGE_ENTRY_SIZE * i); |
|||
if (m_entry[i] == nullptr) |
|||
{ |
|||
write_rtc(offset + 0, 0xFF); |
|||
} |
|||
else |
|||
{ |
|||
write_rtc(offset + 0, m_entry[i]->module); |
|||
write_rtc(offset + 1, (byte)(m_entry[i]->length >> 8)); |
|||
write_rtc(offset + 2, (byte)(m_entry[i]->length)); |
|||
write_rtc(offset + 3, m_entry[i]->options); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void Module_Storage::reset() |
|||
{ |
|||
m_magic = MODULE_STORAGE_MAGIC; |
|||
m_version = MODULE_STORAGE_VERSION; |
|||
m_options = 0; |
|||
|
|||
// Write out blank allocations
|
|||
write_rtc(0, (byte)(m_magic >> 8)); |
|||
write_rtc(1, (byte)(m_magic)); |
|||
write_rtc(2, m_version); |
|||
write_rtc(3, m_options); |
|||
|
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
if (m_entry[i] != nullptr) |
|||
{ |
|||
free(m_entry[i]); |
|||
m_entry[i] = nullptr; |
|||
} |
|||
|
|||
write_rtc(MODULE_STORAGE_HEADER_SIZE + (MODULE_STORAGE_ENTRY_SIZE * i), 0xFF); |
|||
} |
|||
} |
|||
|
|||
bool Module_Storage::allocate(byte module, uint16_t size, byte options) |
|||
{ |
|||
// Check if an allocation already exists
|
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
if (m_entry[i] != nullptr && m_entry[i]->module == module) |
|||
{ |
|||
if (m_entry[i]->length != size) |
|||
watchos::panic("Storage module does not support reallocating storage with a new size."); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// None exists, allocate
|
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
if (m_entry[i] == nullptr) |
|||
{ |
|||
m_entry[i] = new StorageEntry(); |
|||
m_entry[i]->module = module; |
|||
m_entry[i]->length = size; |
|||
m_entry[i]->options = options; |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
// None exists and we were unable to allocate one
|
|||
watchos::panic("Exceeded MODULE_STORAGE_MAX_ENTRIES"); |
|||
} |
|||
|
|||
void Module_Storage::write(byte module, uint16_t offset, byte value) |
|||
{ |
|||
// TODO: Check offset doesn't put us past the end of the allocation
|
|||
write_rtc(getOffset(module) + offset, value); |
|||
} |
|||
|
|||
byte Module_Storage::read(byte module, uint16_t offset) |
|||
{ |
|||
// TODO: Check offset doesn't put us past the end of the allocation
|
|||
return read_rtc(getOffset(module) + offset); |
|||
} |
|||
|
|||
bool Module_Storage::allocate(well_known_handle_t module, uint16_t size, byte options) |
|||
{ |
|||
return allocate(wellKnownHandleToByte(module), size); |
|||
} |
|||
|
|||
void Module_Storage::write(well_known_handle_t module, uint16_t offset, byte value) |
|||
{ |
|||
return write(wellKnownHandleToByte(module), offset, value); |
|||
} |
|||
|
|||
byte Module_Storage::read(well_known_handle_t module, uint16_t offset) |
|||
{ |
|||
return read(wellKnownHandleToByte(module), offset); |
|||
} |
|||
|
|||
byte Module_Storage::wellKnownHandleToByte(well_known_handle_t handle) |
|||
{ |
|||
byte count = 0; |
|||
for (;;) |
|||
{ |
|||
if (((handle >> count) & 1) == 1) |
|||
return count; |
|||
else |
|||
count++; |
|||
assert(count < 64); |
|||
} |
|||
} |
|||
|
|||
int Module_Storage::getOffset(byte module) |
|||
{ |
|||
int offset = MODULE_STORAGE_HEADER_SIZE + (MODULE_STORAGE_ENTRY_SIZE * MODULE_STORAGE_MAX_ENTRIES); |
|||
for (int i = 0; i < MODULE_STORAGE_MAX_ENTRIES; i++) |
|||
{ |
|||
if (m_entry[i] != nullptr) |
|||
{ |
|||
if (m_entry[i]->module == module) |
|||
return offset; |
|||
else |
|||
offset += m_entry[i]->length; |
|||
} |
|||
} |
|||
watchos::panic("Cannot get offset for module %d; not found", module); |
|||
} |
|||
|
|||
byte read_rtc(uint16_t offset) |
|||
{ |
|||
return RTC_MEM[offset]; |
|||
} |
|||
|
|||
void write_rtc(uint16_t offset, byte value) |
|||
{ |
|||
RTC_MEM[offset] = value; |
|||
} |
@ -0,0 +1,47 @@ |
|||
#ifndef _MODULE_STORAGE_h |
|||
#define _MODULE_STORAGE_h |
|||
|
|||
#include "watchos_consts.h" |
|||
#include "watchos_types.h" |
|||
|
|||
#include "Task.h" |
|||
|
|||
// 4kB RTC
|
|||
// 4kB EEPROM
|
|||
|
|||
#define MODULE_STORAGE_MAX_ENTRIES 16 |
|||
|
|||
struct StorageEntry; |
|||
|
|||
class Module_Storage : public Task |
|||
{ |
|||
uint16_t m_magic; |
|||
byte m_version; |
|||
byte m_options; |
|||
StorageEntry* m_entry[MODULE_STORAGE_MAX_ENTRIES]; |
|||
|
|||
byte wellKnownHandleToByte(well_known_handle_t handle); |
|||
int getOffset(byte module); |
|||
|
|||
public: |
|||
void initialize(); |
|||
void start(); |
|||
void suspend(); |
|||
|
|||
bool isValid(); |
|||
|
|||
void load(); |
|||
void commit(); |
|||
void reset(); |
|||
|
|||
bool allocate(well_known_handle_t module, uint16_t size, byte options = 0); |
|||
void write(well_known_handle_t module, uint16_t offset, byte value); |
|||
byte read(well_known_handle_t module, uint16_t offset); |
|||
|
|||
bool allocate(byte module, uint16_t size, byte options = 0); |
|||
void write(byte module, uint16_t offset, byte value); |
|||
byte read(byte module, uint16_t offset); |
|||
|
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,61 @@ |
|||
#include "watchos.h" |
|||
#include "Module_UI.h" |
|||
#include "Module_RTC.h" |
|||
|
|||
class Task_Clock : public IRunnable, public IDrawable, public Task, public EventListener |
|||
{ |
|||
Module_UI* ui = nullptr; |
|||
kernel_handle_t window_handle; |
|||
bool read_rtc = false; |
|||
byte hour, minute; |
|||
|
|||
public: |
|||
void start() |
|||
{ |
|||
watchos::subscribe(this, WATCHOS_MODULE_RTC, WATCHOS_EVENT_TYPE_RTC_MINUTE); |
|||
|
|||
ui = static_cast<Module_UI*>(watchos::module(WATCHOS_MODULE_UI)); |
|||
ui->setLayoutMode(ui->getRoot(), MODULE_UI_LAYOUT_MODE_SPLIT_HORIZONTAL); |
|||
|
|||
window_handle = ui->createWindow(this, ui->getRoot()); |
|||
ui->createWindow(ui->getRoot()); |
|||
} |
|||
void tick() |
|||
{ |
|||
Event* e; |
|||
while (this->hasEvent()) |
|||
{ |
|||
e = this->getEvent(); |
|||
|
|||
if (e->source == WATCHOS_MODULE_RTC && e->event == WATCHOS_EVENT_TYPE_RTC_MINUTE) |
|||
{ |
|||
if (!read_rtc || e->param1 != hour || e->param2 != minute) |
|||
{ |
|||
hour = e->param1; |
|||
minute = e->param2; |
|||
read_rtc = true; |
|||
ui->setDirty(window_handle); |
|||
} |
|||
} |
|||
|
|||
this->popEvent(); |
|||
} |
|||
} |
|||
void draw(kernel_handle_t handle) |
|||
{ |
|||
if (!read_rtc) |
|||
{ |
|||
Module_RTC* rtc = static_cast<Module_RTC*>(watchos::module(WATCHOS_MODULE_RTC)); |
|||
hour = rtc->getHour(); |
|||
minute = rtc->getMinute(); |
|||
read_rtc = true; |
|||
} |
|||
|
|||
char time[6]; |
|||
sprintf(time, "%02d:%02d", hour, minute); |
|||
|
|||
ui->fill(COLOUR_SECONDARY); |
|||
ui->print(0, ui->getHeight(), time, COLOUR_PRIMARY, 1); |
|||
} |
|||
|
|||
}; |
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