From b6f4234517184ad0272d65cd7af791fd05c1d99b Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 2 Jun 2024 00:43:25 +0000 Subject: [PATCH 01/36] Move motorController.Init call to DisplayApp::Start --- src/displayapp/DisplayApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index d9b2e9b3..3fd34b3a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -125,6 +125,7 @@ void DisplayApp::Start(System::BootErrors error) { bootError = error; lvgl.Init(); + motorController.Init(); if (error == System::BootErrors::TouchController) { LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None); @@ -150,7 +151,6 @@ void DisplayApp::Process(void* instance) { void DisplayApp::InitHw() { brightnessController.Init(); ApplyBrightness(); - motorController.Init(); lcd.Init(); } From c4bea51725f8808f19a04ff245cf2ca34fd402b9 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sat, 6 Jul 2024 01:57:04 +0000 Subject: [PATCH 02/36] Add ASM screen --- src/displayapp/screens/ASM.cpp | 185 +++++++++++++++++++++++++++++++++ src/displayapp/screens/ASM.h | 73 +++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 src/displayapp/screens/ASM.cpp create mode 100644 src/displayapp/screens/ASM.h diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp new file mode 100644 index 00000000..44af99db --- /dev/null +++ b/src/displayapp/screens/ASM.cpp @@ -0,0 +1,185 @@ +#include "ASM.h" + +#include +#include + +#include "asm_data.h" + +using namespace Pinetime::Applications::Screens; + +#define u16(n) (n) >> 8, (n) & 0xFF + +ASM::ASM() { + this->code = out_bin; + this->code_len = out_bin_len; + + run(); +} + +ASM::~ASM() { + lv_obj_clean(lv_scr_act()); +} + +uint8_t ASM::read_byte(size_t pos) { + return code[pos]; +} + +uint16_t ASM::read_u16(size_t pos) { + return static_cast(code[pos + 1] << 8 | code[pos]); +} + +uint32_t ASM::read_u24(size_t pos) { + return static_cast(code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); +} + +uint32_t ASM::read_u32(size_t pos) { + return static_cast(code[pos + 3] << 24 | code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); +} + +void ASM::run() { + for (;;) { + if (ptr >= code_len) { + break; + } + + OpcodeShort opcode = static_cast(code[ptr]); + if (opcode & (1 << 7)) { + // Long opcode + OpcodeLong opcode = static_cast(code[ptr] << 8 | code[ptr + 1]); + + NRF_LOG_INFO("Long opcode: %d", opcode); + + ptr += 2; + + switch (opcode) { + default: + NRF_LOG_ERROR("Unknown opcode: 0x%04X", opcode); + break; + } + } else { + ptr++; + + NRF_LOG_INFO("Short opcode: %d", opcode); + + if (opcode >= SelectSlot0 && opcode <= SelectSlotMax) { + current_slot = opcode - SelectSlot0; + continue; + } + + switch (opcode) { + case WaitRefresh: + return; + + case Push0: + stack[stack_pointer++] = 0; + break; + + case PushU8: + stack[stack_pointer++] = read_byte(ptr); + ptr++; + break; + + case PushU16: + stack[stack_pointer++] = read_u16(ptr); + ptr += 2; + break; + + case PushU24: + stack[stack_pointer++] = read_u24(ptr); + ptr += 3; + break; + + case PushU32: + stack[stack_pointer++] = read_u32(ptr); + ptr += 4; + break; + + case Branch: + assert(stack_pointer >= 1); + ptr = stack[--stack_pointer]; + break; + + case SetLabelText: { // TODO: Remove double allocation here + assert(stack_pointer >= 1); + size_t ptr = stack[--stack_pointer]; + + int length = read_byte(ptr); + char* text = new char[length + 1]; + text[length] = '\0'; + + for (int i = 0; i < length; i++) { + text[i] = read_byte(ptr + 1 + i); + } + + lv_label_set_text(slots[current_slot], text); + + delete[] text; + break; + } + + case CreateLabel: + slots[current_slot] = lv_label_create(lv_scr_act(), NULL); // + break; + + case SetObjectAlign: { + assert(stack_pointer >= 3); // TODO: Compactize this + int16_t y = stack[--stack_pointer]; + int16_t x = stack[--stack_pointer]; + uint8_t align = stack[--stack_pointer]; + lv_obj_align(slots[current_slot], lv_scr_act(), align, x, y); + break; + } + + case SetStyleLocalInt: + case SetStyleLocalFont: + case SetStyleLocalColor: { + assert(stack_pointer >= 3); + uint32_t value = stack[--stack_pointer]; + uint32_t prop = stack[--stack_pointer]; + uint32_t part = stack[--stack_pointer]; + + switch (opcode) { + case SetStyleLocalInt: + _lv_obj_set_style_local_int(slots[current_slot], part, prop, value); + break; + + case SetStyleLocalColor: + _lv_obj_set_style_local_color(slots[current_slot], part, prop, lv_color_hex(value)); + break; + + case SetStyleLocalFont: { + lv_font_t* font = NULL; + + switch (value) { + case 0: + font = &jetbrains_mono_extrabold_compressed; + break; + + default: + NRF_LOG_ERROR("Unknown font: %d", value); + break; + } + + if (font) + _lv_obj_set_style_local_ptr(slots[current_slot], part, prop, font); + + break; + } + + default: + break; + } + break; + } + + default: + NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); + break; + } + } + } +} + +void ASM::Refresh() { + run(); +} \ No newline at end of file diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h new file mode 100644 index 00000000..cb28464b --- /dev/null +++ b/src/displayapp/screens/ASM.h @@ -0,0 +1,73 @@ +#pragma once + +#include "displayapp/screens/Screen.h" +#include "displayapp/apps/Apps.h" +#include "displayapp/Controllers.h" +#include "Symbols.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class ASM : public Screen { + public: + ASM(); + ~ASM(); + + void Refresh() override; + + private: + static constexpr int num_slots = 16; + static constexpr int stack_size = 32; + + enum OpcodeShort : uint8_t { + Branch, + Push0, + PushU8, + PushU16, + PushU24, + PushU32, + SelectSlot0, + SelectSlotMax = SelectSlot0 + ASM::num_slots - 1, + SetLabelText, + SetObjectAlign, + CreateLabel, + SetStyleLocalInt, + SetStyleLocalColor, + SetStyleLocalOpa, + SetStyleLocalFont, + WaitRefresh, + }; + + enum OpcodeLong : uint16_t {}; + + uint8_t read_byte(size_t pos); + uint16_t read_u16(size_t pos); + uint32_t read_u24(size_t pos); + uint32_t read_u32(size_t pos); + + uint8_t* code; + size_t code_len; + size_t ptr = 0; + + lv_obj_t* slots[num_slots] = {0}; + + uint32_t stack[stack_size] = {0}; + uint8_t stack_pointer = 0; + + uint8_t current_slot = 0; + + void run(); + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::ASM; + static constexpr const char* icon = Screens::Symbols::eye; + + static Screens::Screen* Create(AppControllers&) { + return new Screens::ASM(); + }; + }; + }; +} \ No newline at end of file From f173f1b1d52ca37438fb1881529b5a58531d1ec6 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 12:44:32 +0000 Subject: [PATCH 03/36] Add locals --- src/displayapp/screens/ASM.cpp | 77 +++++++++++++++++++++------------- src/displayapp/screens/ASM.h | 66 ++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 36 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 44af99db..265a20f5 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "asm_data.h" @@ -61,47 +62,41 @@ void ASM::run() { NRF_LOG_INFO("Short opcode: %d", opcode); - if (opcode >= SelectSlot0 && opcode <= SelectSlotMax) { - current_slot = opcode - SelectSlot0; - continue; - } - switch (opcode) { case WaitRefresh: return; case Push0: - stack[stack_pointer++] = 0; + push(Value((uint32_t) 0)); break; case PushU8: - stack[stack_pointer++] = read_byte(ptr); + push(Value(read_byte(ptr))); ptr++; break; case PushU16: - stack[stack_pointer++] = read_u16(ptr); + push(Value(read_u16(ptr))); ptr += 2; break; case PushU24: - stack[stack_pointer++] = read_u24(ptr); + push(Value(read_u24(ptr))); ptr += 3; break; case PushU32: - stack[stack_pointer++] = read_u32(ptr); + push(Value(read_u32(ptr))); ptr += 4; break; - case Branch: - assert(stack_pointer >= 1); - ptr = stack[--stack_pointer]; + case Duplicate: + // TODO: Check stack_pointer + push(stack[stack_pointer - 1]); break; - case SetLabelText: { // TODO: Remove double allocation here - assert(stack_pointer >= 1); - size_t ptr = stack[--stack_pointer]; + case LoadString: { + uint32_t ptr = pop_uint32(); int length = read_byte(ptr); char* text = new char[length + 1]; @@ -111,22 +106,43 @@ void ASM::run() { text[i] = read_byte(ptr + 1 + i); } - lv_label_set_text(slots[current_slot], text); + push(Value(text, length + 1)); + break; + } - delete[] text; + case StoreLocal: + locals[read_byte(ptr++)] = pop(); + break; + + case LoadLocal: + push(locals[read_byte(ptr++)]); + break; + + case Branch: + assert(stack_pointer >= 1); + ptr = pop_uint32(); + break; + + case SetLabelText: { + Value str = pop(); + assert(str.type == String); + Value obj = pop(); // TODO: Check type + + lv_label_set_text(obj.data.obj, str.data.s); break; } case CreateLabel: - slots[current_slot] = lv_label_create(lv_scr_act(), NULL); // + push(Value(lv_label_create(lv_scr_act(), NULL))); break; case SetObjectAlign: { - assert(stack_pointer >= 3); // TODO: Compactize this - int16_t y = stack[--stack_pointer]; - int16_t x = stack[--stack_pointer]; - uint8_t align = stack[--stack_pointer]; - lv_obj_align(slots[current_slot], lv_scr_act(), align, x, y); + assert(stack_pointer >= 3); + int16_t y = pop_uint32(); + int16_t x = pop_uint32(); + uint8_t align = pop_uint32(); + Value obj = pop(); // TODO: Check type + lv_obj_align(obj.data.obj, lv_scr_act(), align, x, y); break; } @@ -134,17 +150,18 @@ void ASM::run() { case SetStyleLocalFont: case SetStyleLocalColor: { assert(stack_pointer >= 3); - uint32_t value = stack[--stack_pointer]; - uint32_t prop = stack[--stack_pointer]; - uint32_t part = stack[--stack_pointer]; + uint32_t value = pop_uint32(); + uint32_t prop = pop_uint32(); + uint32_t part = pop_uint32(); + Value obj = pop(); // TODO: Check type switch (opcode) { case SetStyleLocalInt: - _lv_obj_set_style_local_int(slots[current_slot], part, prop, value); + _lv_obj_set_style_local_int(obj.data.obj, part, prop, value); break; case SetStyleLocalColor: - _lv_obj_set_style_local_color(slots[current_slot], part, prop, lv_color_hex(value)); + _lv_obj_set_style_local_color(obj.data.obj, part, prop, lv_color_hex(value)); break; case SetStyleLocalFont: { @@ -161,7 +178,7 @@ void ASM::run() { } if (font) - _lv_obj_set_style_local_ptr(slots[current_slot], part, prop, font); + _lv_obj_set_style_local_ptr(obj.data.obj, part, prop, font); break; } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index cb28464b..e0a08396 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -4,6 +4,7 @@ #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" +#include namespace Pinetime { namespace Applications { @@ -17,17 +18,55 @@ namespace Pinetime { private: static constexpr int num_slots = 16; + static constexpr int max_locals = 16; static constexpr int stack_size = 32; + enum DataType : uint8_t { Integer, String, LvglObject }; + + struct Value { + DataType type; + + union { + uint32_t i; + lv_obj_t* obj; + + struct { + char* s; + uint16_t cap; + }; + } data; + + Value() : type(Integer), data {0} { + } + + Value(DataType t) : type(t), data {0} { + } + + Value(uint32_t i) : type(Integer) { + data.i = i; + } + + Value(lv_obj_t* obj) : type(LvglObject) { + data.obj = obj; + } + + Value(char* s, uint16_t cap) : type(String) { + data.s = s; + data.cap = cap; + } + } __packed; + enum OpcodeShort : uint8_t { + StoreLocal, + LoadLocal, Branch, Push0, PushU8, PushU16, PushU24, PushU32, - SelectSlot0, - SelectSlotMax = SelectSlot0 + ASM::num_slots - 1, + Duplicate, + LoadString, SetLabelText, SetObjectAlign, CreateLabel, @@ -49,14 +88,29 @@ namespace Pinetime { size_t code_len; size_t ptr = 0; - lv_obj_t* slots[num_slots] = {0}; + Value locals[max_locals]; - uint32_t stack[stack_size] = {0}; + Value stack[stack_size]; uint8_t stack_pointer = 0; - uint8_t current_slot = 0; - void run(); + + Value pop() { + assert(stack_pointer > 0); + return stack[--stack_pointer]; + } + + uint32_t pop_uint32() { + Value v = pop(); + assert(v.type == Integer); + return v.data.i; + } + + void push(Value v) { + assert(stack_pointer < stack_size); + stack[stack_pointer] = v; + stack_pointer++; + } }; } From 350567a6d294a917a0cfca67033c62f62426c058 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 12:51:13 +0000 Subject: [PATCH 04/36] Add asm_assert --- src/displayapp/screens/ASM.cpp | 16 ++++++++++++---- src/displayapp/screens/ASM.h | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 265a20f5..edc59c23 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -126,7 +126,7 @@ void ASM::run() { case SetLabelText: { Value str = pop(); assert(str.type == String); - Value obj = pop(); // TODO: Check type + Value obj = pop(LvglObject); lv_label_set_text(obj.data.obj, str.data.s); break; @@ -141,7 +141,7 @@ void ASM::run() { int16_t y = pop_uint32(); int16_t x = pop_uint32(); uint8_t align = pop_uint32(); - Value obj = pop(); // TODO: Check type + Value obj = pop(LvglObject); lv_obj_align(obj.data.obj, lv_scr_act(), align, x, y); break; } @@ -153,7 +153,7 @@ void ASM::run() { uint32_t value = pop_uint32(); uint32_t prop = pop_uint32(); uint32_t part = pop_uint32(); - Value obj = pop(); // TODO: Check type + Value obj = pop(LvglObject); switch (opcode) { case SetStyleLocalInt: @@ -199,4 +199,12 @@ void ASM::run() { void ASM::Refresh() { run(); -} \ No newline at end of file +} + +void ASM::asm_assert(bool condition) { + if (!condition) { + // TODO: Handle better + for (;;) { + } + } +} diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index e0a08396..a1ecf46b 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -74,7 +74,7 @@ namespace Pinetime { SetStyleLocalColor, SetStyleLocalOpa, SetStyleLocalFont, - WaitRefresh, + WaitRefresh }; enum OpcodeLong : uint16_t {}; @@ -94,20 +94,26 @@ namespace Pinetime { uint8_t stack_pointer = 0; void run(); + void asm_assert(bool condition); Value pop() { - assert(stack_pointer > 0); + asm_assert(stack_pointer > 0); return stack[--stack_pointer]; } + Value pop(DataType type) { + asm_assert(stack_pointer > 0); + Value v = stack[--stack_pointer]; + asm_assert(v.type == type); + return v; + } + uint32_t pop_uint32() { - Value v = pop(); - assert(v.type == Integer); - return v.data.i; + return pop(Integer).data.i; } void push(Value v) { - assert(stack_pointer < stack_size); + asm_assert(stack_pointer < stack_size); stack[stack_pointer] = v; stack_pointer++; } From c7d58fc97a92db06285b5362b0287f5302e6b96e Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 12:52:24 +0000 Subject: [PATCH 05/36] Add arithmetic --- src/displayapp/screens/ASM.cpp | 16 ++++++++++++++++ src/displayapp/screens/ASM.h | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index edc59c23..161529a0 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -189,6 +189,22 @@ void ASM::run() { break; } + case Add: + push(Value(pop_uint32() + pop_uint32())); + break; + + case Subtract: + push(Value(pop_uint32() - pop_uint32())); + break; + + case Multiply: + push(Value(pop_uint32() * pop_uint32())); + break; + + case Divide: + push(Value(pop_uint32() / pop_uint32())); + break; + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index a1ecf46b..9bb07537 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -74,7 +74,12 @@ namespace Pinetime { SetStyleLocalColor, SetStyleLocalOpa, SetStyleLocalFont, - WaitRefresh + WaitRefresh, + + Add, + Subtract, + Multiply, + Divide }; enum OpcodeLong : uint16_t {}; From e677d1cb426d39a61218f6c2f0541b729e83d2b1 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 13:34:11 +0000 Subject: [PATCH 06/36] Concat strings --- src/displayapp/screens/ASM.cpp | 54 ++++++++++++++++++++++++++++++++-- src/displayapp/screens/ASM.h | 7 ++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 161529a0..88c09742 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -90,6 +90,10 @@ void ASM::run() { ptr += 4; break; + case PushEmptyString: + push(Value(new char[1] {0}, 1)); + break; + case Duplicate: // TODO: Check stack_pointer push(stack[stack_pointer - 1]); @@ -124,8 +128,7 @@ void ASM::run() { break; case SetLabelText: { - Value str = pop(); - assert(str.type == String); + Value str = pop(String); Value obj = pop(LvglObject); lv_label_set_text(obj.data.obj, str.data.s); @@ -205,6 +208,53 @@ void ASM::run() { push(Value(pop_uint32() / pop_uint32())); break; + case GrowString: { + Value len = pop(Integer); + Value str = pop(String); + + size_t new_cap = len.data.i + str.data.cap; + asm_assert(new_cap >= str.data.cap); + + char* new_str = new char[new_cap]; + memcpy(new_str, str.data.s, str.data.cap); + + push(Value(new_str, new_cap)); + break; + } + + case Concat: { + Value b = pop(); + Value a = pop(); + + if (a.type == String && b.type == String) { + int len_a = strlen(a.data.s); + int len_b = strlen(b.data.s); + + size_t new_len = len_a + len_b + 1; + + if (a.data.cap >= new_len) { + strcat(a.data.s, b.data.s); + + push(Value(a.data.s, a.data.cap)); + } else { + char* s = new char[new_len + 1]; + strcpy(s, a.data.s); + strcat(s, b.data.s); + + push(Value(s, new_len + 1)); + } + } else if (a.type == String && b.type == Integer) { + size_t cap = strlen(a.data.s) + 12 + 1; + char* s = new char[cap]; + snprintf(s, cap, "%s%lu", a.data.s, b.data.i); + + push(Value(s, cap)); + } else { + asm_assert(false); + } + break; + } + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 9bb07537..8a2e4e99 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -65,8 +65,10 @@ namespace Pinetime { PushU16, PushU24, PushU32, + PushEmptyString, Duplicate, LoadString, + SetLabelText, SetObjectAlign, CreateLabel, @@ -79,7 +81,10 @@ namespace Pinetime { Add, Subtract, Multiply, - Divide + Divide, + + GrowString, + Concat }; enum OpcodeLong : uint16_t {}; From 0faece9e4bac6247461217987f626e9b07bf416a Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 16:36:59 +0000 Subject: [PATCH 07/36] Add refreshing --- src/displayapp/screens/ASM.cpp | 13 +++++++++++++ src/displayapp/screens/ASM.h | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 88c09742..5742345b 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -127,6 +127,19 @@ void ASM::run() { ptr = pop_uint32(); break; + case StartPeriodicRefresh: + if (taskRefresh == nullptr) { + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + } + break; + + case StopPeriodicRefresh: + if (taskRefresh != nullptr) { + lv_task_del(taskRefresh); + taskRefresh = nullptr; + } + break; + case SetLabelText: { Value str = pop(String); Value obj = pop(LvglObject); diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 8a2e4e99..ebb815f9 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -54,6 +54,21 @@ namespace Pinetime { data.s = s; data.cap = cap; } + + ~Value() { + switch (type) { + case String: + delete[] data.s; + break; + + case LvglObject: + lv_obj_del(data.obj); + break; + + default: + break; + } + } } __packed; enum OpcodeShort : uint8_t { @@ -69,6 +84,9 @@ namespace Pinetime { Duplicate, LoadString, + StartPeriodicRefresh, + StopPeriodicRefresh, + SetLabelText, SetObjectAlign, CreateLabel, @@ -103,6 +121,8 @@ namespace Pinetime { Value stack[stack_size]; uint8_t stack_pointer = 0; + lv_task_t* taskRefresh = nullptr; + void run(); void asm_assert(bool condition); From 8d5ac4f4c2686d620afda4fe05ab50f5749505e8 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 16:45:53 +0000 Subject: [PATCH 08/36] Add call --- src/displayapp/screens/ASM.cpp | 8 ++++++++ src/displayapp/screens/ASM.h | 25 +++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 5742345b..56f6b91f 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -127,6 +127,14 @@ void ASM::run() { ptr = pop_uint32(); break; + case Call: { + assert(stack_pointer >= 1); + uint32_t next = ptr; + ptr = pop_uint32(); + push(Value(next)); + break; + } + case StartPeriodicRefresh: if (taskRefresh == nullptr) { taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index ebb815f9..c8b84f1d 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -55,26 +55,27 @@ namespace Pinetime { data.cap = cap; } - ~Value() { - switch (type) { - case String: - delete[] data.s; - break; + // ~Value() { + // switch (type) { + // case String: + // delete[] data.s; + // break; - case LvglObject: - lv_obj_del(data.obj); - break; + // case LvglObject: + // lv_obj_del(data.obj); + // break; - default: - break; - } - } + // default: + // break; + // } + // } } __packed; enum OpcodeShort : uint8_t { StoreLocal, LoadLocal, Branch, + Call, Push0, PushU8, PushU16, From 23729eff99cb3b20626e15f5be8499872533c1fa Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 18:49:19 +0000 Subject: [PATCH 09/36] Use shared_ptrs --- src/displayapp/screens/ASM.cpp | 129 +++++++++++++++++---------------- src/displayapp/screens/ASM.h | 62 +++++++++------- 2 files changed, 100 insertions(+), 91 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 56f6b91f..69188c69 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -18,7 +18,12 @@ ASM::ASM() { } ASM::~ASM() { - lv_obj_clean(lv_scr_act()); + if (taskRefresh != nullptr) { + lv_task_del(taskRefresh); + } + + // We don't need to clean the screen since all objects are deleted when their shared_ptr is dropped + // lv_obj_clean(lv_scr_act()); } uint8_t ASM::read_byte(size_t pos) { @@ -39,18 +44,18 @@ uint32_t ASM::read_u32(size_t pos) { void ASM::run() { for (;;) { - if (ptr >= code_len) { + if (pc >= code_len) { break; } - OpcodeShort opcode = static_cast(code[ptr]); + OpcodeShort opcode = static_cast(code[pc]); if (opcode & (1 << 7)) { // Long opcode - OpcodeLong opcode = static_cast(code[ptr] << 8 | code[ptr + 1]); + OpcodeLong opcode = static_cast(code[pc] << 8 | code[pc + 1]); NRF_LOG_INFO("Long opcode: %d", opcode); - ptr += 2; + pc += 2; switch (opcode) { default: @@ -58,7 +63,7 @@ void ASM::run() { break; } } else { - ptr++; + pc++; NRF_LOG_INFO("Short opcode: %d", opcode); @@ -67,35 +72,34 @@ void ASM::run() { return; case Push0: - push(Value((uint32_t) 0)); + push(std::make_shared((uint32_t) 0)); break; case PushU8: - push(Value(read_byte(ptr))); - ptr++; + push(std::make_shared(read_byte(pc))); + pc++; break; case PushU16: - push(Value(read_u16(ptr))); - ptr += 2; + push(std::make_shared(read_u16(pc))); + pc += 2; break; case PushU24: - push(Value(read_u24(ptr))); - ptr += 3; + push(std::make_shared(read_u24(pc))); + pc += 3; break; case PushU32: - push(Value(read_u32(ptr))); - ptr += 4; + push(std::make_shared(read_u32(pc))); + pc += 4; break; case PushEmptyString: - push(Value(new char[1] {0}, 1)); + push(std::make_shared(new char[1] {0}, 1)); break; case Duplicate: - // TODO: Check stack_pointer push(stack[stack_pointer - 1]); break; @@ -110,28 +114,26 @@ void ASM::run() { text[i] = read_byte(ptr + 1 + i); } - push(Value(text, length + 1)); + push(std::make_shared(text, length + 1)); break; } case StoreLocal: - locals[read_byte(ptr++)] = pop(); + locals[read_byte(pc++)] = pop(); break; case LoadLocal: - push(locals[read_byte(ptr++)]); + push(locals[read_byte(pc++)]); break; case Branch: - assert(stack_pointer >= 1); - ptr = pop_uint32(); + pc = pop_uint32(); break; case Call: { - assert(stack_pointer >= 1); - uint32_t next = ptr; - ptr = pop_uint32(); - push(Value(next)); + uint32_t next = pc; + pc = pop_uint32(); + push(std::make_shared(next)); break; } @@ -149,43 +151,41 @@ void ASM::run() { break; case SetLabelText: { - Value str = pop(String); - Value obj = pop(LvglObject); + auto str = pop(String); + auto obj = pop(LvglObject); - lv_label_set_text(obj.data.obj, str.data.s); + lv_label_set_text(obj->data.obj, str->data.s); break; } case CreateLabel: - push(Value(lv_label_create(lv_scr_act(), NULL))); + push(std::make_shared(lv_label_create(lv_scr_act(), NULL))); break; case SetObjectAlign: { - assert(stack_pointer >= 3); int16_t y = pop_uint32(); int16_t x = pop_uint32(); uint8_t align = pop_uint32(); - Value obj = pop(LvglObject); - lv_obj_align(obj.data.obj, lv_scr_act(), align, x, y); + auto obj = pop(LvglObject); + lv_obj_align(obj->data.obj, lv_scr_act(), align, x, y); break; } case SetStyleLocalInt: case SetStyleLocalFont: case SetStyleLocalColor: { - assert(stack_pointer >= 3); uint32_t value = pop_uint32(); uint32_t prop = pop_uint32(); uint32_t part = pop_uint32(); - Value obj = pop(LvglObject); + auto obj = pop(LvglObject); switch (opcode) { case SetStyleLocalInt: - _lv_obj_set_style_local_int(obj.data.obj, part, prop, value); + _lv_obj_set_style_local_int(obj->data.obj, part, prop, value); break; case SetStyleLocalColor: - _lv_obj_set_style_local_color(obj.data.obj, part, prop, lv_color_hex(value)); + _lv_obj_set_style_local_color(obj->data.obj, part, prop, lv_color_hex(value)); break; case SetStyleLocalFont: { @@ -202,7 +202,7 @@ void ASM::run() { } if (font) - _lv_obj_set_style_local_ptr(obj.data.obj, part, prop, font); + _lv_obj_set_style_local_ptr(obj->data.obj, part, prop, font); break; } @@ -213,63 +213,64 @@ void ASM::run() { break; } - case Add: - push(Value(pop_uint32() + pop_uint32())); + case Add: { + push(std::make_shared(pop_uint32() + pop_uint32())); break; + } case Subtract: - push(Value(pop_uint32() - pop_uint32())); + push(std::make_shared(pop_uint32() - pop_uint32())); break; case Multiply: - push(Value(pop_uint32() * pop_uint32())); + push(std::make_shared(pop_uint32() * pop_uint32())); break; case Divide: - push(Value(pop_uint32() / pop_uint32())); + push(std::make_shared(pop_uint32() / pop_uint32())); break; case GrowString: { - Value len = pop(Integer); - Value str = pop(String); + auto len = pop(Integer); + auto str = pop(String); - size_t new_cap = len.data.i + str.data.cap; - asm_assert(new_cap >= str.data.cap); + size_t new_cap = len->data.i + str->data.cap; + asm_assert(new_cap >= str->data.cap); char* new_str = new char[new_cap]; - memcpy(new_str, str.data.s, str.data.cap); + memcpy(new_str, str->data.s, str->data.cap); - push(Value(new_str, new_cap)); + push(std::make_shared(new_str, new_cap)); break; } case Concat: { - Value b = pop(); - Value a = pop(); + auto b = pop(); + auto a = pop(); - if (a.type == String && b.type == String) { - int len_a = strlen(a.data.s); - int len_b = strlen(b.data.s); + if (a->type == String && b->type == String) { + int len_a = strlen(a->data.s); + int len_b = strlen(b->data.s); size_t new_len = len_a + len_b + 1; - if (a.data.cap >= new_len) { - strcat(a.data.s, b.data.s); + if (a->data.cap >= new_len) { + strcat(a->data.s, b->data.s); - push(Value(a.data.s, a.data.cap)); + push(a); } else { char* s = new char[new_len + 1]; - strcpy(s, a.data.s); - strcat(s, b.data.s); + strcpy(s, a->data.s); + strcat(s, b->data.s); - push(Value(s, new_len + 1)); + push(std::make_shared(s, new_len + 1)); } - } else if (a.type == String && b.type == Integer) { - size_t cap = strlen(a.data.s) + 12 + 1; + } else if (a->type == String && b->type == Integer) { + size_t cap = strlen(a->data.s) + 12 + 1; char* s = new char[cap]; - snprintf(s, cap, "%s%lu", a.data.s, b.data.i); + snprintf(s, cap, "%s%lu", a->data.s, b->data.i); - push(Value(s, cap)); + push(std::make_shared(s, cap)); } else { asm_assert(false); } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index c8b84f1d..92e969a2 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -4,7 +4,9 @@ #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" + #include +#include namespace Pinetime { namespace Applications { @@ -24,7 +26,7 @@ namespace Pinetime { enum DataType : uint8_t { Integer, String, LvglObject }; struct Value { - DataType type; + const DataType type; union { uint32_t i; @@ -55,21 +57,21 @@ namespace Pinetime { data.cap = cap; } - // ~Value() { - // switch (type) { - // case String: - // delete[] data.s; - // break; + ~Value() { + switch (type) { + case String: + delete[] data.s; + break; - // case LvglObject: - // lv_obj_del(data.obj); - // break; + case LvglObject: + lv_obj_del(data.obj); + break; - // default: - // break; - // } - // } - } __packed; + default: + break; + } + } + }; enum OpcodeShort : uint8_t { StoreLocal, @@ -115,11 +117,11 @@ namespace Pinetime { uint8_t* code; size_t code_len; - size_t ptr = 0; + size_t pc = 0; - Value locals[max_locals]; + std::shared_ptr locals[max_locals] = {}; - Value stack[stack_size]; + std::shared_ptr stack[stack_size] = {}; uint8_t stack_pointer = 0; lv_task_t* taskRefresh = nullptr; @@ -127,26 +129,32 @@ namespace Pinetime { void run(); void asm_assert(bool condition); - Value pop() { + std::shared_ptr pop() { asm_assert(stack_pointer > 0); - return stack[--stack_pointer]; + + stack_pointer--; + + auto v = stack[stack_pointer]; + stack[stack_pointer] = nullptr; + + return v; } - Value pop(DataType type) { - asm_assert(stack_pointer > 0); - Value v = stack[--stack_pointer]; - asm_assert(v.type == type); + std::shared_ptr pop(DataType type) { + auto v = pop(); + asm_assert(v->type == type); + return v; } uint32_t pop_uint32() { - return pop(Integer).data.i; + return pop(Integer)->data.i; } - void push(Value v) { + void push(std::shared_ptr v) { asm_assert(stack_pointer < stack_size); - stack[stack_pointer] = v; - stack_pointer++; + + stack[stack_pointer++] = v; } }; } From 7ac66dc2373fae8772ea8b589806292f8c99dfc2 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 18:50:05 +0000 Subject: [PATCH 10/36] Rename obj to lvobj --- src/displayapp/screens/ASM.cpp | 10 +++++----- src/displayapp/screens/ASM.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 69188c69..b361ee67 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -154,7 +154,7 @@ void ASM::run() { auto str = pop(String); auto obj = pop(LvglObject); - lv_label_set_text(obj->data.obj, str->data.s); + lv_label_set_text(obj->data.lvobj, str->data.s); break; } @@ -167,7 +167,7 @@ void ASM::run() { int16_t x = pop_uint32(); uint8_t align = pop_uint32(); auto obj = pop(LvglObject); - lv_obj_align(obj->data.obj, lv_scr_act(), align, x, y); + lv_obj_align(obj->data.lvobj, lv_scr_act(), align, x, y); break; } @@ -181,11 +181,11 @@ void ASM::run() { switch (opcode) { case SetStyleLocalInt: - _lv_obj_set_style_local_int(obj->data.obj, part, prop, value); + _lv_obj_set_style_local_int(obj->data.lvobj, part, prop, value); break; case SetStyleLocalColor: - _lv_obj_set_style_local_color(obj->data.obj, part, prop, lv_color_hex(value)); + _lv_obj_set_style_local_color(obj->data.lvobj, part, prop, lv_color_hex(value)); break; case SetStyleLocalFont: { @@ -202,7 +202,7 @@ void ASM::run() { } if (font) - _lv_obj_set_style_local_ptr(obj->data.obj, part, prop, font); + _lv_obj_set_style_local_ptr(obj->data.lvobj, part, prop, font); break; } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 92e969a2..2478a541 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -30,7 +30,7 @@ namespace Pinetime { union { uint32_t i; - lv_obj_t* obj; + lv_obj_t* lvobj; struct { char* s; @@ -49,7 +49,7 @@ namespace Pinetime { } Value(lv_obj_t* obj) : type(LvglObject) { - data.obj = obj; + data.lvobj = obj; } Value(char* s, uint16_t cap) : type(String) { @@ -64,7 +64,7 @@ namespace Pinetime { break; case LvglObject: - lv_obj_del(data.obj); + lv_obj_del(data.lvobj); break; default: From bf13db05ce4e98c5e75bad59a2e3d20bca40755c Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 21:01:23 +0000 Subject: [PATCH 11/36] Use inheritance for values --- src/displayapp/screens/ASM.cpp | 90 ++++++++++++++++++---------------- src/displayapp/screens/ASM.h | 74 ++++++++++++++-------------- 2 files changed, 87 insertions(+), 77 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index b361ee67..068ee222 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -72,31 +72,31 @@ void ASM::run() { return; case Push0: - push(std::make_shared((uint32_t) 0)); + push(std::make_shared(0)); break; case PushU8: - push(std::make_shared(read_byte(pc))); + push(std::make_shared(read_byte(pc))); pc++; break; case PushU16: - push(std::make_shared(read_u16(pc))); + push(std::make_shared(read_u16(pc))); pc += 2; break; case PushU24: - push(std::make_shared(read_u24(pc))); + push(std::make_shared(read_u24(pc))); pc += 3; break; case PushU32: - push(std::make_shared(read_u32(pc))); + push(std::make_shared(read_u32(pc))); pc += 4; break; case PushEmptyString: - push(std::make_shared(new char[1] {0}, 1)); + push(std::make_shared(new char[1] {0}, 1)); break; case Duplicate: @@ -114,7 +114,7 @@ void ASM::run() { text[i] = read_byte(ptr + 1 + i); } - push(std::make_shared(text, length + 1)); + push(std::make_shared(text, length + 1)); break; } @@ -133,7 +133,7 @@ void ASM::run() { case Call: { uint32_t next = pc; pc = pop_uint32(); - push(std::make_shared(next)); + push(std::make_shared(next)); break; } @@ -151,23 +151,23 @@ void ASM::run() { break; case SetLabelText: { - auto str = pop(String); - auto obj = pop(LvglObject); + auto str = pop(String); + auto obj = pop(LvglObject); - lv_label_set_text(obj->data.lvobj, str->data.s); + lv_label_set_text(obj->obj, str->str); break; } case CreateLabel: - push(std::make_shared(lv_label_create(lv_scr_act(), NULL))); + push(std::make_shared(lv_label_create(lv_scr_act(), NULL))); break; case SetObjectAlign: { int16_t y = pop_uint32(); int16_t x = pop_uint32(); uint8_t align = pop_uint32(); - auto obj = pop(LvglObject); - lv_obj_align(obj->data.lvobj, lv_scr_act(), align, x, y); + auto obj = pop(LvglObject); + lv_obj_align(obj->obj, lv_scr_act(), align, x, y); break; } @@ -177,15 +177,15 @@ void ASM::run() { uint32_t value = pop_uint32(); uint32_t prop = pop_uint32(); uint32_t part = pop_uint32(); - auto obj = pop(LvglObject); + auto obj = pop(LvglObject); switch (opcode) { case SetStyleLocalInt: - _lv_obj_set_style_local_int(obj->data.lvobj, part, prop, value); + _lv_obj_set_style_local_int(obj->obj, part, prop, value); break; case SetStyleLocalColor: - _lv_obj_set_style_local_color(obj->data.lvobj, part, prop, lv_color_hex(value)); + _lv_obj_set_style_local_color(obj->obj, part, prop, lv_color_hex(value)); break; case SetStyleLocalFont: { @@ -202,7 +202,7 @@ void ASM::run() { } if (font) - _lv_obj_set_style_local_ptr(obj->data.lvobj, part, prop, font); + _lv_obj_set_style_local_ptr(obj->obj, part, prop, font); break; } @@ -214,33 +214,33 @@ void ASM::run() { } case Add: { - push(std::make_shared(pop_uint32() + pop_uint32())); + push(std::make_shared(pop_uint32() + pop_uint32())); break; } case Subtract: - push(std::make_shared(pop_uint32() - pop_uint32())); + push(std::make_shared(pop_uint32() - pop_uint32())); break; case Multiply: - push(std::make_shared(pop_uint32() * pop_uint32())); + push(std::make_shared(pop_uint32() * pop_uint32())); break; case Divide: - push(std::make_shared(pop_uint32() / pop_uint32())); + push(std::make_shared(pop_uint32() / pop_uint32())); break; case GrowString: { - auto len = pop(Integer); - auto str = pop(String); + auto len = pop_uint32(); + auto str = pop(String); - size_t new_cap = len->data.i + str->data.cap; - asm_assert(new_cap >= str->data.cap); + size_t new_cap = len + str->capacity; + asm_assert(new_cap >= str->capacity); char* new_str = new char[new_cap]; - memcpy(new_str, str->data.s, str->data.cap); + memcpy(new_str, str->str, str->capacity); - push(std::make_shared(new_str, new_cap)); + push(std::make_shared(new_str, new_cap)); break; } @@ -248,29 +248,37 @@ void ASM::run() { auto b = pop(); auto a = pop(); - if (a->type == String && b->type == String) { - int len_a = strlen(a->data.s); - int len_b = strlen(b->data.s); + if (a->type() == String && b->type() == String) { + auto aString = static_cast(a.get()); + auto bString = static_cast(b.get()); + + int len_a = strlen(aString->str); + int len_b = strlen(bString->str); size_t new_len = len_a + len_b + 1; - if (a->data.cap >= new_len) { - strcat(a->data.s, b->data.s); + if (aString->capacity >= new_len) { + strcat(aString->str, bString->str); push(a); } else { char* s = new char[new_len + 1]; - strcpy(s, a->data.s); - strcat(s, b->data.s); + strcpy(s, aString->str); + strcat(s, bString->str); - push(std::make_shared(s, new_len + 1)); + push(std::make_shared(s, new_len + 1)); } - } else if (a->type == String && b->type == Integer) { - size_t cap = strlen(a->data.s) + 12 + 1; - char* s = new char[cap]; - snprintf(s, cap, "%s%lu", a->data.s, b->data.i); + } else if (a->type() == String && b->type() == Integer) { + auto aString = static_cast(a.get()); + auto bInt = static_cast(b.get()); - push(std::make_shared(s, cap)); + if (bInt) { + size_t cap = strlen(aString->str) + 12 + 1; + char* s = new char[cap]; + snprintf(s, cap, "%s%lu", aString->str, bInt->i); + + push(std::make_shared(s, cap)); + } } else { asm_assert(false); } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 2478a541..f575f16c 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -25,51 +25,50 @@ namespace Pinetime { enum DataType : uint8_t { Integer, String, LvglObject }; + // TODO: Use fancy C++ type stuff struct Value { - const DataType type; + virtual DataType type() = 0; + }; - union { - uint32_t i; - lv_obj_t* lvobj; + struct ValueInteger : public Value { + uint32_t i; - struct { - char* s; - uint16_t cap; - }; - } data; - - Value() : type(Integer), data {0} { + ValueInteger(uint32_t i) : i(i) { } - Value(DataType t) : type(t), data {0} { + DataType type() override { + return Integer; + } + }; + + struct ValueString : public Value { + char* str; + uint16_t capacity; + + ValueString(char* str, uint16_t cap) : str(str), capacity(cap) { } - Value(uint32_t i) : type(Integer) { - data.i = i; + ~ValueString() { + delete[] str; } - Value(lv_obj_t* obj) : type(LvglObject) { - data.lvobj = obj; + DataType type() override { + return String; + } + }; + + struct ValueLvglObject : public Value { + lv_obj_t* obj; + + ValueLvglObject(lv_obj_t* obj) : obj(obj) { } - Value(char* s, uint16_t cap) : type(String) { - data.s = s; - data.cap = cap; + ~ValueLvglObject() { + lv_obj_del(obj); } - ~Value() { - switch (type) { - case String: - delete[] data.s; - break; - - case LvglObject: - lv_obj_del(data.lvobj); - break; - - default: - break; - } + DataType type() override { + return LvglObject; } }; @@ -140,15 +139,18 @@ namespace Pinetime { return v; } - std::shared_ptr pop(DataType type) { + template + std::shared_ptr pop(DataType type) + requires(std::is_base_of_v) + { auto v = pop(); - asm_assert(v->type == type); + asm_assert(v->type() == type); - return v; + return std::static_pointer_cast(v); } uint32_t pop_uint32() { - return pop(Integer)->data.i; + return pop(Integer)->i; } void push(std::shared_ptr v) { From 29f1a938392713a74b8eb03c7e0957251d84493a Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 22:08:00 +0000 Subject: [PATCH 12/36] Add datetime formatting --- src/displayapp/screens/ASM.cpp | 43 ++++++++++++++++++++++++++++++++-- src/displayapp/screens/ASM.h | 30 ++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 068ee222..5392f8df 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -10,11 +10,11 @@ using namespace Pinetime::Applications::Screens; #define u16(n) (n) >> 8, (n) & 0xFF -ASM::ASM() { +ASM::ASM(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { this->code = out_bin; this->code_len = out_bin_len; - run(); + Refresh(); } ASM::~ASM() { @@ -244,6 +244,15 @@ void ASM::run() { break; } + case ClearString: { + auto str = pop(String); + if (str->capacity > 0) + str->str[0] = '\0'; + + push(std::make_shared(str->str, str->capacity)); + break; + } + case Concat: { auto b = pop(); auto a = pop(); @@ -285,6 +294,36 @@ void ASM::run() { break; } + case PushCurrentTime: { + auto time = dateTimeController.CurrentDateTime(); + std::tm tm { + .tm_sec = dateTimeController.Seconds(), + .tm_min = dateTimeController.Minutes(), + .tm_hour = dateTimeController.Hours(), + .tm_mday = dateTimeController.Day(), + .tm_mon = static_cast(dateTimeController.Month()) - 1, + .tm_year = dateTimeController.Year() - 1900, + .tm_wday = static_cast(dateTimeController.DayOfWeek()), + .tm_yday = dateTimeController.DayOfYear() - 1, + }; + + push(std::make_shared(time, tm)); + break; + } + + case FormatDateTime: { + auto fmt = pop(String); + auto time = pop(DateTime); + + constexpr int max_len = 16; + char* str = new char[max_len]; // TODO: Allow user to reuse string in stack + + strftime(str, max_len, fmt->str, &time->tm); + + push(std::make_shared(str, max_len)); + break; + } + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index f575f16c..8b9ce094 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -3,17 +3,19 @@ #include "displayapp/screens/Screen.h" #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" +#include "components/datetime/DateTimeController.h" #include "Symbols.h" #include #include +#include namespace Pinetime { namespace Applications { namespace Screens { class ASM : public Screen { public: - ASM(); + ASM(Controllers::DateTime&); ~ASM(); void Refresh() override; @@ -23,7 +25,7 @@ namespace Pinetime { static constexpr int max_locals = 16; static constexpr int stack_size = 32; - enum DataType : uint8_t { Integer, String, LvglObject }; + enum DataType : uint8_t { Integer, String, LvglObject, DateTime }; // TODO: Use fancy C++ type stuff struct Value { @@ -72,6 +74,19 @@ namespace Pinetime { } }; + struct ValueDateTime : public Value { + std::chrono::time_point time; + std::tm tm; + + ValueDateTime(std::chrono::time_point time, std::tm tm) + : time(time), tm(tm) { + } + + DataType type() override { + return DateTime; + } + }; + enum OpcodeShort : uint8_t { StoreLocal, LoadLocal, @@ -83,6 +98,7 @@ namespace Pinetime { PushU24, PushU32, PushEmptyString, + PushCurrentTime, Duplicate, LoadString, @@ -104,7 +120,9 @@ namespace Pinetime { Divide, GrowString, - Concat + ClearString, + Concat, + FormatDateTime }; enum OpcodeLong : uint16_t {}; @@ -125,6 +143,8 @@ namespace Pinetime { lv_task_t* taskRefresh = nullptr; + Controllers::DateTime& dateTimeController; + void run(); void asm_assert(bool condition); @@ -166,8 +186,8 @@ namespace Pinetime { static constexpr Apps app = Apps::ASM; static constexpr const char* icon = Screens::Symbols::eye; - static Screens::Screen* Create(AppControllers&) { - return new Screens::ASM(); + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::ASM(controllers.dateTimeController); }; }; }; From e9db08e589d98796e318e4ad61a51019d10ae903 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 7 Jul 2024 22:14:17 +0000 Subject: [PATCH 13/36] Include ASM screen --- src/CMakeLists.txt | 1 + src/displayapp/UserApps.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd8ece62..2f146929 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -397,6 +397,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Alarm.cpp displayapp/screens/Styles.cpp displayapp/screens/WeatherSymbols.cpp + displayapp/screens/ASM.cpp displayapp/Colors.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 67bbfa7d..d88d4842 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -2,6 +2,7 @@ #include "displayapp/apps/Apps.h" #include "Controllers.h" +#include "displayapp/screens/ASM.h" #include "displayapp/screens/Alarm.h" #include "displayapp/screens/Dice.h" #include "displayapp/screens/Timer.h" From 562035dcab10903f697f316a6055d1fad35345c7 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 00:42:21 +0000 Subject: [PATCH 14/36] Add ASM app to apps list --- src/displayapp/apps/Apps.h.in | 3 ++- src/displayapp/apps/CMakeLists.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267..fd4bd70a 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -42,7 +42,8 @@ namespace Pinetime { SettingChimes, SettingShakeThreshold, SettingBluetooth, - Error + Error, + ASM }; enum class WatchFace : uint8_t { diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index d7858760..824671c5 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -2,6 +2,7 @@ if(DEFINED ENABLE_USERAPPS) set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware") else () set(DEFAULT_USER_APP_TYPES "Apps::StopWatch") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::ASM") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps") From 2adeb398005ac93f3aa8bb3f3afc07ae7f7cf04b Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 00:52:42 +0000 Subject: [PATCH 15/36] Add RealignObject --- src/displayapp/screens/ASM.cpp | 4 ++++ src/displayapp/screens/ASM.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 5392f8df..a8290e6b 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -324,6 +324,10 @@ void ASM::run() { break; } + case RealignObject: + lv_obj_realign(pop(LvglObject)->obj); + break; + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 8b9ce094..244ebdd9 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -112,6 +112,7 @@ namespace Pinetime { SetStyleLocalColor, SetStyleLocalOpa, SetStyleLocalFont, + RealignObject, WaitRefresh, Add, From db53157c216062a8246d05acc2bc3f4d9846f2ca Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 00:53:17 +0000 Subject: [PATCH 16/36] Cleanup --- src/displayapp/screens/ASM.cpp | 22 ++-------------------- src/displayapp/screens/ASM.h | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index a8290e6b..4a10a44f 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -8,8 +8,6 @@ using namespace Pinetime::Applications::Screens; -#define u16(n) (n) >> 8, (n) & 0xFF - ASM::ASM(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { this->code = out_bin; this->code_len = out_bin_len; @@ -26,32 +24,16 @@ ASM::~ASM() { // lv_obj_clean(lv_scr_act()); } -uint8_t ASM::read_byte(size_t pos) { - return code[pos]; -} - -uint16_t ASM::read_u16(size_t pos) { - return static_cast(code[pos + 1] << 8 | code[pos]); -} - -uint32_t ASM::read_u24(size_t pos) { - return static_cast(code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); -} - -uint32_t ASM::read_u32(size_t pos) { - return static_cast(code[pos + 3] << 24 | code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); -} - void ASM::run() { for (;;) { if (pc >= code_len) { break; } - OpcodeShort opcode = static_cast(code[pc]); + OpcodeShort opcode = static_cast(read_byte(pc)); if (opcode & (1 << 7)) { // Long opcode - OpcodeLong opcode = static_cast(code[pc] << 8 | code[pc + 1]); + OpcodeLong opcode = static_cast(read_u16(pc)); NRF_LOG_INFO("Long opcode: %d", opcode); diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 244ebdd9..2af98c77 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -128,10 +128,21 @@ namespace Pinetime { enum OpcodeLong : uint16_t {}; - uint8_t read_byte(size_t pos); - uint16_t read_u16(size_t pos); - uint32_t read_u24(size_t pos); - uint32_t read_u32(size_t pos); + uint8_t read_byte(size_t pos) { + return code[pos]; + } + + uint16_t read_u16(size_t pos) { + return static_cast(code[pos + 1] << 8 | code[pos]); + } + + uint32_t read_u24(size_t pos) { + return static_cast(code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); + } + + uint32_t read_u32(size_t pos) { + return static_cast(code[pos + 3] << 24 | code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); + } uint8_t* code; size_t code_len; From 1751c4d5b4e2604115f153c8e1bf0d1e3fd0c6a9 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 00:59:00 +0000 Subject: [PATCH 17/36] Add fonts array --- src/displayapp/screens/ASM.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 4a10a44f..554de4df 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -8,6 +8,17 @@ using namespace Pinetime::Applications::Screens; +constexpr lv_font_t* fonts[] = { + &fontawesome_weathericons, + &jetbrains_mono_42, + &jetbrains_mono_76, + &jetbrains_mono_bold_20, + &jetbrains_mono_extrabold_compressed, + &lv_font_sys_48, + &open_sans_light, +}; +constexpr int num_fonts = sizeof(fonts) / sizeof(fonts[0]); + ASM::ASM(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { this->code = out_bin; this->code_len = out_bin_len; @@ -171,21 +182,9 @@ void ASM::run() { break; case SetStyleLocalFont: { - lv_font_t* font = NULL; - - switch (value) { - case 0: - font = &jetbrains_mono_extrabold_compressed; - break; - - default: - NRF_LOG_ERROR("Unknown font: %d", value); - break; + if (value < num_fonts) { + _lv_obj_set_style_local_ptr(obj->obj, part, prop, fonts[value]); } - - if (font) - _lv_obj_set_style_local_ptr(obj->obj, part, prop, font); - break; } From d3706722e0f2ec3289a5853a66b2acbd362fcad7 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 02:05:57 +0000 Subject: [PATCH 18/36] Add status icons --- src/displayapp/screens/ASM.cpp | 14 +++++++++++++- src/displayapp/screens/ASM.h | 9 +++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 554de4df..0926da39 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -19,7 +19,8 @@ constexpr lv_font_t* fonts[] = { }; constexpr int num_fonts = sizeof(fonts) / sizeof(fonts[0]); -ASM::ASM(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { +ASM::ASM(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController) + : dateTimeController(dateTimeController), statusIcons(batteryController, bleController) { this->code = out_bin; this->code_len = out_bin_len; @@ -309,6 +310,13 @@ void ASM::run() { lv_obj_realign(pop(LvglObject)->obj); break; + case ShowStatusIcons: + if (!showingStatusIcons) { + showingStatusIcons = true; + statusIcons.Create(); + } + break; + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; @@ -319,6 +327,10 @@ void ASM::run() { void ASM::Refresh() { run(); + + if (showingStatusIcons) { + statusIcons.Update(); + } } void ASM::asm_assert(bool condition) { diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 2af98c77..d7b7c161 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -3,6 +3,7 @@ #include "displayapp/screens/Screen.h" #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" +#include "displayapp/widgets/StatusIcons.h" #include "components/datetime/DateTimeController.h" #include "Symbols.h" @@ -15,7 +16,7 @@ namespace Pinetime { namespace Screens { class ASM : public Screen { public: - ASM(Controllers::DateTime&); + ASM(Controllers::DateTime&, const Controllers::Battery&, const Controllers::Ble&); ~ASM(); void Refresh() override; @@ -104,6 +105,7 @@ namespace Pinetime { StartPeriodicRefresh, StopPeriodicRefresh, + ShowStatusIcons, SetLabelText, SetObjectAlign, @@ -156,6 +158,9 @@ namespace Pinetime { lv_task_t* taskRefresh = nullptr; Controllers::DateTime& dateTimeController; + Widgets::StatusIcons statusIcons; + + bool showingStatusIcons = false; void run(); void asm_assert(bool condition); @@ -199,7 +204,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::eye; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::ASM(controllers.dateTimeController); + return new Screens::ASM(controllers.dateTimeController, controllers.batteryController, controllers.bleController); }; }; }; From 408f4bd6dcbf93fac459c1947678e5dd2608a468 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 02:11:40 +0000 Subject: [PATCH 19/36] Ensure division order --- src/displayapp/screens/ASM.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 0926da39..c1e0e4d2 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -195,10 +195,9 @@ void ASM::run() { break; } - case Add: { + case Add: push(std::make_shared(pop_uint32() + pop_uint32())); break; - } case Subtract: push(std::make_shared(pop_uint32() - pop_uint32())); @@ -208,9 +207,12 @@ void ASM::run() { push(std::make_shared(pop_uint32() * pop_uint32())); break; - case Divide: - push(std::make_shared(pop_uint32() / pop_uint32())); + case Divide: { + uint32_t b = pop_uint32(); + uint32_t a = pop_uint32(); + push(std::make_shared(a / b)); break; + } case GrowString: { auto len = pop_uint32(); From d6b51579e50c024de0da65546173f8c34f1b8105 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 11:14:14 +0000 Subject: [PATCH 20/36] Add Equals and Negate --- src/displayapp/screens/ASM.cpp | 11 +++++++++++ src/displayapp/screens/ASM.h | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index c1e0e4d2..973cd389 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -319,6 +319,17 @@ void ASM::run() { } break; + case Equals: { + auto b = pop(); + auto a = pop(); + push(std::make_shared(a.get()->equals(b.get()) ? 1 : 0)); + break; + } + + case Negate: + push(std::make_shared(pop().get()->isTruthy() ? 0 : 1)); + break; + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index d7b7c161..9c4fd20c 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -31,6 +31,8 @@ namespace Pinetime { // TODO: Use fancy C++ type stuff struct Value { virtual DataType type() = 0; + virtual bool equals(Value* other) = 0; + virtual bool isTruthy() = 0; }; struct ValueInteger : public Value { @@ -42,6 +44,14 @@ namespace Pinetime { DataType type() override { return Integer; } + + bool equals(Value* other) override { + return other->type() == Integer && i == static_cast(other)->i; + } + + bool isTruthy() override { + return i != 0; + } }; struct ValueString : public Value { @@ -58,6 +68,14 @@ namespace Pinetime { DataType type() override { return String; } + + bool equals(Value* other) override { + return other->type() == String && strcmp(str, static_cast(other)->str) == 0; + } + + bool isTruthy() override { + return capacity > 0 && str[0] != '\0'; + } }; struct ValueLvglObject : public Value { @@ -73,6 +91,14 @@ namespace Pinetime { DataType type() override { return LvglObject; } + + bool equals(Value* other) override { + return other->type() == LvglObject && obj == static_cast(other)->obj; + } + + bool isTruthy() override { + return obj != nullptr; + } }; struct ValueDateTime : public Value { @@ -86,6 +112,14 @@ namespace Pinetime { DataType type() override { return DateTime; } + + bool equals(Value* other) override { + return other->type() == DateTime && time == static_cast(other)->time; + } + + bool isTruthy() override { + return true; + } }; enum OpcodeShort : uint8_t { @@ -121,6 +155,8 @@ namespace Pinetime { Subtract, Multiply, Divide, + Equals, + Negate, GrowString, ClearString, From c9f22468ce1276af0405d6c0ea2a2f747ac1fca2 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 11:25:30 +0000 Subject: [PATCH 21/36] Use enum class --- src/displayapp/screens/ASM.cpp | 76 +++++++++++++++++----------------- src/displayapp/screens/ASM.h | 4 +- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 973cd389..32f112ff 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -43,7 +43,7 @@ void ASM::run() { } OpcodeShort opcode = static_cast(read_byte(pc)); - if (opcode & (1 << 7)) { + if (static_cast(opcode) & (1 << 7)) { // Long opcode OpcodeLong opcode = static_cast(read_u16(pc)); @@ -62,42 +62,42 @@ void ASM::run() { NRF_LOG_INFO("Short opcode: %d", opcode); switch (opcode) { - case WaitRefresh: + case OpcodeShort::WaitRefresh: return; - case Push0: + case OpcodeShort::Push0: push(std::make_shared(0)); break; - case PushU8: + case OpcodeShort::PushU8: push(std::make_shared(read_byte(pc))); pc++; break; - case PushU16: + case OpcodeShort::PushU16: push(std::make_shared(read_u16(pc))); pc += 2; break; - case PushU24: + case OpcodeShort::PushU24: push(std::make_shared(read_u24(pc))); pc += 3; break; - case PushU32: + case OpcodeShort::PushU32: push(std::make_shared(read_u32(pc))); pc += 4; break; - case PushEmptyString: + case OpcodeShort::PushEmptyString: push(std::make_shared(new char[1] {0}, 1)); break; - case Duplicate: + case OpcodeShort::Duplicate: push(stack[stack_pointer - 1]); break; - case LoadString: { + case OpcodeShort::LoadString: { uint32_t ptr = pop_uint32(); int length = read_byte(ptr); @@ -112,39 +112,39 @@ void ASM::run() { break; } - case StoreLocal: + case OpcodeShort::StoreLocal: locals[read_byte(pc++)] = pop(); break; - case LoadLocal: + case OpcodeShort::LoadLocal: push(locals[read_byte(pc++)]); break; - case Branch: + case OpcodeShort::Branch: pc = pop_uint32(); break; - case Call: { + case OpcodeShort::Call: { uint32_t next = pc; pc = pop_uint32(); push(std::make_shared(next)); break; } - case StartPeriodicRefresh: + case OpcodeShort::StartPeriodicRefresh: if (taskRefresh == nullptr) { taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } break; - case StopPeriodicRefresh: + case OpcodeShort::StopPeriodicRefresh: if (taskRefresh != nullptr) { lv_task_del(taskRefresh); taskRefresh = nullptr; } break; - case SetLabelText: { + case OpcodeShort::SetLabelText: { auto str = pop(String); auto obj = pop(LvglObject); @@ -152,11 +152,11 @@ void ASM::run() { break; } - case CreateLabel: + case OpcodeShort::CreateLabel: push(std::make_shared(lv_label_create(lv_scr_act(), NULL))); break; - case SetObjectAlign: { + case OpcodeShort::SetObjectAlign: { int16_t y = pop_uint32(); int16_t x = pop_uint32(); uint8_t align = pop_uint32(); @@ -165,24 +165,24 @@ void ASM::run() { break; } - case SetStyleLocalInt: - case SetStyleLocalFont: - case SetStyleLocalColor: { + case OpcodeShort::SetStyleLocalInt: + case OpcodeShort::SetStyleLocalFont: + case OpcodeShort::SetStyleLocalColor: { uint32_t value = pop_uint32(); uint32_t prop = pop_uint32(); uint32_t part = pop_uint32(); auto obj = pop(LvglObject); switch (opcode) { - case SetStyleLocalInt: + case OpcodeShort::SetStyleLocalInt: _lv_obj_set_style_local_int(obj->obj, part, prop, value); break; - case SetStyleLocalColor: + case OpcodeShort::SetStyleLocalColor: _lv_obj_set_style_local_color(obj->obj, part, prop, lv_color_hex(value)); break; - case SetStyleLocalFont: { + case OpcodeShort::SetStyleLocalFont: { if (value < num_fonts) { _lv_obj_set_style_local_ptr(obj->obj, part, prop, fonts[value]); } @@ -195,26 +195,26 @@ void ASM::run() { break; } - case Add: + case OpcodeShort::Add: push(std::make_shared(pop_uint32() + pop_uint32())); break; - case Subtract: + case OpcodeShort::Subtract: push(std::make_shared(pop_uint32() - pop_uint32())); break; - case Multiply: + case OpcodeShort::Multiply: push(std::make_shared(pop_uint32() * pop_uint32())); break; - case Divide: { + case OpcodeShort::Divide: { uint32_t b = pop_uint32(); uint32_t a = pop_uint32(); push(std::make_shared(a / b)); break; } - case GrowString: { + case OpcodeShort::GrowString: { auto len = pop_uint32(); auto str = pop(String); @@ -228,7 +228,7 @@ void ASM::run() { break; } - case ClearString: { + case OpcodeShort::ClearString: { auto str = pop(String); if (str->capacity > 0) str->str[0] = '\0'; @@ -237,7 +237,7 @@ void ASM::run() { break; } - case Concat: { + case OpcodeShort::Concat: { auto b = pop(); auto a = pop(); @@ -278,7 +278,7 @@ void ASM::run() { break; } - case PushCurrentTime: { + case OpcodeShort::PushCurrentTime: { auto time = dateTimeController.CurrentDateTime(); std::tm tm { .tm_sec = dateTimeController.Seconds(), @@ -295,7 +295,7 @@ void ASM::run() { break; } - case FormatDateTime: { + case OpcodeShort::FormatDateTime: { auto fmt = pop(String); auto time = pop(DateTime); @@ -308,25 +308,25 @@ void ASM::run() { break; } - case RealignObject: + case OpcodeShort::RealignObject: lv_obj_realign(pop(LvglObject)->obj); break; - case ShowStatusIcons: + case OpcodeShort::ShowStatusIcons: if (!showingStatusIcons) { showingStatusIcons = true; statusIcons.Create(); } break; - case Equals: { + case OpcodeShort::Equals: { auto b = pop(); auto a = pop(); push(std::make_shared(a.get()->equals(b.get()) ? 1 : 0)); break; } - case Negate: + case OpcodeShort::Negate: push(std::make_shared(pop().get()->isTruthy() ? 0 : 1)); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 9c4fd20c..a903a91e 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -122,7 +122,7 @@ namespace Pinetime { } }; - enum OpcodeShort : uint8_t { + enum class OpcodeShort : uint8_t { StoreLocal, LoadLocal, Branch, @@ -164,7 +164,7 @@ namespace Pinetime { FormatDateTime }; - enum OpcodeLong : uint16_t {}; + enum class OpcodeLong : uint16_t {}; uint8_t read_byte(size_t pos) { return code[pos]; From 46c25e83bca4da71cb1296cbb512c97fc4c00353 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 12:49:30 +0000 Subject: [PATCH 22/36] Add asm_assert macro --- src/displayapp/screens/ASM.cpp | 6 +++++- src/displayapp/screens/ASM.h | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 32f112ff..dea2653d 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -346,9 +346,13 @@ void ASM::Refresh() { } } -void ASM::asm_assert(bool condition) { +void ASM::_asm_assert(bool condition, const char* msg) { if (!condition) { // TODO: Handle better + + if (msg) + NRF_LOG_ERROR("Assertion failed: %s", msg); + for (;;) { } } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index a903a91e..f5862dff 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -11,6 +11,14 @@ #include #include +#if DEBUG + #define STRINGIZE_DETAIL(x) #x + #define STRINGIZE(x) STRINGIZE_DETAIL(x) + #define asm_assert(condition) _asm_assert(condition, __FILE__ ":" STRINGIZE(__LINE__) " " #condition) +#else + #define asm_assert(condition) _asm_assert(condition, NULL) +#endif + namespace Pinetime { namespace Applications { namespace Screens { @@ -199,7 +207,7 @@ namespace Pinetime { bool showingStatusIcons = false; void run(); - void asm_assert(bool condition); + void _asm_assert(bool condition, const char* msg); std::shared_ptr pop() { asm_assert(stack_pointer > 0); From 3556687e2e9df1c21155eee3cb634a73fc5ff124 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 12:49:58 +0000 Subject: [PATCH 23/36] Read program from external flash --- src/displayapp/screens/ASM.cpp | 30 +++++++++++++++++++++++------- src/displayapp/screens/ASM.h | 29 +++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index dea2653d..d1f9e387 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -4,8 +4,6 @@ #include #include -#include "asm_data.h" - using namespace Pinetime::Applications::Screens; constexpr lv_font_t* fonts[] = { @@ -19,10 +17,16 @@ constexpr lv_font_t* fonts[] = { }; constexpr int num_fonts = sizeof(fonts) / sizeof(fonts[0]); -ASM::ASM(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController) - : dateTimeController(dateTimeController), statusIcons(batteryController, bleController) { - this->code = out_bin; - this->code_len = out_bin_len; +ASM::ASM(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::FS& fsController) + : dateTimeController(dateTimeController), statusIcons(batteryController, bleController), fs(fsController) { + + int result = fsController.FileOpen(&file, "program.bin", LFS_O_RDONLY); + asm_assert(result >= 0); + + populate_cache(0); Refresh(); } @@ -32,13 +36,25 @@ ASM::~ASM() { lv_task_del(taskRefresh); } + fs.FileClose(&file); + // We don't need to clean the screen since all objects are deleted when their shared_ptr is dropped // lv_obj_clean(lv_scr_act()); } +void ASM::populate_cache(size_t pos) { + int result = fs.FileSeek(&file, pos); + asm_assert(result >= 0); + + result = fs.FileRead(&file, cache, cache_size); + asm_assert(result >= 0); + + cache_start = pos; +} + void ASM::run() { for (;;) { - if (pc >= code_len) { + if (pc >= program_size) { break; } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index f5862dff..bc078012 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -24,7 +24,7 @@ namespace Pinetime { namespace Screens { class ASM : public Screen { public: - ASM(Controllers::DateTime&, const Controllers::Battery&, const Controllers::Ble&); + ASM(Controllers::DateTime&, const Controllers::Battery&, const Controllers::Ble&, Controllers::FS&); ~ASM(); void Refresh() override; @@ -33,6 +33,7 @@ namespace Pinetime { static constexpr int num_slots = 16; static constexpr int max_locals = 16; static constexpr int stack_size = 32; + static constexpr int cache_size = 16; enum DataType : uint8_t { Integer, String, LvglObject, DateTime }; @@ -174,24 +175,32 @@ namespace Pinetime { enum class OpcodeLong : uint16_t {}; + void populate_cache(size_t pos); + uint8_t read_byte(size_t pos) { - return code[pos]; + if (pos < cache_start || pos >= cache_start + cache_size) { + populate_cache(pos); + } + + return cache[pos - cache_start]; } uint16_t read_u16(size_t pos) { - return static_cast(code[pos + 1] << 8 | code[pos]); + return static_cast(read_byte(pos + 1) << 8 | read_byte(pos)); } uint32_t read_u24(size_t pos) { - return static_cast(code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); + return static_cast(read_byte(pos + 2) << 16 | read_byte(pos + 1) << 8 | read_byte(pos)); } uint32_t read_u32(size_t pos) { - return static_cast(code[pos + 3] << 24 | code[pos + 2] << 16 | code[pos + 1] << 8 | code[pos]); + return static_cast(read_byte(pos + 3) << 24 | read_byte(pos + 2) << 16 | read_byte(pos + 1) << 8 | read_byte(pos)); } - uint8_t* code; - size_t code_len; + lfs_file_t file; + uint8_t cache[cache_size]; + size_t cache_start; + size_t program_size; size_t pc = 0; std::shared_ptr locals[max_locals] = {}; @@ -203,6 +212,7 @@ namespace Pinetime { Controllers::DateTime& dateTimeController; Widgets::StatusIcons statusIcons; + Controllers::FS& fs; bool showingStatusIcons = false; @@ -248,7 +258,10 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::eye; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::ASM(controllers.dateTimeController, controllers.batteryController, controllers.bleController); + return new Screens::ASM(controllers.dateTimeController, + controllers.batteryController, + controllers.bleController, + controllers.filesystem); }; }; }; From 9bc75c5d3cde184bda485809890f9a0d70dd7462 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 13:01:27 +0000 Subject: [PATCH 24/36] Add FS::FileSeek method with whence --- src/components/fs/FS.cpp | 6 +++++- src/components/fs/FS.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/fs/FS.cpp b/src/components/fs/FS.cpp index 95b40824..6064a5fa 100644 --- a/src/components/fs/FS.cpp +++ b/src/components/fs/FS.cpp @@ -70,7 +70,11 @@ int FS::FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size) { } int FS::FileSeek(lfs_file_t* file_p, uint32_t pos) { - return lfs_file_seek(&lfs, file_p, pos, LFS_SEEK_SET); + return FileSeek(file_p, pos, LFS_SEEK_SET); +} + +int FS::FileSeek(lfs_file_t* file_p, uint32_t pos, int whence) { + return lfs_file_seek(&lfs, file_p, pos, whence); } int FS::FileDelete(const char* fileName) { diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h index aba30509..9daa1d39 100644 --- a/src/components/fs/FS.h +++ b/src/components/fs/FS.h @@ -17,6 +17,7 @@ namespace Pinetime { int FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size); int FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size); int FileSeek(lfs_file_t* file_p, uint32_t pos); + int FileSeek(lfs_file_t* file_p, uint32_t pos, int whence); int FileDelete(const char* fileName); From c5183c0cba07e4b164e0d985d67759332e602699 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 13:02:32 +0000 Subject: [PATCH 25/36] Find program size --- src/displayapp/screens/ASM.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index d1f9e387..ad8f5ff8 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -26,6 +26,9 @@ ASM::ASM(Controllers::DateTime& dateTimeController, int result = fsController.FileOpen(&file, "program.bin", LFS_O_RDONLY); asm_assert(result >= 0); + program_size = fsController.FileSeek(&file, 0, LFS_SEEK_END); + fsController.FileSeek(&file, 0, LFS_SEEK_SET); + populate_cache(0); Refresh(); @@ -54,9 +57,7 @@ void ASM::populate_cache(size_t pos) { void ASM::run() { for (;;) { - if (pc >= program_size) { - break; - } + asm_assert(pc < program_size); OpcodeShort opcode = static_cast(read_byte(pc)); if (static_cast(opcode) & (1 << 7)) { From 06fffa6df29d126a97c3db9cec51152ac3c827e2 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 13:51:44 +0000 Subject: [PATCH 26/36] Destroy status icons on exit --- src/displayapp/screens/ASM.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index ad8f5ff8..6f25baf3 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -38,6 +38,9 @@ ASM::~ASM() { if (taskRefresh != nullptr) { lv_task_del(taskRefresh); } + if (showingStatusIcons) { + lv_obj_del(statusIcons.GetObject()); + } fs.FileClose(&file); From b7cdd481570d65c0f2c35db5efa2c89e7ff5bc5f Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 19:39:22 +0000 Subject: [PATCH 27/36] Add buttons and event handlers --- src/displayapp/screens/ASM.cpp | 64 ++++++++++++++++++++++++++++++++-- src/displayapp/screens/ASM.h | 8 ++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 6f25baf3..b6a4ba9d 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -17,6 +17,18 @@ constexpr lv_font_t* fonts[] = { }; constexpr int num_fonts = sizeof(fonts) / sizeof(fonts[0]); +constexpr uint32_t handler_return_pc_mark = 1 << 31; + +struct CallbackInfo { + ASM* instance; + uint32_t callback_pc; +}; + +static void event_handler(lv_obj_t* obj, lv_event_t event) { + CallbackInfo* cbInfo = static_cast(lv_obj_get_user_data(obj)); + cbInfo->instance->OnObjectEvent(obj, event); +} + ASM::ASM(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, @@ -117,6 +129,10 @@ void ASM::run() { push(stack[stack_pointer - 1]); break; + case OpcodeShort::Pop: + pop(); + break; + case OpcodeShort::LoadString: { uint32_t ptr = pop_uint32(); @@ -140,9 +156,17 @@ void ASM::run() { push(locals[read_byte(pc++)]); break; - case OpcodeShort::Branch: - pc = pop_uint32(); + case OpcodeShort::Branch: { + uint32_t value = pop_uint32(); + + if ((value & handler_return_pc_mark) != 0) { + pc = value & ~handler_return_pc_mark; + return; + } + + pc = value; break; + } case OpcodeShort::Call: { uint32_t next = pc; @@ -176,6 +200,10 @@ void ASM::run() { push(std::make_shared(lv_label_create(lv_scr_act(), NULL))); break; + case OpcodeShort::CreateButton: + push(std::make_shared(lv_btn_create(lv_scr_act(), NULL))); + break; + case OpcodeShort::SetObjectAlign: { int16_t y = pop_uint32(); int16_t x = pop_uint32(); @@ -185,6 +213,14 @@ void ASM::run() { break; } + case OpcodeShort::SetObjectSize: { + int16_t h = pop_uint32(); + int16_t w = pop_uint32(); + auto obj = pop(LvglObject); + lv_obj_set_size(obj->obj, w, h); + break; + } + case OpcodeShort::SetStyleLocalInt: case OpcodeShort::SetStyleLocalFont: case OpcodeShort::SetStyleLocalColor: { @@ -215,6 +251,16 @@ void ASM::run() { break; } + case OpcodeShort::SetEventHandler: { + uint32_t cb_pc = pop_uint32(); + auto obj = pop(LvglObject); + CallbackInfo* cb = new CallbackInfo {this, cb_pc}; + + lv_obj_set_user_data(obj->obj, cb); + lv_obj_set_event_cb(obj->obj, event_handler); + break; + } + case OpcodeShort::Add: push(std::make_shared(pop_uint32() + pop_uint32())); break; @@ -377,3 +423,17 @@ void ASM::_asm_assert(bool condition, const char* msg) { } } } + +void ASM::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { + if (event != LV_EVENT_CLICKED) + return; + + CallbackInfo* cb = static_cast(lv_obj_get_user_data(obj)); + + if (cb) { + push(std::make_shared(pc | handler_return_pc_mark)); + pc = cb->callback_pc; + + run(); + } +} diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index bc078012..751fd3e0 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -29,6 +29,8 @@ namespace Pinetime { void Refresh() override; + void OnObjectEvent(lv_obj_t* obj, lv_event_t event); + private: static constexpr int num_slots = 16; static constexpr int max_locals = 16; @@ -144,19 +146,23 @@ namespace Pinetime { PushEmptyString, PushCurrentTime, Duplicate, + Pop, LoadString, StartPeriodicRefresh, StopPeriodicRefresh, ShowStatusIcons, + CreateLabel, + CreateButton, SetLabelText, SetObjectAlign, - CreateLabel, + SetObjectSize, SetStyleLocalInt, SetStyleLocalColor, SetStyleLocalOpa, SetStyleLocalFont, + SetEventHandler, RealignObject, WaitRefresh, From b55b59ea13dc3034d3c781629e671408282eaa81 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 20:06:33 +0000 Subject: [PATCH 28/36] Set object parent --- src/displayapp/screens/ASM.cpp | 7 +++++++ src/displayapp/screens/ASM.h | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index b6a4ba9d..a12ef9ff 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -221,6 +221,13 @@ void ASM::run() { break; } + case OpcodeShort::SetObjectParent: { + auto parent = pop(LvglObject); + auto child = pop(LvglObject); + lv_obj_set_parent(child->obj, parent->obj); + break; + } + case OpcodeShort::SetStyleLocalInt: case OpcodeShort::SetStyleLocalFont: case OpcodeShort::SetStyleLocalColor: { diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index 751fd3e0..c176dbde 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -158,6 +158,7 @@ namespace Pinetime { SetLabelText, SetObjectAlign, SetObjectSize, + SetObjectParent, SetStyleLocalInt, SetStyleLocalColor, SetStyleLocalOpa, @@ -237,11 +238,11 @@ namespace Pinetime { } template - std::shared_ptr pop(DataType type) + std::shared_ptr pop(DataType wantType) requires(std::is_base_of_v) { auto v = pop(); - asm_assert(v->type() == type); + asm_assert(v->type() == wantType); return std::static_pointer_cast(v); } From ff4607c6daa669db9e25308474dcd3c515b76d9d Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 21:37:23 +0000 Subject: [PATCH 29/36] Add PushCurrentTicks --- src/displayapp/screens/ASM.cpp | 6 +++++- src/displayapp/screens/ASM.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index a12ef9ff..9b3bcf23 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -351,7 +351,7 @@ void ASM::run() { break; } - case OpcodeShort::PushCurrentTime: { + case OpcodeShort::PushCurrentDateTime: { auto time = dateTimeController.CurrentDateTime(); std::tm tm { .tm_sec = dateTimeController.Seconds(), @@ -368,6 +368,10 @@ void ASM::run() { break; } + case OpcodeShort::PushCurrentTicks: + push(std::make_shared((xTaskGetTickCount() * configTICK_RATE_HZ) / 1000)); + break; + case OpcodeShort::FormatDateTime: { auto fmt = pop(String); auto time = pop(DateTime); diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index c176dbde..e22ad9a5 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -144,7 +144,8 @@ namespace Pinetime { PushU24, PushU32, PushEmptyString, - PushCurrentTime, + PushCurrentDateTime, + PushCurrentTicks, Duplicate, Pop, LoadString, From 9bc6c820e9c99eb3e1954b122450fe7841b54a17 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 8 Jul 2024 21:37:32 +0000 Subject: [PATCH 30/36] Tweaks --- src/displayapp/screens/ASM.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 9b3bcf23..05565f14 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -38,7 +38,9 @@ ASM::ASM(Controllers::DateTime& dateTimeController, int result = fsController.FileOpen(&file, "program.bin", LFS_O_RDONLY); asm_assert(result >= 0); - program_size = fsController.FileSeek(&file, 0, LFS_SEEK_END); + result = fsController.FileSeek(&file, 0, LFS_SEEK_END); + asm_assert(result >= 0); + program_size = result; fsController.FileSeek(&file, 0, LFS_SEEK_SET); populate_cache(0); @@ -71,9 +73,7 @@ void ASM::populate_cache(size_t pos) { } void ASM::run() { - for (;;) { - asm_assert(pc < program_size); - + while (pc < program_size) { OpcodeShort opcode = static_cast(read_byte(pc)); if (static_cast(opcode) & (1 << 7)) { // Long opcode @@ -292,7 +292,6 @@ void ASM::run() { auto str = pop(String); size_t new_cap = len + str->capacity; - asm_assert(new_cap >= str->capacity); char* new_str = new char[new_cap]; memcpy(new_str, str->str, str->capacity); @@ -306,7 +305,7 @@ void ASM::run() { if (str->capacity > 0) str->str[0] = '\0'; - push(std::make_shared(str->str, str->capacity)); + push(str); break; } @@ -338,12 +337,19 @@ void ASM::run() { auto aString = static_cast(a.get()); auto bInt = static_cast(b.get()); - if (bInt) { - size_t cap = strlen(aString->str) + 12 + 1; - char* s = new char[cap]; - snprintf(s, cap, "%s%lu", aString->str, bInt->i); + size_t aLen = strlen(aString->str); + size_t need_cap = aLen + 12 + 1; - push(std::make_shared(s, cap)); + if (aString->capacity - aLen >= need_cap) { + snprintf(aString->str + aLen, aString->capacity - aLen, "%lu", bInt->i); + + push(a); + } else { + char* s = new char[need_cap]; + memcpy(s, aString->str, aLen); + snprintf(s + aLen, need_cap - aLen, "%lu", bInt->i); + + push(std::make_shared(s, need_cap)); } } else { asm_assert(false); From 700e9a4f6d95f1ade08e45fa59201a52af76f3d8 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 9 Jul 2024 20:53:29 +0000 Subject: [PATCH 31/36] Store status icons in unique_ptr --- src/displayapp/screens/ASM.cpp | 16 ++++++++-------- src/displayapp/screens/ASM.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 05565f14..8bc924b6 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -33,7 +33,7 @@ ASM::ASM(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, Controllers::FS& fsController) - : dateTimeController(dateTimeController), statusIcons(batteryController, bleController), fs(fsController) { + : dateTimeController(dateTimeController), batteryController(batteryController), bleController(bleController), fs(fsController) { int result = fsController.FileOpen(&file, "program.bin", LFS_O_RDONLY); asm_assert(result >= 0); @@ -52,8 +52,8 @@ ASM::~ASM() { if (taskRefresh != nullptr) { lv_task_del(taskRefresh); } - if (showingStatusIcons) { - lv_obj_del(statusIcons.GetObject()); + if (statusIcons) { + lv_obj_del(statusIcons->GetObject()); } fs.FileClose(&file); @@ -396,9 +396,9 @@ void ASM::run() { break; case OpcodeShort::ShowStatusIcons: - if (!showingStatusIcons) { - showingStatusIcons = true; - statusIcons.Create(); + if (!statusIcons) { + statusIcons = std::make_unique(batteryController, bleController); + statusIcons->Create(); } break; @@ -424,8 +424,8 @@ void ASM::run() { void ASM::Refresh() { run(); - if (showingStatusIcons) { - statusIcons.Update(); + if (statusIcons) { + statusIcons->Update(); } } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index e22ad9a5..b30a614c 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -219,10 +219,10 @@ namespace Pinetime { lv_task_t* taskRefresh = nullptr; Controllers::DateTime& dateTimeController; - Widgets::StatusIcons statusIcons; + const Controllers::Battery& batteryController; + const Controllers::Ble& bleController; Controllers::FS& fs; - - bool showingStatusIcons = false; + std::unique_ptr statusIcons; void run(); void _asm_assert(bool condition, const char* msg); From 47522994f5c6660bd111e8b50c0046450b75a0bf Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 9 Jul 2024 21:19:29 +0000 Subject: [PATCH 32/36] Add arcs; push object when setting property --- src/displayapp/screens/ASM.cpp | 61 ++++++++++++++++++++++++++++++++++ src/displayapp/screens/ASM.h | 7 ++++ 2 files changed, 68 insertions(+) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 8bc924b6..f04c5cbe 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -193,6 +193,57 @@ void ASM::run() { auto obj = pop(LvglObject); lv_label_set_text(obj->obj, str->str); + push(obj); + break; + } + + case OpcodeShort::SetArcRange: { + uint32_t max = pop_uint32(); + uint32_t min = pop_uint32(); + auto obj = pop(LvglObject); + lv_arc_set_range(obj->obj, min, max); + push(obj); + break; + } + + case OpcodeShort::SetArcRotation: { + uint32_t rot = pop_uint32(); + auto obj = pop(LvglObject); + lv_arc_set_rotation(obj->obj, rot); + push(obj); + break; + } + + case OpcodeShort::SetArcBgAngles: { + uint32_t end = pop_uint32(); + uint32_t start = pop_uint32(); + auto obj = pop(LvglObject); + lv_arc_set_bg_angles(obj->obj, start, end); + push(obj); + break; + } + + case OpcodeShort::SetArcAdjustable: { + auto val = pop(); + auto obj = pop(LvglObject); + lv_arc_set_adjustable(obj->obj, val->isTruthy()); + push(obj); + break; + } + + case OpcodeShort::SetArcStartAngle: { + uint32_t angle = pop_uint32(); + auto obj = pop(LvglObject); + lv_arc_set_start_angle(obj->obj, angle); + push(obj); + break; + } + + case OpcodeShort::SetArcValue: { + uint32_t value = pop_uint32(); + auto obj = pop(LvglObject); + lv_arc_set_value(obj->obj, value); + push(obj); break; } @@ -204,12 +255,17 @@ void ASM::run() { push(std::make_shared(lv_btn_create(lv_scr_act(), NULL))); break; + case OpcodeShort::CreateArc: + push(std::make_shared(lv_arc_create(lv_scr_act(), NULL))); + break; + case OpcodeShort::SetObjectAlign: { int16_t y = pop_uint32(); int16_t x = pop_uint32(); uint8_t align = pop_uint32(); auto obj = pop(LvglObject); lv_obj_align(obj->obj, lv_scr_act(), align, x, y); + push(obj); break; } @@ -218,6 +274,7 @@ void ASM::run() { int16_t w = pop_uint32(); auto obj = pop(LvglObject); lv_obj_set_size(obj->obj, w, h); + push(obj); break; } @@ -225,6 +282,7 @@ void ASM::run() { auto parent = pop(LvglObject); auto child = pop(LvglObject); lv_obj_set_parent(child->obj, parent->obj); + push(child); break; } @@ -255,6 +313,8 @@ void ASM::run() { default: break; } + + push(obj); break; } @@ -265,6 +325,7 @@ void ASM::run() { lv_obj_set_user_data(obj->obj, cb); lv_obj_set_event_cb(obj->obj, event_handler); + push(obj); break; } diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index b30a614c..c39b88bc 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -156,7 +156,14 @@ namespace Pinetime { CreateLabel, CreateButton, + CreateArc, SetLabelText, + SetArcRange, + SetArcRotation, + SetArcBgAngles, + SetArcAdjustable, + SetArcStartAngle, + SetArcValue, SetObjectAlign, SetObjectSize, SetObjectParent, From 86c8fd882d3ff98d6ce2ae395799ac82a0021f8c Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 9 Jul 2024 22:26:26 +0000 Subject: [PATCH 33/36] Get time components --- src/displayapp/screens/ASM.cpp | 18 ++++++++++++++++++ src/displayapp/screens/ASM.h | 6 +++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index f04c5cbe..c82ef0a4 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -474,6 +474,24 @@ void ASM::run() { push(std::make_shared(pop().get()->isTruthy() ? 0 : 1)); break; + case OpcodeShort::GetDateTimeHour: { + auto time = pop(DateTime); + push(std::make_shared(time->tm.tm_hour)); + break; + } + + case OpcodeShort::GetDateTimeMinute: { + auto time = pop(DateTime); + push(std::make_shared(time->tm.tm_min)); + break; + } + + case OpcodeShort::GetDateTimeSecond: { + auto time = pop(DateTime); + push(std::make_shared(time->tm.tm_sec)); + break; + } + default: NRF_LOG_ERROR("Unknown opcode: 0x%02X", opcode); break; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index c39b88bc..ce19fb8b 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -185,7 +185,11 @@ namespace Pinetime { GrowString, ClearString, Concat, - FormatDateTime + FormatDateTime, + + GetDateTimeHour, + GetDateTimeMinute, + GetDateTimeSecond }; enum class OpcodeLong : uint16_t {}; From 23b1bfcb9afdf2020842726d9ed79d812aa2e1d0 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 9 Jul 2024 23:01:55 +0000 Subject: [PATCH 34/36] Remove logs --- src/displayapp/screens/ASM.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index c82ef0a4..aa5b9a66 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -79,8 +79,6 @@ void ASM::run() { // Long opcode OpcodeLong opcode = static_cast(read_u16(pc)); - NRF_LOG_INFO("Long opcode: %d", opcode); - pc += 2; switch (opcode) { @@ -92,8 +90,6 @@ void ASM::run() { pc++; NRF_LOG_INFO("Short opcode: %d", opcode); - - switch (opcode) { case OpcodeShort::WaitRefresh: return; From c59e29a5c842068b2186ef8ae4d3476da4bf00e4 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 9 Jul 2024 23:02:14 +0000 Subject: [PATCH 35/36] Add conditionals --- src/displayapp/screens/ASM.cpp | 50 +++++++++++++++++++++++++++------- src/displayapp/screens/ASM.h | 50 ++++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index aa5b9a66..425d5957 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -89,7 +89,7 @@ void ASM::run() { } else { pc++; - NRF_LOG_INFO("Short opcode: %d", opcode); + switch (opcode) { case OpcodeShort::WaitRefresh: return; @@ -153,14 +153,17 @@ void ASM::run() { break; case OpcodeShort::Branch: { - uint32_t value = pop_uint32(); - - if ((value & handler_return_pc_mark) != 0) { - pc = value & ~handler_return_pc_mark; + if (doBranch(pop_uint32())) return; - } + break; + } - pc = value; + case OpcodeShort::BranchIfTrue: { + uint32_t to = pop_uint32(); + auto cond = pop(); + + if (cond->isTruthy() && doBranch(to)) + return; break; } @@ -329,9 +332,12 @@ void ASM::run() { push(std::make_shared(pop_uint32() + pop_uint32())); break; - case OpcodeShort::Subtract: - push(std::make_shared(pop_uint32() - pop_uint32())); + case OpcodeShort::Subtract: { + uint32_t b = pop_uint32(); + uint32_t a = pop_uint32(); + push(std::make_shared(a - b)); break; + } case OpcodeShort::Multiply: push(std::make_shared(pop_uint32() * pop_uint32())); @@ -462,7 +468,21 @@ void ASM::run() { case OpcodeShort::Equals: { auto b = pop(); auto a = pop(); - push(std::make_shared(a.get()->equals(b.get()) ? 1 : 0)); + push(std::make_shared(a.get()->compare(b.get()) == 0 ? 1 : 0)); + break; + } + + case OpcodeShort::Greater: { + auto b = pop(); + auto a = pop(); + push(std::make_shared(a.get()->compare(b.get()) > 0 ? 1 : 0)); + break; + } + + case OpcodeShort::Lesser: { + auto b = pop(); + auto a = pop(); + push(std::make_shared(a.get()->compare(b.get()) < 0 ? 1 : 0)); break; } @@ -516,6 +536,16 @@ void ASM::_asm_assert(bool condition, const char* msg) { } } +bool ASM::doBranch(uint32_t to) { + if ((to & handler_return_pc_mark) != 0) { + pc = to & ~handler_return_pc_mark; + return true; + } + + pc = to; + return false; +} + void ASM::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { if (event != LV_EVENT_CLICKED) return; diff --git a/src/displayapp/screens/ASM.h b/src/displayapp/screens/ASM.h index ce19fb8b..ae257f29 100644 --- a/src/displayapp/screens/ASM.h +++ b/src/displayapp/screens/ASM.h @@ -42,7 +42,7 @@ namespace Pinetime { // TODO: Use fancy C++ type stuff struct Value { virtual DataType type() = 0; - virtual bool equals(Value* other) = 0; + virtual int compare(Value* other) = 0; virtual bool isTruthy() = 0; }; @@ -56,8 +56,20 @@ namespace Pinetime { return Integer; } - bool equals(Value* other) override { - return other->type() == Integer && i == static_cast(other)->i; + int compare(Value* other) override { + if (other->type() != Integer) { + return -1; + } + + auto otherInt = static_cast(other)->i; + + if (i < otherInt) { + return -1; + } else if (i > otherInt) { + return 1; + } + + return 0; } bool isTruthy() override { @@ -80,8 +92,12 @@ namespace Pinetime { return String; } - bool equals(Value* other) override { - return other->type() == String && strcmp(str, static_cast(other)->str) == 0; + int compare(Value* other) override { + if (other->type() != String) { + return -1; + } + + return strcmp(str, static_cast(other)->str); } bool isTruthy() override { @@ -103,8 +119,8 @@ namespace Pinetime { return LvglObject; } - bool equals(Value* other) override { - return other->type() == LvglObject && obj == static_cast(other)->obj; + int compare(Value*) override { + return -1; } bool isTruthy() override { @@ -124,8 +140,20 @@ namespace Pinetime { return DateTime; } - bool equals(Value* other) override { - return other->type() == DateTime && time == static_cast(other)->time; + int compare(Value* other) override { + if (other->type() != DateTime) { + return -1; + } + + auto otherTime = static_cast(other)->time; + + if (time < otherTime) { + return -1; + } else if (time > otherTime) { + return 1; + } + + return 0; } bool isTruthy() override { @@ -137,6 +165,7 @@ namespace Pinetime { StoreLocal, LoadLocal, Branch, + BranchIfTrue, Call, Push0, PushU8, @@ -180,6 +209,8 @@ namespace Pinetime { Multiply, Divide, Equals, + Greater, + Lesser, Negate, GrowString, @@ -237,6 +268,7 @@ namespace Pinetime { void run(); void _asm_assert(bool condition, const char* msg); + bool doBranch(uint32_t to); std::shared_ptr pop() { asm_assert(stack_pointer > 0); From 21c3b1ebb05c42362a3269406dd60289cfaf5d74 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 9 Jul 2024 23:03:43 +0000 Subject: [PATCH 36/36] Use stop variable instead of return --- src/displayapp/screens/ASM.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/ASM.cpp b/src/displayapp/screens/ASM.cpp index 425d5957..5c5a1302 100644 --- a/src/displayapp/screens/ASM.cpp +++ b/src/displayapp/screens/ASM.cpp @@ -73,7 +73,9 @@ void ASM::populate_cache(size_t pos) { } void ASM::run() { - while (pc < program_size) { + bool stop = false; + + while (!stop && pc < program_size) { OpcodeShort opcode = static_cast(read_byte(pc)); if (static_cast(opcode) & (1 << 7)) { // Long opcode @@ -91,7 +93,8 @@ void ASM::run() { switch (opcode) { case OpcodeShort::WaitRefresh: - return; + stop = true; + break; case OpcodeShort::Push0: push(std::make_shared(0)); @@ -154,7 +157,7 @@ void ASM::run() { case OpcodeShort::Branch: { if (doBranch(pop_uint32())) - return; + stop = true; break; } @@ -163,7 +166,7 @@ void ASM::run() { auto cond = pop(); if (cond->isTruthy() && doBranch(to)) - return; + stop = true; break; }