#include "step1.h" __attribute__((unused)) static const char *TAG = "step1"; static const char* COLOR_NAMES[] = { "green", "red", "yellow", "blue" }; static const char* NUM_NAMES[] = { "one", "two", "three", "four" }; static uint8_t NEOPIXEL_COLORS[4][3] = { {0, 20, 0}, {20, 0, 0}, {20, 20, 0}, {0, 0, 20}, }; static std::random_device my_rd; static std::mt19937 my_gen(my_rd()); static std::uniform_int_distribution<> zero_to_one(0, 1); static std::uniform_int_distribution<> zero_to_two(0, 2); static std::uniform_int_distribution<> zero_to_three(0, 3); static lv_obj_t *scr; static lv_obj_t *text = NULL; static lv_style_t style_screen; static lv_style_t green_text; static lv_style_t red_text; static lv_style_t yellow_text; static lv_style_t blue_text; static lv_style_t* last_style = nullptr; static int switch_leds[] = {0, 0, 0, 0}; static lv_style_t* color_styles[] = { &green_text, &red_text, &yellow_text, &blue_text }; /// 0 => part a /// 1 => part b /// 2 => part c static int part = 0; static void init_step(void) { if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { 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 = { .full = 0x0560 }; lv_color_t red = { .full = 0xf800 }; lv_color_t yellow = { .full = 0xfce0 }; lv_color_t blue = { .full = 0x045f }; 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(&blue_text); lv_style_set_text_color(&blue_text, blue); text = lv_label_create(scr); xSemaphoreGive(xGuiSemaphore); } } static void clean_up_step(void) { if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { lv_obj_clean(scr); xSemaphoreGive(xGuiSemaphore); } } static 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]; 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); } static void set_text_and_color(const char* text_str, int color) { if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { lv_label_set_text(text, text_str); lv_obj_center(text); if (last_style != nullptr) { lv_obj_remove_style(text, last_style, LV_STATE_DEFAULT); } lv_obj_add_style(text, color_styles[color], LV_STATE_DEFAULT); last_style = color_styles[color]; xSemaphoreGive(xGuiSemaphore); } } static int generate_part_a(void) { int text_color = zero_to_three(my_gen); int text_idx = zero_to_three(my_gen); const char* text_string = COLOR_NAMES[text_idx]; set_text_and_color(text_string, text_color); generate_switch_leds(); // the correct answer is the text color return text_color; } static 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); const char* text_string = NUM_NAMES[text_number]; set_text_and_color(text_string, text_color); generate_switch_leds(); // the correct answer is the number return text_number; } static 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); const char* text_string = "switch"; set_text_and_color(text_string, text_color); generate_switch_leds(); // the correct answer is the switch return text_color + 4; } static int generate_part(void) { switch (part) { case 0: return generate_part_a(); case 1: return generate_part_b(); case 2: return generate_part_c(); } ESP_LOGW(TAG, "`part` (%d) was not to in range 0..=2!", part); return -1; } static void update_lcd_count(int times) { char buf[16] = {0}; sprintf(buf, "%d/15", times); lcd_print(14, 1, buf); } static bool play_part(uint32_t time) { stop_module_timer(); set_module_time(time); lcd_clear(); lcd_set_cursor_pos(1, 1); switch (part) { case 0: lcd_print("COLOR"); led_strip_set_pixel(leds, Led::char_lcd, 20, 0, 20); break; case 1: lcd_print("NUMBER"); led_strip_set_pixel(leds, Led::char_lcd, 0, 0, 30); break; case 2: lcd_print("SWITCH"); led_strip_set_pixel(leds, Led::char_lcd, 20, 20, 0); break; } led_strip_refresh(leds); int times = 0; int correct = generate_part(); update_lcd_count(times); ButtonKey button; SwitchKey switch_; while (times < 15) { while (get_button_pressed(&button)) { start_module_timer(); if ((int)(button) == correct) { times++; if (times >= 15) break; correct = generate_part(); update_lcd_count(times); } else { strike("Incorrect action"); } } while (get_switch_flipped(&switch_)) { start_module_timer(); if (switch_leds[(int)(switch_)] + 4 == correct) { times++; if (times >= 15) break; correct = generate_part(); update_lcd_count(times); } else { strike("Incorrect action"); } } if (get_module_time() <= 0) { strike("Out of time"); return false; } vTaskDelay(pdMS_TO_TICKS(10)); } if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { lv_label_set_text(text, ""); xSemaphoreGive(xGuiSemaphore); } if (part < 2) { play_clip_wav(MOUNT_POINT "/partdone.wav", true, false, 0, 0); vTaskDelay(pdMS_TO_TICKS(2000)); } else { play_clip_wav(MOUNT_POINT "/stepdone.wav", true, false, 1, 0); } return true; } void step1(void) { while (get_switch_flipped(nullptr)); init_step(); while (!play_part(40*1000)); part = 1; while (!play_part(35*1000)); part = 2; while (!play_part(30*1000)); clean_up_step(); // TODO: flash lights }