287 lines
7.1 KiB
C++
287 lines
7.1 KiB
C++
#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 uint32_t NEOPIXEL_COLORS[4] = {
|
|
LEDColor::LED_COLOR_GREEN,
|
|
LEDColor::LED_COLOR_RED,
|
|
LEDColor::LED_COLOR_YELLOW,
|
|
LEDColor::LED_COLOR_BLUE,
|
|
};
|
|
|
|
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++) {
|
|
led_set(IndicatorLED::LED_S1 - i, NEOPIXEL_COLORS[switch_leds[i]]);
|
|
}
|
|
leds_flush();
|
|
}
|
|
|
|
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_set(IndicatorLED::LED_LCD, LEDColor::LED_COLOR_PINK);
|
|
break;
|
|
case 1:
|
|
lcd_print("NUMBER");
|
|
led_set(IndicatorLED::LED_LCD, LEDColor::LED_COLOR_BLUE);
|
|
break;
|
|
case 2:
|
|
lcd_print("SWITCH");
|
|
led_set(IndicatorLED::LED_LCD, LEDColor::LED_COLOR_YELLOW);
|
|
break;
|
|
}
|
|
leds_flush();
|
|
|
|
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
|
|
}
|