1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
#include <stdio.h>
#include <vector>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/sync.h"
#include "hardware/rtc.h"
#include "pico/util/datetime.h"
#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"
global_status g_s;
user_settings g_user;
Api app_api;
#define NUMBER_OF_APPS 3
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
if (app_id > NUMBER_OF_APPS-1 or app_id < 0) {
printf("Tried to init app %d", app_id);
return app_init(0);
}
if (!APPS_IS_INIT[app_id]) {
app_create(app_id);
/* int status = (*APPS_FUNC_INIT[app_id])(&app_api);
switch (status) {
case Api::app_init_return_status::MALLOC_FAILED:
printf("App init failed (alloc), ");
for (int i=0; i<10; i++) {
if ((*APPS_FUNC_INIT[app_id])(&app_api) != Api::app_init_return_status::MALLOC_FAILED) {
printf("worked after %d tries\n", i);
APPS_IS_INIT[app_id] = 1;
return app_id;
}
}
// Instead, the current app could continue running: return current_app
printf("gave up, launching app 0\n");
return app_init(0); // Note: this has to work (and should)
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) {
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) {
for (auto app : open_apps) {
if (app_id == app->app_id)
return app->btnpressed(&app_api, gpio, delta);
}
}
int app_destroy(int app_id) {
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
APPS_IS_INIT[app_id] = 0;
return 0;
}
bool repeating_callback(struct repeating_timer *t) {
// Enter shallow sleep mode when needed
auto time_since_last_press = time_since_button_press();
if (!g_s.is_sleeping && time_since_last_press > g_user.sleep_delay) {
g_s.is_sleeping = true;
app_api.performance_set(Api::perf_modes::ENTER_SHALLOW_SLEEP);
app_api.display_power(false);
} else if (g_s.is_sleeping && time_since_last_press < g_user.sleep_delay) {
g_s.is_sleeping = false;
app_api.performance_set(Api::perf_modes::EXIT_SHALLOW_SLEEP);
app_api.display_power(true);
}
// 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;
}
void app_switch_request(int to_appid) {
if (!g_s.app_switch_requested)
g_s.app_switch_to_app = to_appid;
g_s.app_switch_requested = true;
app_api.performance_render_interval_set(0); // This will be reset on new app init
}
void app_switch(int old_appid, int new_appid) {
g_s.app_ready = false;
if (APPS_DESTROY_ON_EXIT[old_appid])
app_destroy(old_appid);
g_s.current_app = app_init(new_appid);
g_s.app_ready = true;
}
int main() {
init_all();
printf("~~~==~~~");
init_buttons();
app_api.init();
struct repeating_timer timer;
add_repeating_timer_ms(250, repeating_callback, NULL, &timer); // TODO: Execute on core1
app_init(g_s.current_app);
while (1) {
if (g_s.app_switch_requested) {
app_switch(g_s.current_app, g_s.app_switch_to_app);
g_s.app_switch_requested = false;
}
if (g_s.app_ready && !g_s.is_sleeping) {
app_render(g_s.current_app);
app_api.display_write_backbuffer();
}
if (g_s.is_sleeping) __wfi();
else sleep_ms(app_api.performance_render_interval_get());
}
return 0;
}
|