diff options
author | ConfuSomu | 2021-02-15 11:06:57 -0500 |
---|---|---|
committer | ConfuSomu | 2021-02-15 11:06:57 -0500 |
commit | f2d591ce164086cdb0e57a49e867058e59457795 (patch) | |
tree | 1d4d44005e9e886a1cea52e9b808450bd74be478 | |
parent | 93341511201aca2daf10c26f8b1f5c0bf13e669c (diff) | |
download | pico-watch-f2d591ce164086cdb0e57a49e867058e59457795.tar pico-watch-f2d591ce164086cdb0e57a49e867058e59457795.tar.gz pico-watch-f2d591ce164086cdb0e57a49e867058e59457795.zip |
Implement home menu
Buttons are now detected and reported to the current running application
(demoed in main_clock and home_menu with `oledWriteString(oled, 0,0,2,
&data[0], FONT_6x8, 0, 1);`). I start to see the limitations with
APP_DATA. It will be dropped in a futur commit after moving each app
into its own namespace. Variables will be allocated dynamically on app
init.
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | apps/home_menu.c | 88 | ||||
-rw-r--r-- | apps/home_menu.h | 15 | ||||
-rw-r--r-- | apps/main_clock.c | 6 | ||||
-rw-r--r-- | apps/main_clock.h | 2 | ||||
-rw-r--r-- | buttons.c | 10 | ||||
-rw-r--r-- | pico-watch.c | 51 |
7 files changed, 159 insertions, 15 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e9e2c8b..0b9aa59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,8 @@ add_executable(pico-watch init.h buttons.c buttons.h + apps/home_menu.c + apps/home_menu.h apps/main_clock.c apps/main_clock.h ) diff --git a/apps/home_menu.c b/apps/home_menu.c new file mode 100644 index 0000000..b7c15b0 --- /dev/null +++ b/apps/home_menu.c @@ -0,0 +1,88 @@ +#include <stdio.h> +#include "pico/stdlib.h" +#include "hardware/rtc.h" +#include "pico/util/datetime.h" +#include "../oled/ss_oled.h" + +#include "home_menu.h" +#include "../buttons.h" + +extern void app_switch(int old_appid, int new_appid); + +#define NUMBER_OF_APPS 2 + +char* APPS_NAME[NUMBER_OF_APPS][12] = {"Home", "Clock"}; + +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(SSOLED *oled) { + char datetime_buf[256]; + char *datetime_str = &datetime_buf[0]; + datetime_t t; + rtc_get_datetime(&t); + + // title with time + title_str(datetime_str, sizeof(datetime_buf), &t); + oledWriteString(oled, 0,0,0, datetime_str, FONT_8x8, 0, 1); +} + +// Rendering of app +int home_menu_render(SSOLED *oled, char *data, uint data_size) { + show_title(oled); + oledWriteString(oled, 0,0,2, &data[0], FONT_6x8, 0, 1); + oledWriteString(oled, 0,5,3, APPS_NAME[data[1]][0], FONT_12x16, 0, 1); // FIXME: The name does not update, it seems that the second string is empty… but data[1]'s content is correct, as BUTTON_SELECT switches to the correct app. + return 0; +} + +// Interpret button inputs +int home_menu_btnpressed(SSOLED *oled, char *data, uint data_size, uint gpio) { + switch (gpio) { + case BUTTON_HOME: + data[0] = 'H'; break; + case BUTTON_SELECT: + data[0] = 'S'; + app_switch(0, data[1]); + break; + case BUTTON_MODE: + data[0] = 'M'; break; + case BUTTON_DOWN: + data[0] = 'D'; + data[1]--; + break; + case BUTTON_UP: + data[0] = 'U'; + data[1]++; + break; + default: + data[0] = '?'; + } + if (data[1] > NUMBER_OF_APPS-1) { + data[1] = NUMBER_OF_APPS-1; data[0] = '>'; + } else if (data[1] < NUMBER_OF_APPS-1) { + data[1] = 0; data[0] = '<'; + } + return 0; +} + +// Initlisation of the app. +int home_menu_init(SSOLED *oled, char *data, uint data_size) { + data[1] = 0; + return 0; // return 1 when function not implemented +} + +// 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 home_menu_bgrefresh(SSOLED *oled, char *data, uint data_size, char in_foreground) { + return 1; +} + +// 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 home_menu_destroy(SSOLED *oled, char *data, uint data_size) { + return 1; +} diff --git a/apps/home_menu.h b/apps/home_menu.h new file mode 100644 index 0000000..507e818 --- /dev/null +++ b/apps/home_menu.h @@ -0,0 +1,15 @@ +#ifndef __HOME_MENU_H__ +#define __HOME_MENU_H__ + +#include "pico/util/datetime.h" +#include "../oled/ss_oled.h" + +void show_title(SSOLED *oled); + +int home_menu_init(SSOLED *oled, char *data, uint data_size); +int home_menu_render(SSOLED *oled, char *data, uint data_size); +int home_menu_btnpressed(SSOLED *oled, char *data, uint data_size, uint gpio); +int home_menu_bgrefresh(SSOLED *oled, char *data, uint data_size, char in_foreground); +int home_menu_destroy(SSOLED *oled, char *data, uint data_size); + +#endif
\ No newline at end of file diff --git a/apps/main_clock.c b/apps/main_clock.c index 496c696..547057e 100644 --- a/apps/main_clock.c +++ b/apps/main_clock.c @@ -51,6 +51,7 @@ void show_datetime(SSOLED *oled) { oledWriteString(oled, 0,0,7, datetime_str, FONT_8x8, 0, 1); } +// Rendering of the app int main_clock_render(SSOLED *oled, char *data, uint data_size) { oledWriteString(oled, 0,15,0, (char *)"Test clock", FONT_8x8, 0, 1); show_datetime(oled); @@ -78,14 +79,17 @@ int main_clock_btnpressed(SSOLED *oled, char *data, uint data_size, uint gpio) { return 0; } +// Initlisation of the app. int main_clock_init(SSOLED *oled, char *data, uint data_size) { return 1; // return 1 when function not implemented } -int main_clock_bgrefresh(SSOLED *oled, char *data, uint data_size) { +// 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 main_clock_bgrefresh(SSOLED *oled, char *data, uint data_size, char in_foreground) { return 1; } +// 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 main_clock_destroy(SSOLED *oled, char *data, uint data_size) { return 1; } diff --git a/apps/main_clock.h b/apps/main_clock.h index a7acdfe..70d9755 100644 --- a/apps/main_clock.h +++ b/apps/main_clock.h @@ -11,7 +11,7 @@ void show_datetime(SSOLED *oled); int main_clock_init(SSOLED *oled, char *data, uint data_size); int main_clock_render(SSOLED *oled, char *data, uint data_size); int main_clock_btnpressed(SSOLED *oled, char *data, uint data_size, uint gpio); -int main_clock_bgrefresh(SSOLED *oled, char *data, uint data_size); +int main_clock_bgrefresh(SSOLED *oled, char *data, uint data_size, char in_foreground); int main_clock_destroy(SSOLED *oled, char *data, uint data_size); #endif
\ No newline at end of file @@ -2,7 +2,9 @@ #include "pico/stdlib.h" #include "buttons.h" +// From pico-watch.c: extern int app_btnpressed(int app_id, uint gpio); +extern void app_switch(int old_appid, int new_appid); extern int current_app; // Debounce control @@ -15,7 +17,11 @@ const int button_delayTime = 50; // 50ms worked fine for me .... change it to yo void gpio_interrupt_cb(uint gpio, uint32_t events) { if ((to_ms_since_boot(get_absolute_time())-button_time)>button_delayTime) { - app_btnpressed(current_app, gpio); + if (gpio == BUTTON_HOME && (current_app != 0)) // Home app + app_switch(current_app, 0); + else + app_btnpressed(current_app, gpio); + button_time = to_ms_since_boot(get_absolute_time()); } } @@ -38,7 +44,7 @@ void init_buttons() { gpio_set_irq_enabled_with_callback(BUTTON_UP, GPIO_IRQ_EDGE_FALL , true, &gpio_interrupt_cb); /* For some reason for loop does not work… TODO - for (int i=0; i == NUMBER_OF_BUTTONS; i++) { + for (int i=0; i < NUMBER_OF_BUTTONS; i++) { uint button = BUTTON_PINS[i]; gpio_init(button); gpio_pull_up(button); diff --git a/pico-watch.c b/pico-watch.c index eb5f7cc..37dcd35 100644 --- a/pico-watch.c +++ b/pico-watch.c @@ -8,23 +8,27 @@ #include "init.h" #include "buttons.h" #include "apps/main_clock.h" +#include "apps/home_menu.h" int current_app = 0; -#define NUMBER_OF_APPS 1 +#define NUMBER_OF_APPS 2 #define APP_DATA_BUFFER_LEN 256 -int (*APPS_FUNC_INIT[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {main_clock_init}; -int (*APPS_FUNC_RENDER[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {main_clock_render}; -int (*APPS_FUNC_BTNPRESS[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size, uint gpio) = {main_clock_btnpressed}; -int (*APPS_FUNC_BGREFRESH[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {main_clock_bgrefresh}; -int (*APPS_FUNC_DESTROY[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {main_clock_destroy}; +int (*APPS_FUNC_INIT[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {home_menu_init, main_clock_init}; +int (*APPS_FUNC_RENDER[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {home_menu_render, main_clock_render}; +int (*APPS_FUNC_BTNPRESS[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size, uint gpio) = {home_menu_btnpressed, main_clock_btnpressed}; +int (*APPS_FUNC_BGREFRESH[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size, char in_foreground) = {home_menu_bgrefresh, main_clock_bgrefresh}; +int (*APPS_FUNC_DESTROY[NUMBER_OF_APPS])(SSOLED *oled, char *data, uint data_size) = {home_menu_destroy, main_clock_destroy}; char APPS_DATA[NUMBER_OF_APPS][APP_DATA_BUFFER_LEN]; -int APPS_DESTROY_ON_EXIT[NUMBER_OF_APPS] = {1}; -int APPS_IS_INIT[NUMBER_OF_APPS] = {0}; +int APPS_DESTROY_ON_EXIT[NUMBER_OF_APPS] = {0, 1}; +int APPS_IS_INIT[NUMBER_OF_APPS] = {0, 0}; // Only run in background if init int app_init(int app_id) { - APPS_IS_INIT[app_id] = 1; - return (*APPS_FUNC_INIT[app_id])(&oled, &APPS_DATA[app_id][0], sizeof(APPS_DATA[app_id])); + oledFill(&oled, 0,1); // Clear OLED + if (!APPS_IS_INIT[app_id]) { + APPS_IS_INIT[app_id] = 1; + return (*APPS_FUNC_INIT[app_id])(&oled, &APPS_DATA[app_id][0], sizeof(APPS_DATA[app_id])); + } } int app_render(int app_id) { @@ -36,13 +40,38 @@ int app_btnpressed(int app_id, uint gpio) { } int app_destroy(int app_id) { + // TODO: reset APPS_DATA for the app + if (APPS_IS_INIT[app_id]) { + APPS_IS_INIT[app_id] = 0; + return (*APPS_FUNC_DESTROY[app_id])(&oled, &APPS_DATA[app_id][0], sizeof(APPS_DATA[app_id])); + } +} + +int app_bgrefresh(int app_id) { if (APPS_IS_INIT[app_id]) - return (*APPS_FUNC_INIT[app_id])(&oled, &APPS_DATA[app_id][0], sizeof(APPS_DATA[app_id])); + return (*APPS_FUNC_BGREFRESH[app_id])(&oled, &APPS_DATA[app_id][0], sizeof(APPS_DATA[app_id]), app_id==current_app); +} + +bool apps_bgrefresh(struct repeating_timer *t) { // TODO: Refresh done on core1 + for (int i=0; i < NUMBER_OF_APPS; i++) { + app_bgrefresh(i); + } + return true; +} + +void app_switch(int old_appid, int new_appid) { + if (APPS_DESTROY_ON_EXIT[old_appid]) { + app_destroy(old_appid); + } + app_init(new_appid); + current_app = new_appid; } int main() { init_all(); init_buttons(); + struct repeating_timer timer; + add_repeating_timer_ms(250, apps_bgrefresh, NULL, &timer); app_init(current_app); |