diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 86dacf2..524e4ec 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "main.cpp" +idf_component_register(SRCS "helper.cpp" "main.cpp" INCLUDE_DIRS ".") add_subdirectory(drivers) diff --git a/main/drivers/bottom_half.cpp b/main/drivers/bottom_half.cpp index b6f93d5..3b65871 100644 --- a/main/drivers/bottom_half.cpp +++ b/main/drivers/bottom_half.cpp @@ -161,6 +161,9 @@ bool get_touch_released(void) { } static void poll_bottom_task(void *arg); +static void receive_keypad(void); +static void receive_button(void); +static void receive_touch(void); // static void IRAM_ATTR gpio_isr_handler(void* arg) // { @@ -196,6 +199,10 @@ void init_bottom_half() { //hook isr handler for specific gpio pin // gpio_isr_handler_add(BOTTOM_INTERUPT_PIN, gpio_isr_handler, NULL); + receive_keypad(); + receive_button(); + receive_touch(); + xTaskCreate(poll_bottom_task, "poll_bottom", 4096, NULL, 10, NULL); } diff --git a/main/drivers/speaker.cpp b/main/drivers/speaker.cpp index 8c01abc..8395f08 100644 --- a/main/drivers/speaker.cpp +++ b/main/drivers/speaker.cpp @@ -45,6 +45,7 @@ esp_err_t play_raw(const char *fp) { i2s_channel_disable(tx_chan); free(read_buf); free(write_buf); + fclose(fh); return ESP_OK; } diff --git a/main/drivers/tft.hpp b/main/drivers/tft.hpp index 9a91049..7ccc762 100644 --- a/main/drivers/tft.hpp +++ b/main/drivers/tft.hpp @@ -36,8 +36,9 @@ static const char *TFT_TAG = "tft_driver"; -#define DISPLAY_HORIZONTAL_PIXELS 320 -#define DISPLAY_VERTICAL_PIXELS 480 +// rotation swaps the horizontal and vertical pixel counts +#define DISPLAY_HORIZONTAL_PIXELS 480 +#define DISPLAY_VERTICAL_PIXELS 320 #define DISPLAY_COMMAND_BITS 8 #define DISPLAY_PARAMETER_BITS 8 #define DISPLAY_REFRESH_HZ 40000000 @@ -169,9 +170,9 @@ void initialize_display() { ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_handle)); ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_handle)); - ESP_ERROR_CHECK(esp_lcd_panel_invert_color(lcd_handle, false)); - ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(lcd_handle, false)); - ESP_ERROR_CHECK(esp_lcd_panel_mirror(lcd_handle, true, false)); + ESP_ERROR_CHECK(esp_lcd_panel_invert_color(lcd_handle, true)); + ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(lcd_handle, true)); + ESP_ERROR_CHECK(esp_lcd_panel_mirror(lcd_handle, false, true)); ESP_ERROR_CHECK(esp_lcd_panel_set_gap(lcd_handle, 0, 0)); #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) ESP_ERROR_CHECK(esp_lcd_panel_disp_off(lcd_handle, false)); @@ -199,6 +200,7 @@ void initialize_lvgl() { lv_disp_drv.flush_cb = lvgl_flush_cb; lv_disp_drv.draw_buf = &lv_disp_buf; lv_disp_drv.user_data = lcd_handle; + // lv_disp_drv.rotated = LV_DISP_ROT_90; lv_display = lv_disp_drv_register(&lv_disp_drv); ESP_LOGI(TFT_TAG, "Creating LVGL tick timer"); @@ -271,11 +273,21 @@ void create_demo_ui() { lv_anim_start(&a); } +void tick_timer_task(void* arg) { + while (1) + { + vTaskDelay(pdMS_TO_TICKS(10)); + lv_timer_handler(); + } +} + void init_tft() { initialize_spi(); initialize_display(); initialize_lvgl(); + xTaskCreate(tick_timer_task, "tick_lvgl", 4096, NULL, 5, NULL); + ESP_LOGI(TFT_TAG, "TFT initialization Successful"); } diff --git a/main/drivers/wires.cpp b/main/drivers/wires.cpp index a5009eb..6d37e00 100644 --- a/main/drivers/wires.cpp +++ b/main/drivers/wires.cpp @@ -55,20 +55,26 @@ uint8_t get_cut_wires(void) { return return_; } -bool get_button(void) { +bool get_help_button(void) { return button_state; } -bool get_button_pressed(void) { +bool get_help_button_pressed(void) { bool return_ = button_pressed; button_pressed = false; return return_; } -bool get_button_released(void) { +bool get_help_button_released(void) { bool return_ = button_released; button_released = false; return return_; } +void clear_wires_pressed_released_cut(void) { + wires_cut = 0; + button_pressed = false; + button_released = false; +} + void strike(char* reason) { ESP_LOGW("strike!", "%s", reason); uint8_t reg = 6; diff --git a/main/drivers/wires.h b/main/drivers/wires.h index a1d6cbf..c12d3d2 100644 --- a/main/drivers/wires.h +++ b/main/drivers/wires.h @@ -17,9 +17,11 @@ void init_wires(void); uint8_t get_wires(void); uint8_t get_cut_wires(void); -bool get_button(void); -bool get_button_pressed(void); -bool get_button_released(void); +bool get_help_button(void); +bool get_help_button_pressed(void); +bool get_help_button_released(void); + +void clear_wires_pressed_released_cut(void); void set_leds(uint8_t led_states); diff --git a/main/helper.cpp b/main/helper.cpp new file mode 100644 index 0000000..57076e6 --- /dev/null +++ b/main/helper.cpp @@ -0,0 +1,22 @@ +#include "helper.h" + +void clean_bomb(void) { + // clear pending inputs + clear_all_pressed_released(); + clear_wires_pressed_released_cut(); + + // clear leds + led_strip_clear(leds); + led_strip_refresh(leds); + + // clear module timer + stop_module_timer(); + set_module_time(0); + uint8_t clear[] = {0}; + set_module_sseg_raw(clear); + + // clear char lcd + lcd_clear(&lcd); + lcd_no_cursor(&lcd); + lcd_set_cursor(&lcd, 0, 0); +} diff --git a/main/helper.h b/main/helper.h new file mode 100644 index 0000000..349b51e --- /dev/null +++ b/main/helper.h @@ -0,0 +1,14 @@ +#ifndef HELPER_H +#define HELPER_H + +#include "drivers/game_timer.h" +#include "drivers/sseg.h" +#include "drivers/bottom_half.h" +#include "drivers/wires.h" +#include "drivers/char_lcd.h" +#include "drivers/leds.h" + +/// Clears most persistant bomb state +void clean_bomb(void); + +#endif /* HELPER_H */ diff --git a/main/main.cpp b/main/main.cpp index 2c6cdb3..91b04bc 100755 --- a/main/main.cpp +++ b/main/main.cpp @@ -14,6 +14,8 @@ #include "esp_rom_gpio.h" #include "drivers/leds.h" +#include "helper.h" + #include "steps/step0.hpp" #include "steps/step1.hpp" #include "steps/step2.hpp" @@ -38,21 +40,31 @@ extern "C" void app_main(void) { init_bottom_half(); init_char_lcd(); + // create_demo_ui(); + clean_bomb(); + step0(); set_game_time(30000); start_game_timer(); + clean_bomb(); step1(); + clean_bomb(); step2(); + clean_bomb(); step3(); + clean_bomb(); step4(); + clean_bomb(); step5(); + clean_bomb(); step6(); + clean_bomb(); stop_game_timer(); ESP_LOGI(TAG, "Bomb has been diffused. Counter-Terrorists win."); ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/diffused.pcm")); - // create_demo_ui(); + // play_example(); diff --git a/main/steps/step1.hpp b/main/steps/step1.hpp index 64874e3..c030dbe 100644 --- a/main/steps/step1.hpp +++ b/main/steps/step1.hpp @@ -1,10 +1,310 @@ #ifndef STEP_1_HPP #define STEP_1_HPP +#include + static const char *STEP1_TAG = "step1"; -void step1(void) { - +static char* COLOR_NAMES[] = { + "green", + "red", + "yellow", + "purple" +}; + +static char* NUM_NAMES[] = { + "one", + "two", + "three", + "four" +}; + +static uint8_t NEOPIXEL_COLORS[4][3] = { + {0, 20, 0}, + {20, 0, 0}, + {20, 20, 0}, + {15, 0, 20}, +}; + +std::random_device my_rd; +std::mt19937 my_gen(my_rd()); +std::uniform_int_distribution<> zero_to_one(0, 1); +std::uniform_int_distribution<> zero_to_two(0, 2); +std::uniform_int_distribution<> zero_to_three(0, 3); + +static lv_obj_t *scr; +static lv_obj_t *text = NULL; + +static lv_style_t green_text; +static lv_style_t red_text; +static lv_style_t yellow_text; +static lv_style_t purple_text; + +static int switch_leds[] = {0, 0, 0, 0}; + +static lv_style_t* color_styles[] = { + &green_text, + &red_text, + &yellow_text, + &purple_text +}; + +void init_step(void) { + scr = lv_disp_get_scr_act(NULL); + + // Set the background color of the display to black. + lv_style_init(&style_screen); + lv_style_set_bg_color(&style_screen, lv_color_black()); + lv_style_set_text_font(&style_screen, &lv_font_montserrat_32); + lv_obj_add_style(lv_scr_act(), &style_screen, LV_STATE_DEFAULT); + + // rgb565 + lv_color_t green; + green.full = 0x27e0; + lv_color_t red; + red.full = 0xf800; + lv_color_t yellow; + yellow.full = 0xffa9; + lv_color_t purple; + purple.full = 0x881f; + + lv_style_init(&green_text); + lv_style_set_text_color(&green_text, green); + + lv_style_init(&red_text); + lv_style_set_text_color(&red_text, red); + + lv_style_init(&yellow_text); + lv_style_set_text_color(&yellow_text, yellow); + + lv_style_init(&purple_text); + lv_style_set_text_color(&purple_text, purple); + + text = lv_label_create(scr); } +void clean_up_step(void) { + lv_obj_clean(text); + lv_obj_clean(scr); +} + +void generate_switch_leds(void) { + int colors[4] = {0, 1, 2, 3}; + + int idx = zero_to_three(my_gen); + switch_leds[0] = colors[idx]; + colors[idx] = colors[3]; + + idx = zero_to_two(my_gen); + switch_leds[1] = colors[idx]; + colors[idx] = colors[2]; + + idx = zero_to_one(my_gen); + switch_leds[2] = colors[idx]; + colors[idx] = colors[1]; + + switch_leds[3] = colors[0]; + + ESP_LOGI(STEP1_TAG, "%d, %d, %d, %d", switch_leds[0], switch_leds[1], switch_leds[2], switch_leds[3]); + + for (int i = 0; i < 4; i++) { + uint8_t* rgb = NEOPIXEL_COLORS[switch_leds[i]]; + led_strip_set_pixel(leds, Led::switch1 - i, rgb[0], rgb[1], rgb[2]); + } + led_strip_refresh(leds); +} + +int generate_part_a(void) { + int text_color = zero_to_three(my_gen); + int text_idx = zero_to_three(my_gen); + + char* text_string = COLOR_NAMES[text_idx]; + + lv_label_set_text(text, text_string); + lv_obj_center(text); + lv_obj_add_style(text, color_styles[text_color], LV_STATE_DEFAULT); + + generate_switch_leds(); + + // the correct answer is the text color + return text_color; +} + +int generate_part_b(void) { + int is_color = zero_to_one(my_gen) == 0; + if (is_color) { + return generate_part_a(); + } + + int text_color = zero_to_three(my_gen); + int text_number = zero_to_three(my_gen); + + char* text_string = NUM_NAMES[text_number]; + + lv_label_set_text(text, text_string); + lv_obj_center(text); + lv_obj_add_style(text, color_styles[text_color], LV_STATE_DEFAULT); + + generate_switch_leds(); + + // the correct answer is the number + return text_number; +} + +int generate_part_c(void) { + int type = zero_to_two(my_gen); + if (type != 0) { + return generate_part_b(); + } + + int text_color = zero_to_three(my_gen); + char* text_string = "switch"; + + lv_label_set_text(text, text_string); + lv_obj_center(text); + lv_obj_add_style(text, color_styles[text_color], LV_STATE_DEFAULT); + + generate_switch_leds(); + + // the correct answer is the switch + return text_color + 4; +} + +void part_a(void) { + stop_module_timer(); + set_module_time(30); + + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, "COLOR"); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, Led::char_lcd, 20, 0, 20)); + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + int times = 0; + int correct = generate_part_a(); + + ButtonKey button; + SwitchKey switch_; + + while (times < 15) { + while (get_pressed_button(&button)) { + start_module_timer(); + if ((int)(button) == correct) { + times++; + if (times >= 15) break; + correct = generate_part_a(); + } else { + strike("Incorrect color action"); + } + } + while (get_flipped_switch(&switch_)) { + strike("Incorrect color action"); + } + + vTaskDelay(pdMS_TO_TICKS(10)); + } + + lv_label_set_text(text, ""); + vTaskDelay(pdMS_TO_TICKS(80)); + play_raw(MOUNT_POINT "/correct.pcm"); +} + +void part_b(void) { + stop_module_timer(); + set_module_time(25); + + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, "NUMBER"); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, Led::char_lcd, 0, 0, 30)); + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + int times = 0; + int correct = generate_part_b(); + + ButtonKey button; + SwitchKey switch_; + + while (times < 15) { + while (get_pressed_button(&button)) { + start_module_timer(); + if ((int)(button) == correct) { + times++; + if (times >= 15) break; + correct = generate_part_b(); + } else { + strike("Incorrect color action"); + } + } + while (get_flipped_switch(&switch_)) { + strike("Incorrect color action"); + } + + vTaskDelay(pdMS_TO_TICKS(10)); + } + + lv_label_set_text(text, ""); + vTaskDelay(pdMS_TO_TICKS(80)); + play_raw(MOUNT_POINT "/correct.pcm"); +} + +void part_c(void) { + stop_module_timer(); + set_module_time(20); + + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, "SWITCH"); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, Led::char_lcd, 20, 20, 0)); + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + int times = 0; + int correct = generate_part_c(); + + ButtonKey button; + SwitchKey switch_; + + while (times < 15) { + while (get_pressed_button(&button)) { + start_module_timer(); + if ((int)(button) == correct) { + times++; + if (times >= 15) break; + correct = generate_part_c(); + } else { + strike("Incorrect color action"); + } + } + while (get_flipped_switch(&switch_)) { + start_module_timer(); + if (switch_leds[(int)(switch_)] + 4 == correct) { + times++; + if (times >= 10) break; + correct = generate_part_c(); + } else { + strike("Incorrect color action"); + } + } + + vTaskDelay(pdMS_TO_TICKS(10)); + } + + lv_label_set_text(text, ""); + vTaskDelay(pdMS_TO_TICKS(80)); + play_raw(MOUNT_POINT "/correct.pcm"); +} + +void step1(void) { + SwitchKey switch_; + while (get_flipped_switch(&switch_)); + + init_step(); + part_a(); + part_b(); + part_c(); + clean_up_step(); +} + + + #endif /* STEP_1_HPP */ \ No newline at end of file diff --git a/main/steps/step6.hpp b/main/steps/step6.hpp index 431fdc5..9c7b1af 100644 --- a/main/steps/step6.hpp +++ b/main/steps/step6.hpp @@ -9,7 +9,6 @@ static const char *STEP6_TAG = "step6"; static uint8_t cut_wires = 0; -static void correct_wire_task(void *arg); void step6(void) { get_cut_wires(); @@ -28,10 +27,8 @@ void step6(void) { for (int i = 0; i < NUM_WIRES; i++) { if (just_cut_wires & (1<