Skip to content

Commit c3f2f07

Browse files
committed
add Conway's Game of Life
1 parent cf19fbb commit c3f2f07

File tree

7 files changed

+192
-3
lines changed

7 files changed

+192
-3
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ popd
2424
pushd apps/synth_piano
2525
esptool.py --chip esp32s3 --baud 921600 --before default_reset --after hard_reset write_flash 0xA60000 build/synth_piano.bin
2626
popd
27+
pushd apps/game_of_life
28+
esptool.py --chip esp32s3 --baud 921600 --before default_reset --after hard_reset write_flash 0xA60000 build/game_of_life.bin
29+
popd
2730
```
2831

2932
## Build

apps/game_of_life/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(game_of_life)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(SRCS "game_of_life.c"
2+
INCLUDE_DIRS "."
3+
REQUIRES app_update)
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#include <stdio.h>
2+
// Conway's Game of Life for ESP32 using LVGL
3+
#include <stdlib.h>
4+
#include <stdbool.h>
5+
#include <time.h>
6+
#include "freertos/FreeRTOS.h"
7+
#include "freertos/task.h"
8+
#include "esp_log.h"
9+
#include "esp_system.h"
10+
#include "lvgl.h"
11+
#include "bsp/esp-bsp.h"
12+
#include "esp_ota_ops.h"
13+
14+
#define TAG "GameOfLife"
15+
#define GRID_SIZE 20
16+
#define CELL_SIZE 10
17+
#define CANVAS_WIDTH (GRID_SIZE * CELL_SIZE)
18+
#define CANVAS_HEIGHT (GRID_SIZE * CELL_SIZE)
19+
20+
static bool grid[GRID_SIZE][GRID_SIZE];
21+
static bool temp_grid[GRID_SIZE][GRID_SIZE];
22+
static lv_obj_t *canvas;
23+
lv_layer_t layer;
24+
25+
static void draw_grid();
26+
static void update_grid();
27+
28+
static void randomize_grid() {
29+
for (int row = 0; row < GRID_SIZE; ++row) {
30+
for (int col = 0; col < GRID_SIZE; ++col) {
31+
grid[row][col] = rand() % 2;
32+
}
33+
}
34+
}
35+
36+
static void reset_btn_event_cb(lv_event_t *e) {
37+
lv_event_code_t code = lv_event_get_code(e);
38+
if (code == LV_EVENT_CLICKED) {
39+
randomize_grid();
40+
}
41+
}
42+
43+
static void draw_grid() {
44+
bsp_display_lock(0);
45+
46+
lv_draw_rect_dsc_t rect_dsc;
47+
lv_draw_rect_dsc_init(&rect_dsc);
48+
49+
for (int row = 0; row < GRID_SIZE; ++row) {
50+
for (int col = 0; col < GRID_SIZE; ++col) {
51+
lv_area_t area;
52+
area.x1 = col * CELL_SIZE;
53+
area.y1 = row * CELL_SIZE;
54+
area.x2 = area.x1 + CELL_SIZE - 1;
55+
area.y2 = area.y1 + CELL_SIZE - 1;
56+
rect_dsc.bg_color = grid[row][col] ? lv_palette_main(LV_PALETTE_BLUE) : lv_color_white();
57+
lv_draw_rect(&layer, &rect_dsc, &area);
58+
}
59+
}
60+
61+
lv_canvas_finish_layer(canvas, &layer);
62+
lv_obj_invalidate(canvas);
63+
bsp_display_unlock();
64+
}
65+
66+
static void update_grid() {
67+
for (int row = 0; row < GRID_SIZE; ++row) {
68+
for (int col = 0; col < GRID_SIZE; ++col) {
69+
int live_neighbors = 0;
70+
for (int i = -1; i <= 1; ++i) {
71+
for (int j = -1; j <= 1; ++j) {
72+
if (i == 0 && j == 0) continue;
73+
int r = row + i;
74+
int c = col + j;
75+
if (r >= 0 && r < GRID_SIZE && c >= 0 && c < GRID_SIZE) {
76+
live_neighbors += grid[r][c];
77+
}
78+
}
79+
}
80+
81+
if (grid[row][col]) {
82+
temp_grid[row][col] = live_neighbors == 2 || live_neighbors == 3;
83+
} else {
84+
temp_grid[row][col] = live_neighbors == 3;
85+
}
86+
}
87+
}
88+
89+
for (int row = 0; row < GRID_SIZE; ++row) {
90+
for (int col = 0; col < GRID_SIZE; ++col) {
91+
grid[row][col] = temp_grid[row][col];
92+
}
93+
}
94+
}
95+
96+
static void life_task(void *param) {
97+
while (1) {
98+
vTaskDelay(pdMS_TO_TICKS(100));
99+
update_grid();
100+
draw_grid();
101+
}
102+
}
103+
104+
void reset_to_factory_app() {
105+
// Get the partition structure for the factory partition
106+
const esp_partition_t *factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
107+
if (factory_partition != NULL) {
108+
if (esp_ota_set_boot_partition(factory_partition) == ESP_OK) {
109+
printf("Set boot partition to factory, restarting now.\n");
110+
} else {
111+
printf("Failed to set boot partition to factory.\n");
112+
}
113+
} else {
114+
printf("Factory partition not found.\n");
115+
}
116+
117+
fflush(stdout);
118+
}
119+
120+
void app_main(void) {
121+
// Reset to factory app for the next boot.
122+
// It should return to graphical bootloader.
123+
reset_to_factory_app();
124+
125+
// Initialize the BSP
126+
bsp_i2c_init();
127+
bsp_display_start();
128+
lv_init();
129+
srand(time(NULL));
130+
131+
bsp_display_lock(0);
132+
133+
LV_DRAW_BUF_DEFINE(draw_buf, CANVAS_WIDTH, CANVAS_HEIGHT, LV_COLOR_FORMAT_RGB565);
134+
135+
canvas = lv_canvas_create(lv_scr_act());
136+
lv_canvas_set_draw_buf(canvas, &draw_buf);
137+
lv_canvas_fill_bg(canvas, lv_color_hex3(0xccc), LV_OPA_COVER);
138+
lv_obj_center(canvas);
139+
140+
lv_canvas_init_layer(canvas, &layer);
141+
142+
// Create a reset button
143+
lv_obj_t *reset_btn = lv_btn_create(lv_scr_act());
144+
lv_obj_t *label = lv_label_create(reset_btn);
145+
lv_label_set_text(label, "Reset");
146+
lv_obj_align(reset_btn, LV_ALIGN_BOTTOM_RIGHT, 0, -10);
147+
lv_obj_add_event_cb(reset_btn, reset_btn_event_cb, LV_EVENT_CLICKED, NULL);
148+
149+
bsp_display_backlight_on();
150+
bsp_display_unlock();
151+
152+
// Initialize grid
153+
randomize_grid();
154+
printf("Grid initialized\n");
155+
draw_grid();
156+
printf("Grid drawn\n");
157+
158+
// Create the life task
159+
xTaskCreate(life_task, "life_task", 32768, NULL, 5, NULL);
160+
161+
while (1) {
162+
vTaskDelay(pdMS_TO_TICKS(1000));
163+
}
164+
}
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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ lvgl_port_create_c_image("../resources/images/icon_tic_tac_toe.png" "images/gen/
99
lvgl_port_create_c_image("../resources/images/icon_wifi_list.png" "images/gen/" "ARGB8888" "NONE")
1010
lvgl_port_create_c_image("../resources/images/icon_calculator.png" "images/gen/" "ARGB8888" "NONE")
1111
lvgl_port_create_c_image("../resources/images/icon_synth_piano.png" "images/gen/" "ARGB8888" "NONE")
12+
lvgl_port_create_c_image("../resources/images/icon_game_of_life.png" "images/gen/" "ARGB8888" "NONE")
13+
1214
lvgl_port_add_images(${COMPONENT_LIB} "images/gen/")

main/bootloader_ui.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ LV_IMG_DECLARE(icon_tic_tac_toe)
4343
LV_IMG_DECLARE(icon_wifi_list)
4444
LV_IMG_DECLARE(icon_calculator)
4545
LV_IMG_DECLARE(icon_synth_piano)
46-
// LV_IMG_DECLARE(icon_app5)
46+
LV_IMG_DECLARE(icon_game_of_life)
4747

4848
void ui_app1_start(void (*fn)(void));
4949
void ui_app2_start(void (*fn)(void));
@@ -56,12 +56,12 @@ static item_desc_t item[] = {
5656
{ "Wi-Fi List", (void *) &icon_wifi_list, ui_app2_start, NULL},
5757
{ "Calculator", (void *) &icon_calculator, ui_app3_start, NULL},
5858
{ "Piano", (void *) &icon_synth_piano, ui_app4_start, NULL},
59-
{ "App5", (void *) &icon_tic_tac_toe, ui_app5_start, NULL},
59+
{ "Game of Life", (void *) &icon_game_of_life, ui_app5_start, NULL},
6060
};
6161

6262
static lv_obj_t *g_img_btn, *g_img_item = NULL;
6363
static lv_obj_t *g_lab_item = NULL;
64-
static lv_obj_t *g_led_item[6];
64+
static lv_obj_t *g_led_item[5];
6565
static size_t g_item_size = sizeof(item) / sizeof(item[0]);
6666
static lv_obj_t *g_status_bar = NULL;
6767

0 commit comments

Comments
 (0)