diff options
-rw-r--r-- | apps/home_menu.cpp | 119 | ||||
-rw-r--r-- | apps/home_menu.hpp | 29 | ||||
-rw-r--r-- | base_app.hpp | 10 | ||||
-rw-r--r-- | pico-watch.cpp | 58 |
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; } |