diff --git a/main/drivers/bottom_half.cpp b/main/drivers/bottom_half.cpp index a3f334c..d64954f 100644 --- a/main/drivers/bottom_half.cpp +++ b/main/drivers/bottom_half.cpp @@ -31,7 +31,9 @@ static bool _take_key(KeypadKey* kp, uint16_t* keypad_bitfield) { for (int i = 0; i < 16; i++) { int bit_selector = (1 << i); if ((*keypad_bitfield) & bit_selector) { - *kp = (KeypadKey) i; + if (kp != nullptr) { + *kp = (KeypadKey) i; + } // clear bit *keypad_bitfield &= ~bit_selector; return true; @@ -90,7 +92,9 @@ static bool _take_button(ButtonKey* button, uint16_t* button_bitfield) { for (int i = 0; i < 4; i++) { int bit_selector = (1 << (i+8)); if ((*button_bitfield) & bit_selector) { - *button = (ButtonKey) i; + if (button != nullptr) { + *button = (ButtonKey) i; + } // clear bit *button_bitfield &= ~bit_selector; return true; @@ -102,7 +106,9 @@ static bool _take_switch(SwitchKey* switch_, uint16_t* button_bitfield) { for (int i = 0; i < 4; i++) { int bit_selector = (1 << i); if ((*button_bitfield) & bit_selector) { - *switch_ = (SwitchKey) i; + if (switch_ != nullptr) { + *switch_ = (SwitchKey) i; + } // clear bit *button_bitfield &= ~bit_selector; return true; @@ -132,7 +138,9 @@ bool get_flipped_switch(SwitchKey* switch_) { for (int i = 0; i < 4; i++) { int bit_selector = (1 << (i+4)); if (button_pressed & bit_selector || button_released & bit_selector) { - *switch_ = (SwitchKey) i; + if (switch_ != nullptr) { + *switch_ = (SwitchKey) i; + } // clear bit button_pressed &= ~bit_selector; button_released &= ~bit_selector; diff --git a/main/drivers/game_timer.cpp b/main/drivers/game_timer.cpp index 027afb0..2d55cbb 100644 --- a/main/drivers/game_timer.cpp +++ b/main/drivers/game_timer.cpp @@ -58,11 +58,23 @@ static void game_timer_task(void *arg) vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS(frequency)); if (is_game_playing) { game_time_left = sat_sub(game_time_left, frequency); - set_game_sseg_num(game_time_left / 100, 1); + if (game_time_left > 60'000) { + int disp_time = (game_time_left / 60'000) * 100; + disp_time = disp_time + ((game_time_left % 60'000) / 1'000); + set_game_sseg_num(disp_time, 2); + } else { + set_game_sseg_num(game_time_left / 100, 1); + } } if (is_module_playing) { module_time_left = sat_sub(module_time_left, frequency); - set_module_sseg_num(module_time_left / 100, 1); + if (module_time_left > 60'000) { + int disp_time = (module_time_left / 60'000) * 100; + disp_time = disp_time + ((module_time_left % 60'000) / 1'000); + set_module_sseg_num(disp_time, 2); + } else { + set_module_sseg_num(module_time_left / 100, 1); + } } } diff --git a/main/helper.cpp b/main/helper.cpp index 797266e..4160911 100644 --- a/main/helper.cpp +++ b/main/helper.cpp @@ -12,7 +12,7 @@ void clean_bomb(void) { // clear module timer stop_module_timer(); set_module_time(0); - uint8_t clear[] = {0}; + uint8_t clear[4] = {0}; set_module_sseg_raw(clear); // clear char lcd @@ -31,3 +31,74 @@ void poster_child_task(void* arg) { vTaskDelete(NULL); } + + +static const int STRING_MAX_LEN = 8; +void do_star_codes(StarCodeHandler* star_codes, int star_codes_len) { + KeypadKey key; + + int current_idx = 0; + char current[STRING_MAX_LEN+1] = {0}; + + while (1) { + while (get_pressed_keypad(&key)) { + if (key == KeypadKey::star) { + current[0] = '*'; + for (int i = 1; i < STRING_MAX_LEN; i++) { + current[i] = 0; + } + current_idx = 1; + } else if (key == KeypadKey::pound) { + // submit + if (current[0] == '\0') { + continue; + } + + bool hit = false; + for (int i = 0; i < star_codes_len; i++) { + StarCodeHandler sch = star_codes[i]; + if (strcmp(current, sch.code) == 0) { + hit = true; + lcd_set_cursor(&lcd, 1, 2); + lcd_print(&lcd, sch.display_text); + vTaskDelay(pdMS_TO_TICKS(2000)); + if (sch.callback != nullptr) { + (sch.callback)(); + } + if (sch.should_exit) { + return; + } + break; + } + } + + if (!hit) { + lcd_set_cursor(&lcd, 1, 2); + lcd_print(&lcd, "Invalid Star Code"); + vTaskDelay(pdMS_TO_TICKS(2000)); + } + + // clear + for (int i = 0; i < STRING_MAX_LEN; i++) { + current[i] = 0; + } + current_idx = 0; + } else { + // out of room. skip + if (current_idx >= STRING_MAX_LEN) break; + // no code started. + if (current[0] != '*') continue; + + char c = char_of_keypad_key(key); + current[current_idx++] = c; + } + // ESP_LOGI(STEP0_TAG, "Pressed: %c", c); + + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, current); + } + + vTaskDelay(pdMS_TO_TICKS(10)); + } +} diff --git a/main/helper.h b/main/helper.h index 7dd8a7c..916e560 100644 --- a/main/helper.h +++ b/main/helper.h @@ -9,8 +9,16 @@ #include "drivers/leds.h" #include "drivers/speaker.h" +struct StarCodeHandler { + char* code; + char* display_text; + bool should_exit; + void (*callback)(void); +}; + /// Clears most persistant bomb state void clean_bomb(void); void poster_child_task(void* arg); +void do_star_codes(StarCodeHandler* star_codes, int star_codes_len); #endif /* HELPER_H */ diff --git a/main/main.cpp b/main/main.cpp index 74eb490..cdbe28e 100755 --- a/main/main.cpp +++ b/main/main.cpp @@ -40,10 +40,9 @@ extern "C" void app_main(void) { init_bottom_half(); init_char_lcd(); - // create_demo_ui(); clean_bomb(); step0(); - set_game_time(1200000); + set_game_time(30*60*1000 + 1000); start_game_timer(); clean_bomb(); step1(); @@ -62,13 +61,5 @@ extern "C" void app_main(void) { stop_game_timer(); ESP_LOGI(TAG, "Bomb has been diffused. Counter-Terrorists win."); ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/diffused.pcm")); - - // play_example(); - - - // deinit_sd(); - - // set_game_timer(1234, 1); - // set_module_timer(5678, 2); } diff --git a/main/steps/step0.cpp b/main/steps/step0.cpp index 55e43fd..4e3fcf8 100644 --- a/main/steps/step0.cpp +++ b/main/steps/step0.cpp @@ -4,62 +4,20 @@ static const char* TAG = "step0"; /// Wait for "*9819" void step0(void) { - KeypadKey key; - - int current_idx = 0; - char current[STRING_MAX_LEN+1] = {0}; - - while (1) { - while (get_pressed_keypad(&key)) { - if (key == KeypadKey::star) { - current[0] = '*'; - for (int i = 1; i < STRING_MAX_LEN; i++) { - current[i] = 0; - } - current_idx = 1; - } else if (key == KeypadKey::pound) { - // submit - if (current[0] == '\0') { - // do nothing - } else if (strcmp(current, "*9819") == 0) { - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, "Diffusal Initated"); - vTaskDelay(pdMS_TO_TICKS(2000)); - lcd_clear(&lcd); - return; - } else if (strcmp(current, "*59861") == 0) { - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, "Set Up Wires"); - vTaskDelay(pdMS_TO_TICKS(2000)); - setup_wires(); - } else { - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, "Invalid Star Code"); - strike("Invalid Star Code"); - vTaskDelay(pdMS_TO_TICKS(2000)); - } - - // clear - for (int i = 0; i < STRING_MAX_LEN; i++) { - current[i] = 0; - } - current_idx = 0; - } else { - // out of room. skip - if (current_idx >= STRING_MAX_LEN) break; - // no code started. - if (current[0] != '*') continue; - - char c = char_of_keypad_key(key); - current[current_idx++] = c; - } - // ESP_LOGI(STEP0_TAG, "Pressed: %c", c); - - lcd_clear(&lcd); - lcd_set_cursor(&lcd, 1, 1); - lcd_print(&lcd, current); - } - - vTaskDelay(pdMS_TO_TICKS(10)); - } + StarCodeHandler star_codes[] = { + { + .code = "*9819", + .display_text = "Diffusal Initiated", + .should_exit = true, + .callback = nullptr, + }, + { + .code = "*59861", + .display_text = "Set Up Wires", + .should_exit = false, + .callback = setup_wires, + }, + }; + int len = sizeof(star_codes)/sizeof(StarCodeHandler); + do_star_codes(star_codes, len); } diff --git a/main/steps/step0.h b/main/steps/step0.h index 0a4afe5..892964a 100644 --- a/main/steps/step0.h +++ b/main/steps/step0.h @@ -5,6 +5,7 @@ #include "../drivers/char_lcd.h" #include "../drivers/wires.h" #include "setup_wires.h" +#include "../helper.h" #define STRING_MAX_LEN 8 diff --git a/main/steps/step1.cpp b/main/steps/step1.cpp index 831d705..aed1310 100644 --- a/main/steps/step1.cpp +++ b/main/steps/step1.cpp @@ -176,9 +176,9 @@ static int generate_part_c(void) { return text_color + 4; } -static void part_a(void) { +static bool part_a(void) { stop_module_timer(); - set_module_time(30); + set_module_time(30*1000); lcd_clear(&lcd); lcd_set_cursor(&lcd, 1, 1); @@ -206,6 +206,10 @@ static void part_a(void) { while (get_flipped_switch(&switch_)) { strike("Incorrect color action"); } + if (get_module_time() <= 0) { + strike("Out of time"); + return false; + } vTaskDelay(pdMS_TO_TICKS(10)); } @@ -217,11 +221,12 @@ static void part_a(void) { } vTaskDelay(pdMS_TO_TICKS(80)); play_raw(MOUNT_POINT "/correct.pcm"); + return true; } -static void part_b(void) { +static bool part_b(void) { stop_module_timer(); - set_module_time(25); + set_module_time(25*1000); lcd_clear(&lcd); lcd_set_cursor(&lcd, 1, 1); @@ -249,6 +254,10 @@ static void part_b(void) { while (get_flipped_switch(&switch_)) { strike("Incorrect color action"); } + if (get_module_time() <= 0) { + strike("Out of time"); + return false; + } vTaskDelay(pdMS_TO_TICKS(10)); } @@ -259,11 +268,12 @@ static void part_b(void) { } vTaskDelay(pdMS_TO_TICKS(80)); play_raw(MOUNT_POINT "/correct.pcm"); + return true; } -static void part_c(void) { +static bool part_c(void) { stop_module_timer(); - set_module_time(20); + set_module_time(20*1000); lcd_clear(&lcd); lcd_set_cursor(&lcd, 1, 1); @@ -292,12 +302,16 @@ static void part_c(void) { start_module_timer(); if (switch_leds[(int)(switch_)] + 4 == correct) { times++; - if (times >= 10) break; + if (times >= 15) break; correct = generate_part_c(); } else { strike("Incorrect color action"); } } + if (get_module_time() <= 0) { + strike("Out of time"); + return false; + } vTaskDelay(pdMS_TO_TICKS(10)); } @@ -308,16 +322,17 @@ static void part_c(void) { } vTaskDelay(pdMS_TO_TICKS(80)); play_raw(MOUNT_POINT "/correct.pcm"); + return true; } void step1(void) { - SwitchKey switch_; - while (get_flipped_switch(&switch_)); + while (get_flipped_switch(nullptr)); init_step(); - part_a(); - part_b(); - part_c(); + while (!part_a()); + while (!part_b()); + while (!part_c()); + clean_up_step(); // TODO: flash lights } diff --git a/main/steps/step2.cpp b/main/steps/step2.cpp index 826d574..efe7aab 100644 --- a/main/steps/step2.cpp +++ b/main/steps/step2.cpp @@ -16,6 +16,8 @@ static int board[height][width] = {0}; static lv_obj_t* visual_board[height][width] = {0}; static lv_obj_t* line_clear_img; +static lv_style_t game_over_style; +static lv_obj_t* game_over_label; static const void* LINE_CLEAR_SRC = (void*)"A:/sdcard/clear.bin"; static const void* BACKGROUND_SRC = (void*)"A:/sdcard/bg.bin"; @@ -140,6 +142,17 @@ static void init_screen(void) { lv_img_set_src(line_clear_img, LINE_CLEAR_SRC); lv_obj_align(line_clear_img, LV_ALIGN_BOTTOM_LEFT, 159, -(height*16)); + lv_style_init(&game_over_style); + lv_style_set_text_color(&game_over_style, lv_color_white()); + lv_style_set_bg_color(&game_over_style, lv_color_black()); + lv_style_set_bg_opa(&game_over_style, LV_OPA_100); + lv_style_set_text_align(&game_over_style, LV_TEXT_ALIGN_CENTER); + + game_over_label = lv_label_create(lv_scr_act()); + lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_align(game_over_label, LV_ALIGN_CENTER, 0, 0); + lv_obj_add_style(game_over_label, &game_over_style, LV_STATE_DEFAULT); + // for (int h = 0; h < height; h++) { // for (int w = 0; w < width; w++) { // visual_board[h][w] = lv_img_create(lv_scr_act()); @@ -172,7 +185,6 @@ bool play_game(int time, int required_score) { score = 0; update_score(); set_module_time(time); - vTaskDelay(1000); start_module_timer(); clear_board(); @@ -180,6 +192,7 @@ bool play_game(int time, int required_score) { generate_block(); ButtonKey button; + while (get_pressed_button(&button)); // SwitchKey switch_; while(game) { @@ -231,12 +244,58 @@ bool play_game(int time, int required_score) { return false; } +static void complete(void) { + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_label_set_text(game_over_label, "Winner!\nPress any button to continue"); + lv_obj_clear_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } + vTaskDelay(pdMS_TO_TICKS(500)); + while (get_pressed_button(nullptr)); + while (1) { + if (get_pressed_button(nullptr)) break; + vTaskDelay(pdMS_TO_TICKS(10)); + } + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } +} + +static void fail(void) { + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_label_set_text(game_over_label, "Game Over\nPress any button to continue"); + lv_obj_clear_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } + vTaskDelay(pdMS_TO_TICKS(500)); + while (get_pressed_button(nullptr)); + while (1) { + if (get_pressed_button(nullptr)) break; + vTaskDelay(pdMS_TO_TICKS(10)); + } + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } +} + void step2(void) { + StarCodeHandler star_code = { + .code = "*3850", + .display_text = "Starting...", + .should_exit = true, + .callback = nullptr, + }; + do_star_codes(&star_code, 1); init_screen(); - while (!play_game(60000, 4)) vTaskDelay(2000); - while (!play_game(60000, 8)) vTaskDelay(2000); - while (!play_game(120000, 16)) vTaskDelay(2000); + while (!play_game(4*60*1000, 2)) fail(); + complete(); + while (!play_game(4*60*1000, 4)) fail(); + complete(); + while (!play_game(8*60*1000, 8)) fail(); + complete(); deinit_screen(); } diff --git a/main/steps/step2.h b/main/steps/step2.h index be8efae..2d925e6 100644 --- a/main/steps/step2.h +++ b/main/steps/step2.h @@ -8,6 +8,7 @@ #include "../drivers/game_timer.h" #include "../drivers/wires.h" #include "../drivers/char_lcd.h" +#include "../helper.h" // TODO: // - [ ] set up real game loop