Skip to content

Commit fe68462

Browse files
committed
add calculator app
1 parent 1612ac5 commit fe68462

File tree

8 files changed

+174
-3
lines changed

8 files changed

+174
-3
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ popd
1818
pushd apps/wifi_list
1919
esptool.py --chip esp32s3 --baud 921600 --before default_reset --after hard_reset write_flash 0x4E0000 build/wifi_list.bin
2020
popd
21+
pushd apps/calculator
22+
esptool.py --chip esp32s3 --baud 921600 --before default_reset --after hard_reset write_flash 0x7A0000 build/calculator.bin
23+
popd
2124
```
2225

2326
## Build

apps/calculator/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following five lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.16)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(calculator)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(SRCS "calculator.c"
2+
INCLUDE_DIRS "."
3+
REQUIRES app_update)

apps/calculator/main/calculator.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include "freertos/FreeRTOS.h"
2+
#include "freertos/task.h"
3+
#include "esp_system.h"
4+
#include "esp_log.h"
5+
#include "lvgl.h"
6+
#include "bsp/esp-bsp.h"
7+
#include "esp_timer.h"
8+
#include "esp_ota_ops.h"
9+
10+
#define TAG "Calculator"
11+
12+
static lv_obj_t *display_label;
13+
static char current_input[64] = "";
14+
static double stored_value = 0;
15+
static char current_operator = 0;
16+
static bool clear_next = false;
17+
static int64_t last_press_time = 0;
18+
19+
static void update_display() {
20+
bsp_display_lock(0);
21+
lv_label_set_text(display_label, current_input);
22+
bsp_display_unlock();
23+
}
24+
25+
static void clear_input() {
26+
current_input[0] = '\0';
27+
update_display();
28+
}
29+
30+
static void append_input(const char *text) {
31+
if (clear_next) {
32+
clear_input();
33+
clear_next = false;
34+
}
35+
if (strlen(current_input) < sizeof(current_input) - 1) {
36+
strcat(current_input, text);
37+
}
38+
update_display();
39+
}
40+
41+
static void handle_operator(char operator) {
42+
if (current_operator != 0 && !clear_next) {
43+
double current_value = atof(current_input);
44+
switch (current_operator) {
45+
case '+': stored_value += current_value; break;
46+
case '-': stored_value -= current_value; break;
47+
case '*': stored_value *= current_value; break;
48+
case '/': if (current_value != 0) stored_value /= current_value; break;
49+
}
50+
snprintf(current_input, sizeof(current_input), "%g", stored_value);
51+
update_display();
52+
} else {
53+
stored_value = atof(current_input);
54+
}
55+
current_operator = operator;
56+
clear_next = true;
57+
}
58+
59+
static void btn_event_cb(lv_event_t *e) {
60+
int64_t now = esp_timer_get_time();
61+
if (now - last_press_time < 500000) { // 500 ms debounce time
62+
return;
63+
}
64+
last_press_time = now;
65+
66+
lv_obj_t *btn = lv_event_get_target(e);
67+
const char *txt = lv_btnmatrix_get_btn_text(btn, lv_btnmatrix_get_selected_btn(btn));
68+
69+
if (strcmp(txt, "C") == 0) {
70+
clear_input();
71+
stored_value = 0;
72+
current_operator = 0;
73+
} else if (strcmp(txt, "=") == 0) {
74+
handle_operator(0);
75+
current_operator = 0;
76+
clear_next = true;
77+
} else if (strchr("+-*/", txt[0]) != NULL) {
78+
handle_operator(txt[0]);
79+
} else {
80+
append_input(txt);
81+
}
82+
}
83+
84+
void reset_to_factory_app() {
85+
// Get the partition structure for the factory partition
86+
const esp_partition_t *factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
87+
if (factory_partition != NULL) {
88+
if (esp_ota_set_boot_partition(factory_partition) == ESP_OK) {
89+
printf("Set boot partition to factory, restarting now.\n");
90+
} else {
91+
printf("Failed to set boot partition to factory.\n");
92+
}
93+
} else {
94+
printf("Factory partition not found.\n");
95+
}
96+
97+
fflush(stdout);
98+
}
99+
100+
void app_main(void) {
101+
// Reset to factory app for the next boot.
102+
// It should return to graphical bootloader.
103+
reset_to_factory_app();
104+
105+
// Initialize the BSP
106+
bsp_i2c_init();
107+
bsp_display_start();
108+
lv_init();
109+
110+
// Create a label for the display
111+
display_label = lv_label_create(lv_scr_act());
112+
lv_obj_set_size(display_label, 300, 30);
113+
lv_obj_align(display_label, LV_ALIGN_TOP_MID, 0, 10);
114+
lv_label_set_text(display_label, "0");
115+
116+
// Create a button matrix for the calculator
117+
static const char *btn_map[] = {
118+
"7", "8", "9", "C", "\n",
119+
"4", "5", "6", "*", "\n",
120+
"1", "2", "3", "-", "\n",
121+
"0", ".", "/", "+", "\n",
122+
"=", ""
123+
};
124+
125+
lv_obj_t *btnm = lv_btnmatrix_create(lv_scr_act());
126+
lv_btnmatrix_set_map(btnm, btn_map);
127+
lv_obj_set_size(btnm, 320, 180);
128+
lv_obj_align(btnm, LV_ALIGN_CENTER, 0, 30);
129+
lv_obj_add_event_cb(btnm, btn_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
130+
131+
bsp_display_backlight_on();
132+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## IDF Component Manager Manifest File
2+
dependencies:
3+
espressif/esp-box: "^3.1.0"
4+
#espressif/esp-box-3: "^1.2.0"
5+
# Workaround for i2c: CONFLICT! driver_ng is not allowed to be used with this old driver
6+
esp_codec_dev:
7+
public: true
8+
version: "==1.1.0"
9+
## Required IDF version
10+
idf:
11+
version: ">=5.0.0"

main/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ idf_component_register(SRCS
77

88
lvgl_port_create_c_image("../resources/images/icon_tic_tac_toe.png" "images/gen/" "ARGB8888" "NONE")
99
lvgl_port_create_c_image("../resources/images/icon_wifi_list.png" "images/gen/" "ARGB8888" "NONE")
10+
lvgl_port_create_c_image("../resources/images/icon_calculator.png" "images/gen/" "ARGB8888" "NONE")
1011
lvgl_port_add_images(${COMPONENT_LIB} "images/gen/")

main/bootloader_ui.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "esp_ota_ops.h"
66
#include "esp_system.h"
77
#include "bsp/esp-bsp.h"
8+
#include "esp_timer.h"
89

910
typedef struct {
1011
lv_obj_t *scr;
@@ -33,13 +34,14 @@ static int g_item_index = 0;
3334
static lv_group_t *g_btn_op_group = NULL;
3435
static button_style_t g_btn_styles;
3536
static lv_obj_t *g_page_menu = NULL;
37+
static int64_t last_btn_press_time = 0;
3638

3739
static lv_obj_t *g_focus_last_obj = NULL;
3840
static lv_obj_t *g_group_list[3] = {0};
3941

4042
LV_IMG_DECLARE(icon_tic_tac_toe)
4143
LV_IMG_DECLARE(icon_wifi_list)
42-
// LV_IMG_DECLARE(icon_app3)
44+
LV_IMG_DECLARE(icon_calculator)
4345
// LV_IMG_DECLARE(icon_app4)
4446
// LV_IMG_DECLARE(icon_app5)
4547

@@ -52,7 +54,7 @@ void ui_app5_start(void (*fn)(void));
5254
static item_desc_t item[] = {
5355
{ "Tic-Tac-Toe", (void *) &icon_tic_tac_toe, ui_app1_start, NULL},
5456
{ "Wi-Fi List", (void *) &icon_wifi_list, ui_app2_start, NULL},
55-
{ "App3", (void *) &icon_tic_tac_toe, ui_app3_start, NULL},
57+
{ "Calculator", (void *) &icon_calculator, ui_app3_start, NULL},
5658
{ "App4", (void *) &icon_tic_tac_toe, ui_app4_start, NULL},
5759
{ "App5", (void *) &icon_tic_tac_toe, ui_app5_start, NULL},
5860
};
@@ -169,6 +171,13 @@ static void menu_prev_cb(lv_event_t *e)
169171
lv_event_code_t code = lv_event_get_code(e);
170172

171173
if (LV_EVENT_RELEASED == code) {
174+
int64_t now = esp_timer_get_time();
175+
if (now - last_btn_press_time < 500000) { // 500 ms debounce time
176+
bsp_display_unlock();
177+
return;
178+
}
179+
last_btn_press_time = now;
180+
172181
lv_led_off(g_led_item[g_item_index]);
173182
if (0 == g_item_index) {
174183
g_item_index = g_item_size;
@@ -187,6 +196,13 @@ static void menu_next_cb(lv_event_t *e)
187196
lv_event_code_t code = lv_event_get_code(e);
188197

189198
if (LV_EVENT_RELEASED == code) {
199+
int64_t now = esp_timer_get_time();
200+
if (now - last_btn_press_time < 500000) { // 500 ms debounce time
201+
bsp_display_unlock();
202+
return;
203+
}
204+
last_btn_press_time = now;
205+
190206
lv_led_off(g_led_item[g_item_index]);
191207
g_item_index++;
192208
if (g_item_index >= g_item_size) {
@@ -199,7 +215,6 @@ static void menu_next_cb(lv_event_t *e)
199215
bsp_display_unlock();
200216
}
201217

202-
203218
static void ui_led_set_visible(bool visible)
204219
{
205220
bsp_display_lock(0);
10.1 KB
Loading

0 commit comments

Comments
 (0)