blk_box_tc/main/steps/step1.cpp

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
}