aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorConfuSomu2021-06-20 16:50:35 -0400
committerConfuSomu2021-06-20 16:50:35 -0400
commita2eac6cd3e29ea0db579cabd644a93996daaeeec (patch)
treea303830e87a6273f471042c36399f6d67218decb
parent76418eebbe331d941caa229fb15abdaf07652137 (diff)
downloadpico-watch-a2eac6cd3e29ea0db579cabd644a93996daaeeec.tar
pico-watch-a2eac6cd3e29ea0db579cabd644a93996daaeeec.tar.gz
pico-watch-a2eac6cd3e29ea0db579cabd644a93996daaeeec.zip
Use an abstract class for apps
It is derived by each app. This allows finally allocating space for an app's variable when it is opened. On the other hand, currently, destruction of apps is not fully implemented. This commit is also done to save a snapshot of something that works.
-rw-r--r--apps/home_menu.cpp119
-rw-r--r--apps/home_menu.hpp29
-rw-r--r--base_app.hpp10
-rw-r--r--pico-watch.cpp58
4 files changed, 119 insertions, 97 deletions
diff --git a/apps/home_menu.cpp b/apps/home_menu.cpp
index 239ffda..a450c8f 100644
--- a/apps/home_menu.cpp
+++ b/apps/home_menu.cpp
@@ -8,80 +8,65 @@
extern void app_switch(int old_appid, int new_appid);
extern bool rtc_get_datetime(datetime_t *t);
-#define NUMBER_OF_APPS 3
-#define SIZE_APP_NAME 12
+void app_home_menu::title_str(char *buf, uint buf_size, const datetime_t *t) {
+ snprintf(buf,
+ buf_size,
+ "%d:%02d Home Menu",
+ t->hour,
+ t->min,
+ t->sec);
+};
-namespace app_home_menu {
- const char *APPS_NAME[NUMBER_OF_APPS] = {"Home", "Clock", "Settings"};
- int selected_app = 0;
- char display_app_name[SIZE_APP_NAME];
+void app_home_menu::show_title(Api *app_api) {
+ char datetime_buf[256];
+ char *datetime_str = &datetime_buf[0];
+ datetime_t t;
+ app_api->datetime_get(&t);
- void title_str(char *buf, uint buf_size, const datetime_t *t) {
- snprintf(buf,
- buf_size,
- "%d:%02d Home Menu",
- t->hour,
- t->min,
- t->sec);
- };
-
- void show_title(Api *app_api) {
- char datetime_buf[256];
- char *datetime_str = &datetime_buf[0];
- datetime_t t;
- app_api->datetime_get(&t);
-
- // title with time
- title_str(datetime_str, sizeof(datetime_buf), &t);
- app_api->gui_header_text((std::string)datetime_str);
- }
+ // title with time
+ title_str(datetime_str, sizeof(datetime_buf), &t);
+ app_api->gui_header_text((std::string)datetime_str);
+}
- // Rendering of app
- int render(Api *app_api) {
- show_title(app_api);
- app_api->display_write_string(0,5,3, display_app_name, FONT_12x16, 0, 1);
- return 0;
- }
+// Rendering of app
+int app_home_menu::render(Api *app_api) {
+ show_title(app_api);
+ app_api->display_write_string(0,5,3, display_app_name, FONT_12x16, 0, 1);
+ return 0;
+}
- // Example of how button inputs could be interpreted.
- // Drawing on screen should be done in the render function.
- int btnpressed(Api *app_api, uint gpio, unsigned long delta) {
- switch (gpio) {
- case BUTTON_SELECT:
- app_switch(0, selected_app);
- return 0;
- case BUTTON_DOWN:
- selected_app--;
- break;
- case BUTTON_UP:
- selected_app++;
- break;
- }
- if (selected_app > NUMBER_OF_APPS-1) {
- selected_app = NUMBER_OF_APPS-1;
- } else if (selected_app < 0) {
- selected_app = 0;
- }
- // Add spaces to avoid "ghost" characters from app names displayed before
- snprintf(display_app_name, SIZE_APP_NAME, "%s ", APPS_NAME[selected_app]);
- return 0;
+// Example of how button inputs could be interpreted.
+// Drawing on screen should be done in the render function.
+int app_home_menu::btnpressed(Api *app_api, uint gpio, unsigned long delta) {
+ switch (gpio) {
+ case BUTTON_SELECT:
+ app_switch(0, selected_app);
+ return 0;
+ case BUTTON_DOWN:
+ selected_app--;
+ break;
+ case BUTTON_UP:
+ selected_app++;
+ break;
}
-
- // Initlisation of the app.
- int init(Api *app_api) {
- app_api->performance_set(Api::perf_modes::LOW_POWER);
+ if (selected_app > NUMBER_OF_APPS-1) {
+ selected_app = NUMBER_OF_APPS-1;
+ } else if (selected_app < 0) {
selected_app = 0;
- snprintf(display_app_name, SIZE_APP_NAME, "%s", APPS_NAME[0]);
- return Api::app_init_return_status::OK;
}
+ // Add spaces to avoid "ghost" characters from app names displayed before
+ snprintf(display_app_name, SIZE_APP_NAME, "%s ", APPS_NAME[selected_app]);
+ return 0;
+}
- // Processor intensive operations and functions related to drawing to the screen should only be done when the app is in_foreground(=1). This function is only called when the app is init.
- int bgrefresh(Api *app_api, bool in_foreground) {
- return 1;
- }
+// Initlisation of the app.
+app_home_menu::app_home_menu(Api *app_api) {
+ app_api->performance_set(Api::perf_modes::LOW_POWER);
+ selected_app = 0;
+ snprintf(display_app_name, SIZE_APP_NAME, "%s", APPS_NAME[0]);
+}
- // Destruction of app, deinitlisation should be done here. This is only called if the app's APPS_DESTROY_ON_EXIT is set to 1. When it is not a "service" app.
- int destroy(Api *app_api) {
- return 0;
- }
+// Processor intensive operations and functions related to drawing to the screen should only be done when the app is in_foreground(=1). This function is only called when the app is init.
+int app_home_menu::bgrefresh(Api *app_api, bool in_foreground) {
+ return 1;
}
diff --git a/apps/home_menu.hpp b/apps/home_menu.hpp
index 78aed40..dce83e4 100644
--- a/apps/home_menu.hpp
+++ b/apps/home_menu.hpp
@@ -1,17 +1,26 @@
-#ifndef __HOME_MENU_H__
-#define __HOME_MENU_H__
+#pragma once
#include "pico/util/datetime.h"
#include "../oled/ss_oled.h"
#include "../api.hpp"
+#include "../base_app.hpp"
-namespace app_home_menu {
- int init(Api *app_api);
- int render(Api *app_api);
- int btnpressed(Api *app_api, uint gpio, unsigned long delta);
- int bgrefresh(Api *app_api, bool in_foreground);
- int destroy(Api *app_api);
-}
+#define NUMBER_OF_APPS 3
+#define SIZE_APP_NAME 12
-#endif
+class app_home_menu : public BaseApp {
+ private:
+ const char *APPS_NAME[NUMBER_OF_APPS] = {"Home", "Clock", "Settings"};
+ int selected_app = 0;
+ char display_app_name[SIZE_APP_NAME];
+ void title_str(char *buf, uint buf_size, const datetime_t *t);
+ void show_title(Api *app_api);
+ public:
+ uint app_id = 0;
+ app_home_menu(Api *app_api);
+ int render(Api *app_api);
+ int btnpressed(Api *app_api, uint gpio, unsigned long delta);
+ int bgrefresh(Api *app_api, bool in_foreground);
+ ~app_home_menu();
+};
diff --git a/base_app.hpp b/base_app.hpp
new file mode 100644
index 0000000..0950a01
--- /dev/null
+++ b/base_app.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+// Base app
+class BaseApp {
+ public:
+ uint app_id = 0; // CHECK: This has to be overwritten by derived classes
+ virtual int render(Api *app_api) = 0; // Has to be implemented
+ virtual int btnpressed(Api *app_api, uint gpio, unsigned long delta) {};
+ virtual int bgrefresh(Api *app_api, bool in_foreground) {};
+};
diff --git a/pico-watch.cpp b/pico-watch.cpp
index f75317e..7ce2f98 100644
--- a/pico-watch.cpp
+++ b/pico-watch.cpp
@@ -1,4 +1,5 @@
#include <stdio.h>
+#include <vector>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/sync.h"
@@ -8,6 +9,7 @@
#include "init.hpp"
#include "api.hpp"
#include "buttons.hpp"
+#include "base_app.hpp"
#include "apps/main_clock.hpp"
#include "apps/home_menu.hpp"
#include "apps/settings/main.hpp"
@@ -17,15 +19,19 @@ user_settings g_user;
Api app_api;
#define NUMBER_OF_APPS 3
-#define APP_DATA_BUFFER_LEN 256
-int (*APPS_FUNC_INIT[NUMBER_OF_APPS])(Api *app_api) = {app_home_menu::init, app_main_clock::init, app_settings::init};
-int (*APPS_FUNC_RENDER[NUMBER_OF_APPS])(Api *app_api) = {app_home_menu::render, app_main_clock::render, app_settings::render};
-int (*APPS_FUNC_BTNPRESS[NUMBER_OF_APPS])(Api *app_api, uint gpio, unsigned long delta) = {app_home_menu::btnpressed, app_main_clock::btnpressed, app_settings::btnpressed};
-int (*APPS_FUNC_BGREFRESH[NUMBER_OF_APPS])(Api *app_api, bool in_foreground) = {app_home_menu::bgrefresh, app_main_clock::bgrefresh, app_settings::bgrefresh};
-int (*APPS_FUNC_DESTROY[NUMBER_OF_APPS])(Api *app_api) = {app_home_menu::destroy, app_main_clock::destroy, app_settings::destroy};
+
+std::vector<BaseApp*> open_apps;
+
int APPS_DESTROY_ON_EXIT[NUMBER_OF_APPS] = {0, 1, 1};
int APPS_IS_INIT[NUMBER_OF_APPS] = {0}; // Only run in background if init
+int app_create(int app_id) {
+ switch (app_id) {
+ case 0: open_apps.push_back(new app_home_menu(&app_api)); break;
+ default: __breakpoint();
+ }
+}
+
int app_init(int app_id) {
app_api.display_fill(0,1); // Clear OLED
app_api.performance_render_interval_set(500); // Reset interval
@@ -36,7 +42,8 @@ int app_init(int app_id) {
}
if (!APPS_IS_INIT[app_id]) {
- int status = (*APPS_FUNC_INIT[app_id])(&app_api);
+ app_create(app_id);
+ /* int status = (*APPS_FUNC_INIT[app_id])(&app_api);
switch (status) {
case Api::app_init_return_status::MALLOC_FAILED:
@@ -55,31 +62,40 @@ int app_init(int app_id) {
default: // OK and unhandled status codes
printf("App init, status: %d\n", status);
break;
- }
+ } */
APPS_IS_INIT[app_id] = 1;
}
return app_id;
}
int app_render(int app_id) {
- return (*APPS_FUNC_RENDER[app_id])(&app_api);
+ for (auto app : open_apps) {
+ if (app_id == app->app_id)
+ return app->render(&app_api);
+ }
}
// Delta is in ms, from time_since_button_press()
int app_btnpressed(int app_id, uint gpio, unsigned long delta) {
- return (*APPS_FUNC_BTNPRESS[app_id])(&app_api, gpio, delta);
+ for (auto app : open_apps) {
+ if (app_id == app->app_id)
+ return app->btnpressed(&app_api, gpio, delta);
+ }
}
int app_destroy(int app_id) {
- if (APPS_IS_INIT[app_id]) {
- APPS_IS_INIT[app_id] = 0;
- return (*APPS_FUNC_DESTROY[app_id])(&app_api);
+ BaseApp* to_destroy;
+
+ for (auto app : open_apps) {
+ if (app_id == app->app_id)
+ to_destroy = app;
}
-}
+ delete to_destroy;
+ // FIXME: Remove app from list
+ //open_apps.erase(std::remove(open_apps.begin(), open_apps.end(), to_destroy), open_apps.end()); // See https://stackoverflow.com/a/27306171/15578170
-int app_bgrefresh(int app_id) {
- if (APPS_IS_INIT[app_id])
- return (*APPS_FUNC_BGREFRESH[app_id])(&app_api, app_id==g_s.current_app);
+ APPS_IS_INIT[app_id] = 0;
+ return 0;
}
bool repeating_callback(struct repeating_timer *t) {
@@ -94,9 +110,11 @@ bool repeating_callback(struct repeating_timer *t) {
app_api.performance_set(Api::perf_modes::EXIT_SHALLOW_SLEEP);
app_api.display_power(true);
}
- // Refresh each app, but should it be done when sleeping?
- for (int i=0; i < NUMBER_OF_APPS; i++) {
- app_bgrefresh(i);
+
+ // Refresh each app
+ // should it be done when sleeping?
+ for (auto app : open_apps) {
+ app->bgrefresh(&app_api, g_s.current_app == app->app_id);
}
return true;
}