Browse Source

Updates to UI, general cleanup, add input/power/rtc/storage modules and

basic clock task
master
Adam PIppin 3 years ago
parent
commit
97826b1537
  1. 33
      watchos2/Kernel.cpp
  2. 4
      watchos2/Kernel.h
  3. 79
      watchos2/Module_Input.cpp
  4. 19
      watchos2/Module_Input.h
  5. 129
      watchos2/Module_Power.cpp
  6. 37
      watchos2/Module_Power.h
  7. 102
      watchos2/Module_RTC.cpp
  8. 30
      watchos2/Module_RTC.h
  9. 219
      watchos2/Module_Storage.cpp
  10. 47
      watchos2/Module_Storage.h
  11. 67
      watchos2/Module_UI.cpp
  12. 13
      watchos2/Module_UI.h
  13. 61
      watchos2/Task_Clock.cpp
  14. 43
      watchos2/Task_Test.cpp
  15. 2
      watchos2/__vm/Compile.vmps.xml
  16. 2
      watchos2/__vm/Upload.vmps.xml
  17. 30
      watchos2/watchos.cpp
  18. 3
      watchos2/watchos.h
  19. 33
      watchos2/watchos2.ino
  20. 25
      watchos2/watchos_consts.h

33
watchos2/Kernel.cpp

@ -191,6 +191,39 @@ void Kernel::unregisterTask(Task* task)
}
}
void Kernel::initialize()
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr)
{
m_task[i]->task->initialize();
}
}
}
void Kernel::start()
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr)
{
m_task[i]->task->start();
}
}
}
void Kernel::suspend()
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] != nullptr)
{
m_task[i]->task->suspend();
}
}
}
void Kernel::pushEvent(well_known_handle_t source, uint16_t event, byte param1, byte param2)
{
Event* e = new Event();

4
watchos2/Kernel.h

@ -27,6 +27,10 @@ private:
public:
Kernel();
void initialize();
void start();
void suspend();
/// <summary>
/// Create a new kernel handle pointing to an object
/// </summary>

79
watchos2/Module_Input.cpp

@ -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;
}

19
watchos2/Module_Input.h

@ -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

129
watchos2/Module_Power.cpp

@ -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;
}

37
watchos2/Module_Power.h

@ -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

102
watchos2/Module_RTC.cpp

@ -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";
}
}

30
watchos2/Module_RTC.h

@ -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

219
watchos2/Module_Storage.cpp

@ -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;
}

47
watchos2/Module_Storage.h

@ -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

67
watchos2/Module_UI.cpp

@ -1,7 +1,7 @@
#include "watchos.h"
#include "Module_UI.h"
#include "Module_Power.h"
#include <GxEPD2_BW.h>
#include <Fonts/FreeMono12pt7b.h>
GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> gfx = GxEPD2_154_D67(HW_DISPLAY_CS, HW_DISPLAY_DC, HW_DISPLAY_RESET, HW_DISPLAY_BUSY);
@ -14,6 +14,12 @@ struct UiWindow
bool dirty;
};
struct UiFont
{
byte id;
GFXfont* font;
};
void destruct_window(kernel_handle_t handle, void* object)
{
}
@ -30,6 +36,20 @@ void draw_wrapper(void* parameter)
#endif
Module_UI::Module_UI()
{
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++)
m_window[i] = nullptr;
for (int i = 0; i < MODULE_UI_MAX_FONTS; i++)
m_font[i] = nullptr;
}
void Module_UI::initialize()
{
m_dirty = true;
m_redraw = true;
}
void Module_UI::start()
{
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++)
{
@ -37,8 +57,8 @@ Module_UI::Module_UI()
}
m_root = createWindow(WATCHOS_HANDLE_NULL);
m_dirty = true;
m_redraw = true;
module_power = static_cast<Module_Power*>(watchos::module(WATCHOS_MODULE_POWER));
}
void Module_UI::tick()
@ -123,7 +143,8 @@ void Module_UI::draw()
void Module_UI::do_draw()
{
watchos::debug("Draw!");
// TODO: Disable light/deep sleep
module_power->disableLightSleep();
module_power->disableDeepSleep();
// Initialize gfx if necessary
if (!m_initialized)
@ -149,7 +170,8 @@ void Module_UI::do_draw()
gfx.display(!m_redraw);
m_redraw = false;
// TODO: Reenable sleep
module_power->enableDeepSleep();
module_power->enableLightSleep();
}
void Module_UI::draw_window(UiWindow* window, int x, int y, int width, int height)
@ -275,15 +297,21 @@ void Module_UI::print(int x, int y, char* str, uint16_t colour, void* font)
local_to_screen(&x, &y);
gfx.setCursor(x, y);
gfx.setTextColor(colour);
if (font == nullptr)
{
gfx.setFont(&FreeMono12pt7b);
}
else
gfx.setFont(static_cast<GFXfont*>(font));
gfx.print(str);
}
void Module_UI::print(int x, int y, char* str, uint16_t colour, byte font_id)
{
for (int i = 0; i < MODULE_UI_MAX_FONTS; i++)
{
gfx.setFont(static_cast<GFXfont*>(font));
if (m_font[i] != nullptr && m_font[i]->id == font_id)
{
print(x, y, str, colour, m_font[i]->font);
return;
}
}
gfx.print(str);
watchos::panic("Unknown font id: %d", font_id);
}
void Module_UI::local_to_screen(int* x, int* y)
@ -298,4 +326,19 @@ void Module_UI::local_to_screen(int* x, int* y)
*y = (m_draw_h - *y) + m_draw_y;
else
*y = m_draw_y + *y;
}
void Module_UI::registerFont(byte id, const void* font)
{
for (int i = 0; i < MODULE_UI_MAX_FONTS; i++)
{
if (m_font[i] == nullptr)
{
m_font[i] = new UiFont();
m_font[i]->id = id;
m_font[i]->font = static_cast<GFXfont*>(const_cast<void*>(font));
return;
}
}
watchos::panic("Exceeded MODULE_UI_MAX_FONTS");
}

13
watchos2/Module_UI.h

@ -7,22 +7,28 @@
#include "watchos_types.h"
#include "Task.h"
#include "Module_Power.h"
#include "IRunnable.h"
#include "IDrawable.h"
#define MODULE_UI_MAX_WINDOWS 32
#define MODULE_UI_MULTICORE_STACK_SIZE 10240
#define MODULE_UI_MAX_FONTS 32
#define MODULE_UI_LAYOUT_MODE_NONE 0
#define MODULE_UI_LAYOUT_MODE_SPLIT_VERTICAL 1
#define MODULE_UI_LAYOUT_MODE_SPLIT_HORIZONTAL 2
#define MODULE_UI_LAYOUT_MODE_ABSOLUTE 3
struct UiWindow;
struct UiFont;
class Module_UI : public Task, public IRunnable
{
Module_Power* module_power;
UiWindow* m_window[MODULE_UI_MAX_WINDOWS];
UiFont* m_font[MODULE_UI_MAX_FONTS];
bool m_initialized = false;
bool m_dirty = false, m_redraw = false;
@ -39,6 +45,8 @@ public:
kernel_handle_t createWindow(kernel_handle_t parent);
kernel_handle_t getRoot();
void initialize();
void start();
void tick();
void draw();
@ -51,7 +59,10 @@ public:
int getHeight();
void fill(uint16_t colour = COLOUR_SECONDARY);
void fill(int x, int y, int width, int height, uint16_t colour = COLOUR_SECONDARY);
void print(int x, int y, char* str, uint16_t colour = COLOUR_PRIMARY, void* font = nullptr);
void print(int x, int y, char* str, uint16_t colour, void* font);
void print(int x, int y, char* str, uint16_t colour = COLOUR_PRIMARY, byte font_id = 0);
void registerFont(byte id, const void* font);
};
#endif

61
watchos2/Task_Clock.cpp

@ -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);
}
};

43
watchos2/Task_Test.cpp

@ -1,18 +1,34 @@
#include "watchos.h"
#include "Module_UI.h"
#include "Module_Storage.h"
class Task_Test : public IRunnable, public IDrawable, public Task, public EventListener
{
Module_UI* ui = nullptr;
Module_Storage* storage = nullptr;
kernel_handle_t window_handle;
int m_counter = 0;
public:
Task_Test()
void start()
{
watchos::subscribe(this, 0xffffffffffffffffu, 0xffffu);
storage = static_cast<Module_Storage*>(watchos::module(WATCHOS_MODULE_STORAGE));
if (storage->allocate((byte)64, 2))
{
watchos::debug("Initialized counter");
storage->write((byte)64, 0, 0);
storage->write((byte)64, 1, 0);
}
else
{
read();
}
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());
}
@ -23,7 +39,13 @@ public:
{
e = this->getEvent();
watchos::debug("Got event: src %#020llx evt %#06x param1 %#04x param2 %#04x", e->source, e->event, e->param1, e->param2);
if (e->source == WATCHOS_MODULE_INPUT && e->event == WATCHOS_EVENT_TYPE_INPUT_PRESSED)
{
watchos::debug("Got event: src %#020llx evt %#06x param1 %#04x param2 %#04x", e->source, e->event, e->param1, e->param2);
m_counter++;
write();
ui->setDirty(window_handle);
}
this->popEvent();
}
@ -31,6 +53,19 @@ public:
void draw(kernel_handle_t handle)
{
ui->fill(COLOUR_SECONDARY);
ui->print(0, ui->getHeight(), "Hello, world!");
char msg[8];
sprintf(msg, "%d", m_counter);
ui->print(0, ui->getHeight(), msg);
}
void read()
{
m_counter = (storage->read((byte)64, 0) << 8) | storage->read((byte)64, 1);
}
void write()
{
storage->write((byte)64, 0, (byte)(m_counter >> 8));
storage->write((byte)64, 1, (byte)(m_counter));
}
};

2
watchos2/__vm/Compile.vmps.xml

File diff suppressed because one or more lines are too long

2
watchos2/__vm/Upload.vmps.xml

File diff suppressed because one or more lines are too long

30
watchos2/watchos.cpp

@ -2,11 +2,41 @@
#include "watchos.h"
#include <Wire.h>
Kernel* watchos::s_kernel = nullptr;
void watchos::initialize()
{
Serial.begin(115200);
Wire.begin(HW_I2C_SDA, HW_I2C_SCL);
}
void watchos::setup()
{
switch (esp_sleep_get_wakeup_cause())
{
case ESP_SLEEP_WAKEUP_EXT0: // external rtc
watchos::debug("Wake due to external rtc");
break;
case ESP_SLEEP_WAKEUP_EXT1: // button press
watchos::debug("Wake due to button press");
break;
case ESP_SLEEP_WAKEUP_TIMER: // internal rtc
watchos::debug("Wake due to internal RTC");
break;
default: // full reset
watchos::debug("Wake due to reset");
kernel()->initialize();
break;
}
kernel()->start();
}
void watchos::tick()
{
kernel()->tick();
}
Kernel* watchos::kernel()

3
watchos2/watchos.h

@ -20,6 +20,9 @@ private:
static Kernel* s_kernel;
public:
static void setup();
static void tick();
static void initialize();
static Kernel* kernel();
static void panic(char* fmt...);

33
watchos2/watchos2.ino

@ -5,24 +5,49 @@
*/
#include "watchos.h"
#include "Module_RTC.h"
#include "Module_Storage.h"
#include "Module_Power.h"
#include "Module_Input.h"
#include "Task_Test.cpp"
#include "Task_Clock.cpp"
#include <Preferences.h>
#include <GxEPD2_BW.h>
#include <Fonts/FreeMono12pt7b.h>
#include <DSEG7_Classic_Bold_53.h>
// the setup function runs once when you press reset or power the board
void setup()
{
delay(500);
delay(100);
watchos::initialize();
Kernel* kernel = watchos::kernel();
kernel->registerTask(new Module_UI(), WATCHOS_MODULE_UI);
Module_Storage* storage;
Module_UI* ui;
kernel->registerTask(new Module_RTC(), WATCHOS_MODULE_RTC);
kernel->registerTask(storage = new Module_Storage(), WATCHOS_MODULE_STORAGE);
kernel->registerTask(new Module_Input(), WATCHOS_MODULE_INPUT);
kernel->registerTask(new Module_Power(), WATCHOS_MODULE_POWER);
kernel->registerTask(ui = new Module_UI(), WATCHOS_MODULE_UI);
watchos::run(new Task_Clock());
watchos::run(new Task_Test());
if (!storage->isValid())
{
watchos::debug("Resetting storage");
storage->reset();
}
watchos::debug("Setup done!");
kernel->pushEvent(0xDEADBEEFu, 0x01, 0x10, 0x20);
ui->registerFont(0, &FreeMono12pt7b);
ui->registerFont(1, &DSEG7_Classic_Bold_53);
watchos::setup();
}
// the loop function runs over and over again until power down or reset
void loop()
{
watchos::kernel()->tick();
watchos::tick();
}

25
watchos2/watchos_consts.h

@ -3,6 +3,8 @@
#include "watchos_config.h"
// If dark mode is enabled, use white as FG black as BG... otherwise
// do the opposite
#ifdef WATCHOS_DARK_MODE
#define COLOUR_PRIMARY 0xFFFF // white
#define COLOUR_SECONDARY 0x0000 // black
@ -11,13 +13,36 @@
#define COLOUR_SECONDARY 0xFFFF // white
#endif
// Event system
// Masks to match all sources/events
#define WATCHOS_EVENT_SOURCE_ALL 0xffffffffffffffffu
#define WATCHOS_EVENT_TYPE_ALL 0xffff
// Event system sources AND kernel well known handles
#define WATCHOS_MODULE_UI 0x00000001
#define WATCHOS_MODULE_POWER 0x00000002
#define WATCHOS_MODULE_INPUT 0x00000004
#define WATCHOS_MODULE_STORAGE 0x00000008
#define WATCHOS_MODULE_RTC 0x00000010
// Event system events
#define WATCHOS_EVENT_TYPE_INPUT_PRESSED 0x0001
#define WATCHOS_EVENT_TYPE_RTC_MINUTE 0x0001
// Kernel handles
#define WATCHOS_HANDLE_NULL 0x00000000
// Kernel handle types
#define WATCHOS_HANDLE_TYPE_TASK 0x01
#define WATCHOS_HANDLE_TYPE_EVENT 0x02
#define WATCHOS_HANDLE_TYPE_EVENT_SUBSCRIPTION 0x03
#define WATCHOS_HANDLE_TYPE_UI_WINDOW 0x04
// Input module buttons
#define WATCHOS_BUTTON_BACK 0x01
#define WATCHOS_BUTTON_OK 0x04
#define WATCHOS_BUTTON_UP 0x08
#define WATCHOS_BUTTON_DOWN 0x10
#endif
Loading…
Cancel
Save