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